Colour Spaces: RGB and HSV

Why selecting a colour is hard in RGB and easy in HSV, and what each channel actually holds.

Overview

RGB describes the hardware

A screen makes colour by mixing three lights. RGB records how much of each: three numbers from 0 to 255, one per main. It's the natural format for a display, a camera sensor and a file, and it's what almost each image arrives in.

It's a poor format for *thinking* about colour, and the three numbers aren't free in any way a person cares about.

Take a mid red, (200, 60, 60). Make it darker and you get (120, 36, 36) — all three numbers changed. Make it paler and you get (220, 140, 140) — all three again. The colour didn't change in either case. The brightness did, and then the purity did, and both ops moved each channel. There's no single number in RGB that means "how red" or "how bright".

Look at the R, G and B channels in the visualisation above. The red disc is bright in R, but so is the yellow one. Yellow is red plus green. None of the three channels isolates a colour, because none of them matches to any of it you'd name.

Colour Spaces: RGB and HSV

This module needs JavaScript: the images are computed in the page rather than downloaded.

Worth knowing

RGB stores how much of each primary light to emit. It matches hardware, not perception.
In RGB, making a colour darker changes all three numbers, so brightness and colour are entangled.
HSV separates them: hue is which colour, saturation how pure, value how bright.
Selecting 'anything red' is one range in hue and three coupled ranges in RGB. That is the whole reason HSV exists.

Colour Spaces: RGB and HSV

The same pixel, given two ways. Why one of them makes colour pick trivial.

HSV separates the three questions

HSV rewrites the same pixel as three numbers that answer three separate questions.

Hue is which colour, as an angle around a wheel from 0 to 360 degrees. Red is near 0, green near 120, blue near 240. It's circular. 359 and 1 are neighbours.

Saturation is how pure the colour is, from 0 to 1. At 0 the pixel is grey even so of hue. At 1 it's the most vivid version of that hue available.

Value is how bright, from 0 to 1. At 0 the pixel is black even so of any of it else.

The conversion is math on the RGB triple. Value is the max channel, saturation is the range between max and min cut by the max, and hue is found by which channel is largest and by how the other two compare. No info is added or lost. It's the same pixel in different coords.

The thing this makes easy

Switch the visualisation to the H channel. Each disc turns a flat, uniform region, and each is a *different* flat region. That is the payoff: within one object, hue barely varies, even where brightness does. A shadow falling across a red ball changes V sharply and leaves H almost alone.

So "find the red object" turns one check:

mask = (hue < 15) or (hue > 345)

Try to write that in RGB. You need red high, green low, blue low — but how high, and scaled to what? A dark red has a low R. A pale pink has a high G and B. The ranges are coupled, they depend on lighting, and each new lighting rule needs them retuned. This is why colour-based tracking, chroma keying and skin spotting are all done in HSV or a close scaled, and why the technique is old enough to predate the tools you'd use for it now.

Saturation earns its place too. Hue is meaningless for a near-grey pixel — the math still makes an angle. But It's found by tiny differences and jumps around unstably. A handy mask so often needs saturation above some floor as well. This Reads as "a definite colour, not just a shade".

TaskSpaceWhy
Storing or displayingRGBmatches sensors and screens
Selecting a colourHSVone range in hue
Adjusting brightness onlyHSVchange V, leave H and S
Equalising contrast in colourHSV or LABone brightness channel to equalise
Measuring perceptual differenceLABdistances match what eyes report

Where HSV stops being enough

HSV is a convenience, not a visual model. Its value channel is simply the max of R, G and B. This Doesn't match how bright a colour looks: pure yellow and pure blue both have value 1 and are nowhere near equally bright to a human eye.

When the question is truly visual. How different do these two colours *look*, which of these is closer. The answer is a space like LAB, built from readings of human vision so that equal distances match to roughly equal seen differences. Colour-difference metrics and palette-matching work there.

The same pixel, converted

RGB stores three lights. HSV stores three answers to separate questions, and converting one pixel shows why the second is easier to reason about. Take a mid-red (200, 60, 60). Value is the largest channel over 255, saturation is the channel range over the max, hue is set by which channel leads:

componentcomputationvalue
Value200 / 2550.78
Saturation(200 − 60) / 2000.70
Huered leads, so 60·((g−b)/range)0°

No info is added or lost. It's the same pixel in different coords — but now "how red" is a single number. Darken the colour and only V moves. Wash it out and only S moves. The hue stays near 0 through both, which is just what makes "find the red object" one check, hue < 15 or hue > 345, where the RGB version needs coupled, lighting-dependent ranges on all three channels. Two traps come straight out of the math: hue *wraps*. So Red straddles 0 and needs two range tests, not one. And hue is meaningless when saturation is near zero (a grey pixel's hue is decided by rounding noise). So A real colour mask also needs S above a floor. And OpenCV packs hue into 0-179 to fit a byte, so half of each published threshold is wrong for it.

Where it goes wrong with Colour Spaces

Losing that hue wraps. Red straddles 0. A naive range test 10 < hue < 350 selects all except red. Two tests are needed, or a rotation of the hue axis first.

Skipping saturation. Grey pixels have an any hue. A hue-only mask picks up noise from each washed-out region in the frame.

given a fixed hue range transfers. Hue is stable against brightness, not against the colour of the light source. Photo the same red object under tungsten and daylight and the hue moves. White balance first, or calibrate per scene.

Reading OpenCV's hue as degrees. OpenCV stores hue in 0-179 so it fits in a byte, not 0-359. Half of each published threshold is wrong for this reason.

Questions people ask about Colour Spaces

Why use HSV instead of RGB for colour detection? In RGB, a single colour changes all three channels as lighting changes. In HSV the hue stays roughly constant, so one hue range picks out an object under varying light.

What do the H, S and V channels mean? Hue is the colour angle, saturation is how far it is from grey, and value is how bright it is.

Why is red hard to threshold in HSV? Hue is circular, so red sits at both ends of the scale, near 0 and near 180 in OpenCV. You need two ranges and combine their masks.

Why does OpenCV use hue values only up to 179? Hue is stored in 8 bits, and 360 degrees does not fit in 0 to 255. OpenCV halves it, so the full circle runs 0 to 179.

Why does my image look blue-tinted after loading it with OpenCV? OpenCV loads channels in BGR order while most plotting libraries expect RGB. Convert with cvtColor and COLOR_BGR2RGB before displaying.

When is Lab better than HSV? When you need distances between colours to match human perception. Lab is built so that equal numeric steps look like equal colour differences.

The same colour, described two ways

RGB says how much of each light. HSV says which colour, how vivid, how bright. Converting between them by hand shows why one is right for displays and the other for finding a coloured object.

example_01.pyNumPy
Output

Hue is an angle on a colour wheel, and lighting changes barely move it, which is why HSV makes colour segmentation practical.

example_02.pyNumPy
Output

A red detector built on hue handles lighting changes that break the same detector built on RGB thresholds.

example_03.pyNumPy
Output

Check yourself

0 of 3

Answer without scrolling back up.

  1. Why is selecting 'anything red' easier in HSV than in RGB?

  2. Why should a hue mask usually also require a minimum saturation?

  3. What breaks a naive `10 < hue < 350` test for red?

Cheat sheet

Colour Spaces: RGB and HSV

Convert the same pixel between RGB and HSV, then see how a colour range that needs six RGB inequalities becomes a single HSV threshold.

COMPUTER VISION · vizlearn.in/computer_vision/colour_spaces_rgb_hsv.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.