I've known for a long time that colour is a confusing subject. Study colour in any physics-related way and you come to realise that it's just an illusion and not the concrete absolute that we often take it to be. Recently, having written some pretty heavyweight image editing software, I've learned again just how confounding the whole subject can be. Let's take a brief look at why.
Back in the day, I would just take a pixel from a bitmap, do some straight linear mathematics upon it, then store it back into the bitmap. Lots of people still do this today, but this is a very, very naïve and destructive approach to image manipulation.
|
Gamma correction |
The image on the left, with gamma correction vs. the image on the right without. Notice the huge difference, and therefore the equally huge numerical errors when using linear math in the sRGB (gamma-corrected) colour space. |
Firstly, image files do not contain linear RGB colour components. Instead, for the most part, they store pixels that have been "corrected" to be displayed on a monitor that has a notional gamma ratio of the power 2.2. This gamma-correct colour space is called [sRGB]. Traditionally, old CRT monitors naturally exhibited this kind of power curve in their display tubes, so compensating images in this way makes them look more realistic when displayed on these kinds of monitors.
So, to correctly manipulate pixels at all you need to make them linear by applying an inverse gamma transform, do your operation, then "recorrect" them back again. Even this approach, though a step up, is very simplistic and still leaves room for significant colour processing errors. There is just a single reason for this, and once you understand it you'll realise that colour processing can in fact be a real nightmare.
The reason of course is to do with the nature of human vision. We see things because our eyes react to certain wavelengths in the electromagnetic spectrum and send signals back to the brain. We have four different ways of detecting light in this way, three of them based on the cones within your eye and the other based on a different mechanism utilising rods. Cones are used during normal daytime vision while rods come into play at night.
Rods concentrate on just those wavelengths of light centred around blue. This is the main reason why things appear to take on a monochromatic bluish tint at night. Cones on the other hand are sensitive to red, green and blue wavelengths and so provide a much more comprehensive picture of colour.
|
Linear RGB colour space |
You can plainly see that the RGB colour space is cubic in nature, with pure green being present in the corner that you cannot see. |
What makes the whole process of understanding colour so confounding is that these three different flavours of cones use different chemical reactions to detect light, utilising different proteins with all of the inaccuracy that implies. Proteins react to these wavelengths of light proportionally to the number of protons entering the cones, but not in the straightforward way that we would like.
Our measurement of colour is skewed and far from the perfect measuring machine that we might think our visual system is. In short, we do not see colour linearly (we see it much more logarithmically) and we see different wavelengths of light with different strengths. For instance, we see shades of green much more brightly than technically equivalently bright shades of red or blue. Red and blue, to us, just seem darker when in fact they are not.
With this in mind, how on Earth do we compensate for these anomalies in colour processing algorithms?
The answer; with some difficulty, but it is quite possible.
First of all, forget using the RGB colour space, or any kind of RGB colour space for that matter. Because our eyes are non-uniform with respect to shades of colour we cannot just manipulate RGB in a uniform way across each of the three colour components. This would simply result in apparent colour hue changes when performing a simple brightness change. Not a desirable characteristic.
So if not RGB, then what?
Firstly, we need to disregard any colour spaces that don't allow a separation between hue and saturation. This precludes the use of the YIQ, YUV, YDbDr, YPbPr, YCbCr and xvYCC colour spaces. They are, quite simply, just not up to the job here.
So how about some of those colour spaces that do separate hue and saturation? After doing some lengthy research in this area I can say the following. Forget using HSB, HSV, HSI, HSL and any other derivatives of this technique also. Though easy to separate hue, saturation and brightness, they do not measure brightness in anything like a realistic way. Without the basic ability to manipulate brightness accurately, they are in my opinion just about next to useless.
Okay, we're running out of road here, but what about some of the CIE colour spaces? Well, I took a look at CIEXYZ which has been around for a very long time, but this still isn't terribly suitable for modern colour processing work. Why? Because it isn't linear with respect to the eye. Linear operations on colours in this space result in non-linear perceptions in the human eye, and this is the whole point of this discussion. So it seems CIEXYZ is no good then, but does CIE offer something else?
|
CIELAB colour space |
Note how chroma and hue are completely separate from lightness and linearly coupled to brightness. |
Well, yes, and this is where we see some light at the end of the tunnel (if you'll excuse the pun). There are two colour spaces that I would say are fast enough and accurate enough for good colour processing, [CIELAB] and [CIECAM02].
CIECAM02 is basically a refinement of CIELAB. This in turn, is a refinement of the aforementioned CIEXYZ colour space. What makes CIELAB so much better than CIEXYZ is that it keeps the simplicity of theoretically linear axes but these in fact map nicely to the colour perceptions of the human eye. Colours stored in this space automatically take on the non-uniform brightess of the different colour hues and the logarithmic nature of brightness changes. CIELAB appears to the programmer as a nice linear colour space, but changes in this linear space also look linear to the human eye too. I think we've reached our goal. Or have we?
Well, not quite. Though a massive step up from RGB, CIELAB does have some problems; it's non-constancy in the blue end of the colour spectrum for instance. This is where CIECAM02 steps in. This colour space makes some incremental improvements on CIELAB and is the colour space of choice if you want absolute accuracy. The colour management system within the Windows operating system was completely overhauled from Vista onwards to utilise this colour space. It's just a shame that the Windows Shell itself doesn't make more use of it. CIECAM02 does come at a cost however, in that it is more processor intensive when converting colours between the RGB (or sRGB) and CIECAM02 colour spaces. So, if processing time is of some concern, then CIELAB will often perform adequately well without the additional overhead.
Settling on CIELAB for a moment then, how would you use it? Well, quite easily as it turns out. The vertical axis is known as L, or lightness. The horizontal axes are conjointly called ab and contain the hue and chroma of the colour. Manipulating lightness is just a question of changing the L coordinate. Changing brightness simply involves scaling all three coordinates simultaneously. Changing hue involves a rotation of the coordinates on the ab axes around the L axis. Finally, changing chroma just means scaling the coordinates on the ab axes without adjusting the L axis. It really is that simple.
In that light, CIELAB does seem to be the silver bullet for accurate colour processing doesn't it? I have to say, now that I've discovered it and have started to use it in anger it has been a real joy, comparatively speaking. If you want to go down the same road yourself and need help with any of this, or want source code for either these colour operations or converting images between RGB and CIELAB, then feel free to just drop me a line.
[Posted 07/04/2010] |