Colour and Channels
Colour is not one number per pixel, it is three, stacked on top of each other and constantly disagreeing. Split a photo into its red, green, and blue channels and find out which one was quietly doing almost all of the work.
Read first: Images as Numbers
You think of a coloured pixel as one thing — a dot of sky-blue, a dot of leaf-green. It is not one thing. It is three separate numbers, recorded independently, that happen to sit on top of each other and get displayed as a single dot. Pull them apart and one of the three turns out to be doing almost all of the work.
One pixel, three numbers
The previous lesson said a grayscale pixel is one integer from 0 to 255. A colour pixel is the same idea, tripled: one integer for how much red light it holds, one for green, one for blue, each independently between 0 and 255.
A clear midday sky is roughly R = 135, G = 206, B = 235 — heavy on blue, as you would expect, but also more green than red, which is why a sky rendered with only its blue channel looks nothing like a sky. Zero out any one of those three numbers and the colour changes completely; there is no single “important” channel until you ask a specific question about a specific image.
Why grayscale is a choice, not a loss
It is tempting to think of converting a colour photo to grayscale as throwing information away, the way deleting two-thirds of a file would. It is closer to a deliberate calculation than a deletion: a common formula is 0.299R + 0.587G + 0.114B, not a plain average of the three.
Green gets about five times the weight of blue because human brightness perception peaks in the green part of the spectrum: the cones that respond to red and to green both respond strongly there, while blue-sensitive cones are comparatively few and contribute little to how bright something looks. A grayscale conversion that used equal weights would produce a technically valid image that looked wrong to every person who looked at it, because it would not match how brightness actually registers for a human observer.
0.299 × 135 + 0.587 × 206 + 0.114 × 235 ≈ 40.4 + 120.9 + 26.8 ≈ 188. A plain average gives (135 + 206 + 235) / 3 = 192. The two are close here, but notice where the weighted grey came from: almost two-thirds of it is the green channel, even though blue is the biggest of the three numbers.
Channels that are not colour at all
Nothing about the word “channel” requires it to carry colour. A channel is just another grid of numbers, the same shape as the image, stacked alongside red, green and blue.
Alpha
A fourth channel recording transparency — 0 for fully see-through, 255 for fully opaque. It changes nothing about colour and everything about what shows through.
Depth
Sensors like LiDAR or a structured-light camera record distance from the lens per pixel, not brightness. A depth channel can sit right alongside an RGB image of the same scene.
Infrared
Satellite and night-vision imagery often carry a channel for light outside what your eyes can see at all, used precisely because it reveals things visible colour does not.
The order of channels is not universal
Even once you have settled on red, green and blue, the order they are stored in is a convention, not a law — and it is not the same convention everywhere.
OpenCV loads images as BGR, not RGB, by default. Read a photo with cv2.imread and the first channel in the array is blue, not red. Hand that array to a library that assumes RGB — Matplotlib, most plotting and machine-learning code — without converting it, and nothing crashes. Nothing throws an error at all. The image simply displays with red and blue silently swapped: skin turns a washed-out blue, a blue sky turns orange.
A two-pixel image, a sky and a leaf, pulled apart into channels, turned grey, and then read in the wrong channel order.
import numpy as np # A 1-by-2 colour image: a sky pixel and a leaf pixel. Shape is (rows, columns, channels).image = np.array([[[135, 206, 235], [60, 140, 70]]], dtype=np.uint8)print("shape:", image.shape) red, green, blue = image[..., 0], image[..., 1], image[..., 2]print("red channel: ", red)print("green channel:", green)print("blue channel: ", blue) weighted = 0.299 * red + 0.587 * green + 0.114 * blueaverage = image.mean(axis=2)print("weighted grey:", weighted.round())print("plain average:", average.round()) # The silent bug: a library that stores BGR hands you the channels reversed.swapped = image[..., ::-1]print("read as RGB by mistake:", swapped.tolist()) import matplotlib.pyplot as pltfig, axes = plt.subplots(1, 2, figsize=(4, 2))for ax, picture, title in zip(axes, [image, swapped], ["RGB", "BGR read as RGB"]): ax.imshow(picture) ax.set_title(title) ax.axis("off")plt.show()The weighted grey for the sky is 188, as in the exercise above. Reversed, the sky becomes 235, 206, 135, a pale orange, while the leaf barely changes, because its red and blue were close to begin with.
Key takeaways
- A colour pixel is not one value, it is three independent numbers for red, green and blue stacked on the same spot.
- Converting to grayscale is a weighted calculation, not a plain average — green gets about five times the weight of blue because human brightness perception is most sensitive to green light.
- A channel does not have to carry colour: alpha carries transparency, depth carries distance, infrared carries light outside human vision.
- Channel order is a convention rather than a universal rule, and OpenCV's default of BGR instead of RGB is the concrete example that trips people up.
- Mixing up channel order does not error — it silently swaps red and blue in the displayed image, which is what makes the bug easy to miss.
Before you move on
Quick check
Answer these to unlock the next chapter: 3 of 4 to pass. You can retake it anytime.
Make a free account to read on
Every chapter is free — an account lets your course progress follow you from your laptop to your phone. No payment, no trial.