RGB Image Logic
Draw with colors to understand how images are composed of Red, Green, and Blue channels.
Draw with colors to understand how images are composed of Red, Green, and Blue channels.
A deep dive into how digital color is represented and manipulated. Read this, experiment with the tool, and solidify your understanding.
RGB Image Processing is a fundamental concept in computer vision. It's the basis for how computers "see" and manipulate color images. Every colored pixel on your screen is a combination of three values: Red, Green, and Blue.
Think of a color image not as a single flat picture, but as three separate grayscale images stacked on top of each other. Each of these "layers" is a channel, representing the intensity of Red, Green, or Blue light for every pixel.
When combined, their values mix to create the full spectrum of colors we see. A value of (0, 0, 0) is black, (255, 255, 255) is white, and (255, 0, 0) is pure red.
A colour image stores three values per pixel — red, green and blue — each usually 0 to 255. Mixing them additively produces every colour the display can show.
| R | G | B | Colour |
|---|---|---|---|
| 255 | 0 | 0 | Red |
| 0 | 255 | 0 | Green |
| 255 | 255 | 0 | Yellow |
| 255 | 255 | 255 | White |
| 0 | 0 | 0 | Black |
| 128 | 128 | 128 | Mid grey |
Equal values give a shade of grey; unequal values give a hue. That simple fact is the basis of several quick image checks.
A 1920×1080 photograph is therefore 1920 × 1080 × 3 = 6.2 million values, about 6MB uncompressed. In code it is an array of shape (height, width, 3) — and note the order: height first, then width, which is the opposite of how image sizes are usually quoted.
Two conventions cause endless confusion. OpenCV stores images as BGR, while almost everything else uses RGB, so an image loaded with cv2.imread and displayed with matplotlib comes out with red and blue swapped. And PyTorch expects channels-first tensors, (3, H, W), while NumPy and PIL use channels-last, (H, W, 3).
RGB is how displays work, not how colour is best reasoned about. Separating colour from brightness is often far more useful.
HSV — hue (which colour, 0–360°), saturation (how vivid), value (how bright). Selecting "all the red pixels" in RGB means writing rules across three interacting channels; in HSV it is a range on one. This is why HSV is the standard choice for colour-based thresholding, and why colour-jitter augmentation is implemented in it.
LAB — lightness plus two colour axes, designed so that equal numeric distances correspond to roughly equal perceived differences. Used for colour matching, and its L channel is what CLAHE is usually applied to for contrast enhancement without shifting hues.
YCbCr — brightness plus two chroma channels. JPEG and video compression store chroma at lower resolution than luma, because human vision is far more sensitive to brightness detail than to colour detail. That asymmetry is a large part of why images compress as well as they do.
import cv2
img = cv2.imread("photo.jpg") # BGR
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, (0, 120, 70), (10, 255, 255)) # reds
Three preprocessing steps, in this order.
Convert to the model's expected channel order. RGB for torchvision, and channels-first for the tensor.
Scale to 0–1 by dividing by 255.
Standardise per channel using the pretraining dataset's statistics — for ImageNet, mean [0.485, 0.456, 0.406] and standard deviation [0.229, 0.224, 0.225]. These are per channel because the channels genuinely have different distributions; natural images have more energy in red and green than in blue.
Skipping the standardisation is a silent error: the model trains and works, several points below where it should be, with nothing to indicate why.
Use the tool above to build a strong mental model. Follow these steps:
#FF0000). Draw a line.#FFFF00). Draw something.#00FF00) shape. Click "Invert Colors". The shape turns magenta.When a computer applies a filter, it iterates through every pixel and applies a mathematical rule. For a brightness adjustment, it looks like this:
function adjust_brightness(image, factor):
for each pixel (x, y) in image:
original_color = image.get_pixel(x, y) // e.g., (R:50, G:100, B:200)
new_R = original_color.R * factor
new_G = original_color.G * factor
new_B = original_color.B * factor
// Clamp values to stay within the 0-255 range
new_R = min(255, new_R)
new_G = min(255, new_G)
new_B = min(255, new_B)
image.set_pixel(x, y, (new_R, new_G, new_B))
return imageThis is exactly what happens when you use the "Brightness" slider and click "Apply".
An RGB image is three greyscale images stacked, and almost every colour operation is a question about how they relate. This works through channel arithmetic, the difference between per-channel and joint operations, and the two mistakes that cause most colour bugs.
(Height x Width x 3).Colour is essential when the task depends on it — ripeness, traffic signals, quality control on painted parts, medical staining, species identification. Discarding it there throws away the signal.
But colour is also the most common shortcut a model will latch onto. If every photograph of one class in your dataset was taken in a particular lighting, or every image of a defect happens to come from a camera with a different white balance, the model will learn the colour cast rather than the object. It will score well on your test split and fail immediately on new data.
Three defences:
The related failure is white balance: the same object photographed under daylight and under tungsten lighting has genuinely different RGB values. Histogram equalisation on the L channel of LAB, or a grey-world white-balance correction, normalises much of this away.
Why does my image look blue-tinted? BGR loaded as RGB. Convert with cv2.cvtColor.
Should I convert to greyscale? Only if colour genuinely carries no information for the task. Test both — it is cheap to check.
What is alpha? A fourth channel for transparency, giving RGBA. Most models expect three channels, so composite onto a background first.
Which colour space for thresholding? HSV, almost always — hue is one axis there and three interacting ones in RGB.
Do CNNs learn colour features? Yes — the first layer of trained networks contains colour-opponent filters alongside the edge detectors.
Why per-channel normalisation rather than one global mean? Because the three channels have genuinely different distributions in natural images, and treating them identically leaves a systematic offset.
Say the answer out loud before you reveal it — recalling it is what makes it stick, and rereading it is not.
What does this module say about “Start here”?
RGB Image Processing is a fundamental concept in computer vision. It's the basis for how computers "see" and manipulate color images. Every colored pixel on your screen is a combination of three values: Red, Green, and Blue.
What does this module say about “The Core Idea: Channels as Layers”?
Think of a color image not as a single flat picture, but as three separate grayscale images stacked on top of each other. Each of these "layers" is a channel , representing the intensity of Red, Green, or Blue light for every pixel.
What does this module say about “Three numbers per pixel”?
A colour image stores three values per pixel — red, green and blue — each usually 0 to 255. Mixing them additively produces every colour the display can show.
RGB Image Processing is a fundamental concept in computer vision. It's the basis for how computers "see" and manipulate color images. Every colored pixel on your screen is a combination of three values: Red, Green, and Blue.