Recently I've been playing with a bunch of color conversion functions. For example, converting from RGB to YUV or from HSV to CMYK. I've also been graphing the values. As it turns out, many programs compute the conversions differently. Part of the difference is due to differing algorithms. But I was surprised to find that many of the algorithms are backwards!
One thing I implemented was a color histogram system similar to the one generated by
VirtualDub's ColorTools plugin. This computes a
histogram of the color intensities per column (or per row). In this case, the horizontal axis is the image column and the vertical axis is the color intensity index. (The index ranges from 0 at the bottom to 255 at the top. The color channel's key is on the right.)
Original image
Intensity (grayscale) per column
Red
Green
Blue
Even though each color channel is different, they all have the same basic shape. While this isn't always the case (especially if the colors are only found in 1 or 2 color channels), most colors span all three color channels.
Intended Inversion
Some algorithms are expected to have an inverted shape. For example, CMYK is really the inverse of RGBI ("I" is the gray-scale intensity). So CMYK should look upside-down:
Cyan (C in CMYK) is the inverse of red (R in RGB)
However, other algorithms have intensities that are clearly inverted. For example, the algorithm for converting HSV to RGB has an inverted Saturation function. Although S is supposed to be in the range [0:1], it really should be [1:0] to match the same intensity curve. (Saturation shows the amount of color that isn't washed out by the white level.)
Saturation (S in HSV) has an inverted power level
Now, keep in mind, HSV is a color space that traces back to the
early 1800's. Back then, they didn't have computers for quickly generating power curves. So although the function is inverted, it has been inverted for over 200 years. Changing it now would just confuse people.
Unintended Confusion
Of course, other complex color systems don't have consistent power levels. For example, the chrominance power levels found in YUV (used by JPEG) may appear upright or inverted depending on the colors. The chrominance power curve is not directly influenced by the RGB values.
Luminance (grayscale)
Chrominance-Blue
Chrominance-Red
Why Be Consistent?
While the color curves are not consistent with other color spaces, that isn't a technical problem. The technical issues arise from all of the confusing aspects related to YUV. For example, with RGB, CMYK, and HSV, each letter stands for the color's name or attribute; R=red, Y=yellow, H=hue, etc. However, YUV is not an acronym or set of initials. "Y" (sometimes written Y') is just a letter chosen to represent the luminance. (I still wonder why the mathematicians did not use 'L' for luminance. It was
probably too obvious.) And the luminance is really just the gray-scale intensity (so they could have used "I" for intensity).
Making things more confusing, the letters from YUV conflict with other color spaces. "Y" is already used by CMYK for "Y=Yellow". Similarly, V is the
value from HSV -- the V from HSV is not the same as the V in YUV.
YUV or YVU?
Since the letters don't mean anything, people (including myself) frequently get them confused. For example, YUV is sometimes written YCC (luminance and two chrominance values; ignore that the two "C" values are different from each other and different from the Cyan color in CMYK).
YCC is really a shorthand notation for YCbCr (Luminance [Y], Chrominance-blue [Cb], and Chrominance-red [Cr]). Or is it YCrCb? According to Google, there are plenty of documents that associate YUV with YCrCb.
- Wikipedia. The Wikipedia definition is correct: YUV aligns with YCbCr. You can even see this if you plot the U and V values with a constant Y. (In this case, Y=0.5.) Notice how U goes from greenish to blue (it is the blue chrominance) and V goes from greenish to red (V is the red chrominance).

- yuv2ppm.c. The source code for yuv2ppm.c has the correct algorithm, but the wrong labels. The author says YCrCb but implemented YCbCr.
- FourCC. The FourCC web site has a great description of the various equations for implementing YUV. However, the page sometimes calls it YCbCr and sometimes says YCrCb.
- Kioskeo. Kioskeo.net says that YUV is YCrCb. They even say, "U is sometimes written as Cr and V is sometimes written as Cb, hence the notation YCrCb." While they have the correct equations, they got the definition backwards.
- ImpulseAdventure. This web site is a great reference for everything camera related. On their colorspace page, they correctly describe YCbCr but also mention that some people call it YCrCb.
For the record: YUV is analogous to YCbCr and not YCrCb. U is the chrominance-blue and V is the chrominance-red. They are not interchangeable.
Inequality
If you noticed, I keep saying YUV is
analogous to YCbCr instead of "YUV is YCbCr". Depending on the documentation you read, there is a little difference. Some papers describe two different algorithms, while others differentiate between analog and digital signals. So while most people use the terms interchangeably and nearly everyone seems to implement YUV with the same algorithms, YCbCr may be a wee bit different numerically.
Then again, not everyone implements the same algorithms. Most people use one of these:
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R -0.515G -0.100B
| Y = 0.257R + 0.504G + 0.098B + 16
U = -0.148R - 0.291G + 0.439B + 128
V = 0.439R - 0.368G - 0.071B + 128 |
Although the coefficients are similar, they are not identical.
Both sets of equations can be computationally expensive if R, G, and B are integers and you need to constantly convert between floats and ints. Microsoft uses a
faster algorithm that only uses integers but isn't numerically equivalent:
Y = ( ( 66R + 129G + 25B + 128 ) >> 8 ) + 16
U = ( ( -38R - 74G + 112B + 128 ) >> 8 ) + 128
V = ( ( 112R - 94G - 18B + 128 ) >> 8 ) + 128
Perhaps this is one reason why JPEGs rendered by Microsoft have slightly different coloring from Photoshop and other systems.
Here's a faster method for integers that is numerically equivalent to the first of the original equations:
Y = ( 299R + 587G + 114B)/1000
U = (-147R - 289G + 436B)/1000
V = ( 615R - 515G - 100B)/1000
Simply multiply out all fractions and then do one integer division at the end. (Add 128 to U and V if you want the range to be from 0 to 255.)
So while HSV may have an inverted power level for the saturation component, at least everyone is numerically equivalent. With YUV, you may see it called YCrCb but it is likely implemented as YCbCr using one of a handful of different (but similar) equations. And while the implementation differences probably won't be noticed by the human eye, these differences can lead to big problems with some automated systems and may also impact the ability to convert from RGB to YUV and back to RGB.