Color spaces

I sometime come accross color spaces other than the "usual" RGB one, and I'm always confused about what they truly are, how they relate and why they are what they are. This article is a memo to myself to try to clarify my mind, and maybe someone else's at the same time. Sources are, a lot of Wikipedia as usual, chapter 2 of "Color Image Edge Detection and Segmentation: A Comparison of the Vector Angle and the Euclidean Distance Color Similarity Measures" by Slawomir B. Wesolkowski, "A Beginner’s Guide to (CIE) Colorimetry" by Chandler Abraham, this pdf by Alberto Del Bimbo, and many others linked below. There are surely things I still misunderstand, feel free to correct or complement by sending me an email.

(Edit on 2022/03/30 and 2023/10/15)
Interesting videos on Youtube: Moviola "Color science basics for filmmakers", Computerphile "Colourspces", Strange Loop Conference "RGB to XYZ: The science and History of Color", Acerola "Your colors suck".
Online conversion tool to check your implementations available here.

(Edit on 2022/06/26)
X-Rite has an interesting paper to read here.

(Edit on 2022/12/12)
In this article Bjorn Ottosson introduces a color space he has designed himself: the Oklab color space. It seems to have interesting properties and worth having a look at.

LMS

What's called a color is our psychophysical response to light interacting with our retina. To describe a perceived color we first need to describe the light entering the eye. This can accurately be done with a SPD (Spectral Power Distribution): for each wavelength the SPD gives the intensity of the light at that wavelength. A pure white light as a constant SPD, but under normal circumstances light is rarely pure white and its SPD is a function difficult to express and manipulate in practice.

Then, there is the question of how to describe the interaction of light with the retina. The trichromatic theory explains how the light interacts with our retina through three types of cells, each one with its own profile of sensitivity \(l(\lambda)\), \(m(\lambda)\), \(s(\lambda)\) (how much a cell reacts to a given wavelength). Given the SPD \(spd(\lambda)\) of the light entering the eye, the response of the retina can then be expressed as three signals \(L\), \(M\), \(S\) as follow: $$ \begin{array}{l} L=\int spd(\lambda)l(\lambda)d\lambda\\ M=\int spd(\lambda)m(\lambda)d\lambda\\ S=\int spd(\lambda)s(\lambda)d\lambda\\ \end{array} $$

This is the LMS color space.

CIE RGB

Note that it isn't possible to calculate back \(spd\) from \(L\), \(M\), \(S\). This means different spectral power distributions can be perceived exactly as the same color by our brain. It's called metamerism. That may look like a bad news, but it's actually a good one: we can replace natural light and its messy \(spd(\lambda)\) function by another one, easier to define and use, and still be able to recreate all the colors our brain perceives. In particular, monochromatic light (i.e. light with a SPD concentrated at one single wavelength) reduces the integral to a simple product of the \(l(\lambda)\), \(m(\lambda)\), \(s(\lambda)\) functions with the intensity of that light.

This was exploited independently by two English researchers, David Wright and John Guild, in the 1920's to make experiments in colorimetry. An interactive reproduction of their experiments is available here. The idea is to match the response to monochromatic lights of given wavelength (\(\lambda_t\)) and intensity (\(I_t\)), with a composition of three monochromatic lights (the primary colors) with fixed wavelengths (\(\lambda_r\), \(\lambda_g\), \(\lambda_b\)) and variable intensity (\(I_r\), \(I_g\), \(I_b\)). The experiment is equivalent to solving empirically: $$ \begin{array}{l} I_tl(\lambda_t)=I_rl(\lambda_r)+I_gl(\lambda_g)+I_bl(\lambda_b)\\ I_tm(\lambda_t)=I_rm(\lambda_r)+I_gm(\lambda_g)+I_bm(\lambda_b)\\ I_ts(\lambda_t)=I_rs(\lambda_r)+I_gs(\lambda_g)+I_bs(\lambda_b)\\ \end{array} $$

Note that \(l(\lambda)\), \(m(\lambda)\), \(s(\lambda)\) are different from individual to individual; not much usually; a lot sometime, for people like me who have color blindness (see also this video). Note also that the results depend on the three primary colors. If you can deal with that, this experiment gives you a simple expression, the three values (\(I_r\), \(I_g\), \(I_b\)), describing any monochromatic color (and by combination all the others too).

Based on the works of Wright and Guild, the CIE (Commission Internationale de l'Eclairage) cleaned up the fuzzy bits, set the primary colors' wavelength to be \(\lambda_r=700nm\), \(\lambda_g=546.1nm\) and \(\lambda_b=435.8nm\), and defined what's known as the "1931 CIE standard observer": three color matching functions \(\overline{r}(\lambda)\), \(\overline{g}(\lambda)\), \(\overline{b}(\lambda)\) looking like this, used in place of the sensitivity profiles \(l(\lambda)\), \(m(\lambda)\), \(s(\lambda)\) to express any color (i.e. the response of our retina to a spectral power distribution \(spd(\lambda)\)) with three values \(R\), \(G\), \(B\) (called the tristimulus values). These color matching functions are defined such as the primary colors (red, green, blue) become respectively (1,0,0), (0,1,0), (0,0,1). $$ \begin{array}{l} R=\int spd(\lambda)\overline{r}(\lambda)d\lambda\\ G=\int spd(\lambda)\overline{g}(\lambda)d\lambda\\ B=\int spd(\lambda)\overline{b}(\lambda)d\lambda\\ \end{array} $$

This is the CIE RGB color space.

CIE XYZ

If you look at the matching functions of the 1931 CIE standard observer you see they return negative values for some wave lengths. This was inconvenient and the CIE wished to define another color space with more practical mathematical properties. The color matching functions, hence the CIE RGB values, are defined for a given set of three primary colors. You could select three different primary colors, measure the corresponding \(\overline{r}(\lambda)\), \(\overline{g}(\lambda)\), \(\overline{b}(\lambda)\) and end up with an equally valid but different color space.

However, the human retina being how it is, to obtain the color space they wished, it would have taken primary colors out of the human gamut. Instead, forget about the reality of these primary colors and transform from the standard observer to another set of color matching functions by applying a linear transformation to the CIE RGB values. The would-be resulting primary colors are shown on this diagram (more about the meaning of this diagram in the next section). This is a purely mathematical construction, but it serves perfectly its practical purpose. The corresponding color matching functions look like this. Positive eveywhere, everybody's happy. Conversion from CIE RGB is done as follow: $$ \left[ \begin{array}{c}X\\Y\\Z\\\end{array} \right] = \left[ \begin{array}{ccc} 0.49&0.31&0.2\\ 0.17697&0.8124&0.01063\\ 0.0&0.01&0.99\\ \end{array} \right] \left[ \begin{array}{c}R\\G\\B\\\end{array} \right] $$

This is the CIE XYZ color space.

CIE xyY

In the CIE XYX color space, Y represent the luminance (how bright), and the XZ plane contains all the possible chromaticities at a given luminance. In practice it is often arbitrarily scaled such as Y=1 or Y=100 represents the brightest possible white.

The luminance being isolated on its own axis, it has the handy property to allow the representation of all possible chromaticities on a 2D diagram (while in CIE RGB color space it's spread over a 3D volume difficult to visualise). To do so we derive two new parameters: \(x\) and \(y\) (not to be confused with \(X\) and \(Y\)) to represents the chromaticity as follow: $$ \begin{array}{l} x=X/(X+Y+Z)\\ y=Y/(X+Y+Z)\\ \end{array} $$

Plotting for a convenient luminance \(Y\) gives a chromacity diagram like this. A more rigorous definition of "convenient luminance" is obtained from the CIE standard illuminants. The most commonly used is the CIE standard illuminant D65 which corresponds to an average midday light in western/northern Europe. A chromacity diagram where the white point \((x,y)=(1/3,1/3)\) is indicated to be "D65" represents all chromaticities of the human gamut as perceived in that average daylight brightness.

This is the xyY color space.

sRGB

The color spaces introduced until now all have their root into biology, into how our retina works. Hardware and software constraints pushed engineer toward new color spaces more appropriate to their needs. In 1996, Hewlett Packard and Microsoft defined for convenience the sRGB standard, matching the specifications of the computer monitors in use at that time. It became the default standard, known as the RGB color space, and without further indication that's how you should interpret RGB values. Beware, it must really not be confused with the CIE RGB color space, of which it is a subset.

The tricky part of sRGB is that it embeds a transfer function, known as the gamma correction, which comes from the monitor characteristics this color space was designed for, and deeper, from our retina again. Our retina sensitivity is not linear with respect to brightness: we can distinguish more nuances in the dark hues than in the light ones. Monitors characteristics follow that non linearity for better (perceived) image quality, and the sRGB too. Standards specify a nominal gamma value of 2.2, this is the origin of the exponent showing up in the equations below.

The sRGB is defined by three primary colors red, green and blue, shown on this chromaticity diagram. A color in sRGB color space is expressed with three values \(R\), \(G\), \(B\) in range \([0,1]\) and can be converted to CIE XYZ as follow: $$ \left[ \begin{array}{c}X\\Y\\Z\\\end{array} \right] = \left[ \begin{array}{ccc} 0.4124108464885388&0.3575845678529519&0.18045380393360833\\ 0.21264934272065283&0.7151691357059038&0.07218152157344333\\ 0.019331758429150258&0.11919485595098397&0.9503900340503373\\ \end{array} \right] \left[ \begin{array}{c}R_l\\G_l\\B_l\\\end{array} \right] $$ where $$ C_l=\left\lbrace \begin{array}{ll} C/12.92&C\le0.0392156862745\\ ((C+0.055)/1.055)^{2.4}&C\gt0.0392156862745\\ \end{array} \right. $$ for \(C\in{R,G,B}\)

Reciprocally, one can convert from CIE XYZ to sRGB as follow: $$ \left[ \begin{array}{c}R_l\\G_l\\B_l\\\end{array} \right] = \left[ \begin{array}{ccc} 3.240812398895283&-1.5373084456298136&-0.4985865229069666\\ -0.9692430170086407&1.8759663029085742&0.04155503085668564\\ 0.055638398436112804&-0.20400746093241362&1.0571295702861434\\ \end{array} \right] \left[ \begin{array}{c}X\\Y\\Z\\\end{array} \right] $$ where $$ C=\left\lbrace \begin{array}{ll} 12.92C_l&C_l\le0.00313066844250060782371\\ 1.055C_l^{1/2.4}-0.055&C_l\gt0.00313066844250060782371\\ \end{array} \right. $$ for \(C\in{R,G,B}\)

(edited on 2022/03/30 to correct error and use more accurate values, cf this link)

(edit on 2022/04/10: XYZ also is defined relatively to an illuminant, the values above are valid only relatively to the illuminant D65. Values for D50 can be found in the implementation of conversions between various color spaces given by Peter Occil here)

So, in general, with a standard camera/monitor/software/... this color space is the one defining what the RGB values mean, and as all devices speak that same colorimetric language, data can be passed from one device to another without further ado. The color shown on your monitor will excite your retina roughly the same as would have the light that entered the lens of the camera that took the picture you're looking at. Roughly because the sRGB color space doesn't cover the whole gamut, and because cheap hardware are often poorly calibrated and introduce bias. By the way, there exist color calibration tool for monitors to help you get the best of your screen.

This is the sRGB color space.

Adobe RGB

As you can see from the chromacity diagram, the sRGB color space covers only a small part (around 35%) of the colors perceivable by the human eye. In 1998, Adobe developed a new color space, the Adobe RGB color space, covering up to 50% of the colors. Its chromacity diagram can be seen here.

It was particularly designed to match the CMYK color space of printers, but seems to had a complicated history. It's definition is similar to sRGB (three primary colors, linear transformations, but no gamma), and conversion from/to CIE XYZ are given on the wikipedia page. Of course it requires dedicated software and harware to be processed correctly.

This is the Adobe RGB color space.

CIE LAB, or L*a*b*

The CIE XYZ color space was great but had a problem: it isn't perceptually uniform, which means that if you take the euclidean distance between two points in that color space this distance is not proportional to the perceived difference across the whole space. This creates complication for applications doing image processing.

The CIE then created in 1976 a new standard, the CIE LAB color space. It's a three dimensional space like the previous ones: L is the lightness value (similiar to the Y of CIE XYZ), A is the axis going from red to green, B the axis going from blue to yellow. Easy to understand why it's called the "opponent color model".

The L axis ranges from 0 (black) to 100 (white). The A and B axes have no ranges: the farther in negative values on A, the more green; the farther in positive values on A, the more red; the farther in negative values on B, the more blue; the farther in positive values on A, the more yellow. Finally, this color space is defined relatively to a given white point which usually correspond to the D65 illuminant I've talked about in the "CIE xyY" section.

Important remark about the name of this color space: there exists another "Lab" color space, the Hunter Lab color space, so to avoid any confusion it should be explicitly referred to as the CIE LAB color space, or as the L*a*b* color space.

The conversion from CIE XYZ to CIE LAB can be done as follow: $$ \begin{array}{l} L^*=116*f(Y/Y_n)-16\\ a^*=500*(f(X/X_n)-f(Y/Y_n))\\ b^*=200*(f(Y/Y_n)-f(Z/Z_n))\\ \end{array} $$ where $$ \begin{array}{l} f(t)=\left\lbrace \begin{array}{lll} t^{1/3}&if&t\gt\delta^3\\ t/(3\delta^2)+4/29&if&t\le\delta^3\\ \end{array}\right.\\ \delta=6/29\\ \end{array} $$ and, if using the D65 illuminant $$ \begin{array}{l} X_n=95.0489\\ Y_n=100\\ Z_n=108.8840\\ \end{array} $$

The conversion from CIE LAB to CIE XYZ can be done as follow: $$ \begin{array}{l} X=X_nf^{-1}((L^*+16)/116+a^*/500)\\ Y=Y_nf^{-1}((L^*+16)/116)\\ Z=Z_nf^{-1}((L^*+16)/116-b^*/200)\\ \end{array} $$ where $$ \begin{array}{l} f^{-1}(t)=\left\lbrace \begin{array}{lll} t^3&if&t\gt\delta\\ 3\delta^2(t-4/29)&if&t\le\delta\\ \end{array}\right.\\ \delta=6/29\\ \end{array} $$ (same values for \(X_n\), \(Y_n\), \(Z_n\))

This is the CIE LAB, or L*a*b*, color space.

CIE HLC, or CIE L*C*h*

Some applications prefer to have a representation of the color in cylindrical form. The CIE HLC does just that. The axis of the cylinder is the L* axis of CIE L*a*b*, and the polar coordinates C* and h* encode a* and b* as follow: $$ \begin{array}{l} C^*=\sqrt{a^{*2}+b^{*2}}\\ h^*=atan(b^*/a^*)\\ \end{array} $$ One can go back from CIE L*C*h* to CIE L*a*b* as follow: $$ \begin{array}{l} a^*=C^*cos(h^*)\\ b^*=C^*sin(h^*)\\ \end{array} $$

Warning about the name again, there exists also the CIE HCL (the cylindrical form of CIE LUV), different from CIE HLC. L*C*h* is sometimes written as LCh (from the shortcut Lab/L*a*b*), and L*C*h* exists also for CIE HCL. So to make sure about what you're talking about, better use L*C*h*(uv) and L*C*h*(ab).

This is the CIE HLC, or CIE L*C*h*, color space.

CIE LUV, or L*u*v*

The CIE LUV color space is another color space, derived from CIE UVW, which is derived from CIE UCS, which is derived from CIE XYZ. Phew!

It is a color space similar to CIE LAB and exists because the uniformity pursued by both of these standards is not perfectly achieved by any. L*a*b* is more sensible to green and blue, L*u*v* is more sensible to red. The conversion functions from/to CIE XYZ are available on the Wikipedia page, and I mention it here just for its relation to L*c*h*(uv) and disambiguation with CIE YUV.

This is the L*u*v* color space.

YUV, or YCbCr or ...

The YUV color spaces comes from the television engineering world. It is a similar color model to L*a*b*, with Y describing the brightness and UV following the opponent color model. It's main purpose was to create a color space converting from sRGB and easy to implement in hardware: the U and V coordinates (in [-0.5,0.5]) were used as a deviation from a central white point toward four colors (blue-yellow and red-cyan).

About the names, I quote the Wikipedia articles: "The scope of the terms Y′UV, YUV, YCbCr, YPbPr, etc., is sometimes ambiguous and overlapping."; "... are used interchangeably, leading to some confusion". Better give up and resume (certainly approximately) as: YUV, Y'UV and YCbCr are the same thing plus/minus gamma correction and up to a scaling factor. For the exact conversion from/to sRGB, you'll have to ascertain which YUV you're dealing with and refer to the appropriate documentation (several are given in the Wikipedia pages 1 and 2)

This is the YUV color space.

HSV and HSL

HSV and HSL (resp. hue-saturation-value and hue-saturation-lightness) are cylindrical color spaces derived from a RGB color space (sRGB, Adobe RGB, ...). HSV is also named HSB (hue-saturation-brightness). Note there is also HSI (hue-saturation-intensity) with slightly different definition (cf the Wikipedia page). They both come from the television engineering world. They were created to provide a color space easy enough to convert from RGB for the hardware of the time, and more intuitive to understand.

In both color spaces, the hue is an angular dimension describing the chromaticity (primary red at 0 degree, primary green at 120, primary blue at 240). The central axis of the cylinder is the line of grey, from black at the bottom to white at the top. Saturation varies from the line of grey to a hue of maximum intensity. The meaning of the remaining dimension differs between the two color spaces. Lightness makes a given hue vary from black to white, while value makes a given hue vary from black to that hue of maximum intensity. A visualisation is available here.

A nice and easy visualisation to understand its relation to RGB is available here. The conversion from RGB is done as follow. For Hue (in degrees): $$ \begin{array}{l} M=max(R,G,B)\\ m=min(R,G,B)\\ C=M-m\\ H'=\left\lbrace \begin{array}{lll} undefined&if&C=0\\ (G-B)/C\bmod 6&if&M=R\\ (B-R)/C+2&if&M=G\\ (R-G)/C+4&if&M=B\\ \end{array}\right.\\ H=60H' \end{array} $$

For Lightness: $$ L=(M+m)/2 $$

For Value: $$ V=M $$

For Saturation in HSV: $$ S=\left\lbrace \begin{array}{lll} 0&if&V=0\\ C/V&if&V\ne 0\\ \end{array}\right.\\ $$

For Saturation in HSL: $$ S=\left\lbrace \begin{array}{lll} 0&if&L\in\{0,1\}\\ C/(1-|2L-1|)&if&L\notin\{0,1\}\\ \end{array}\right.\\ $$

The conversion to RGB is done as follow, For HSL: $$ \begin{array}{l} C=(1-|2L-1|).S\\ H'=H/60\\ X=(1-|H'\bmod 2-1|).C\\ (R',G',B')=\left\lbrace \begin{array}{lll} (C,X,0)&if&0\le H'\lt1\\ (X,C,0)&if&1\le H'\lt2\\ (0,C,X)&if&2\le H'\lt3\\ (0,X,C)&if&3\le H'\lt4\\ (X,0,C)&if&4\le H'\lt5\\ (C,0,X)&if&5\le H'\lt6\\ \end{array}\right.\\ m=L-C/2\\ (R,G,B)=(R'+m,G'+m,B'+m)\\ \end{array} $$

For HSV: $$ \begin{array}{l} C=V.S\\ H'=H/60\\ X=(1-|H'\bmod 2-1|).C\\ (R',G',B')=\left\lbrace \begin{array}{lll} (C,X,0)&if&0\le H'\lt1\\ (X,C,0)&if&1\le H'\lt2\\ (0,C,X)&if&2\le H'\lt3\\ (0,X,C)&if&3\le H'\lt4\\ (X,0,C)&if&4\le H'\lt5\\ (C,0,X)&if&5\le H'\lt6\\ \end{array}\right.\\ m=V-C\\ (R,G,B)=(R'+m,G'+m,B'+m)\\ \end{array} $$

For an implementation in C of the conversion RGB-HSV see this previous article.

These are the HSV and HSL color spaces.

rgb, or RGB normalised

The same way CIE xyY has been created from CIE XYZ, it is possible to derive a color space from RGB (sRGB, Adobe RGB, ...) where the brightness is isolated on one axis, allowing for 2d plot of chromaticity looking like this. This is the RGB normalised, or rgb, color space.

It is calculated as follow: $$ \begin{array}{l} r=R/(R+G+B)\\ g=G/(R+G+B)\\ b=B/(R+G+B)\\ \end{array} $$

This is the rgb color space.

l1l2l3

Another color space derived from RGB color spaces, with invariance property regarding to highlighting. Similar to rgb in its conversion formula: $$ \begin{array}{l} l1=\frac{(R-G)^2}{(R-G)^2+(R-B)^2+(G-B)^2}\\ l2=\frac{(R-B)^2}{(R-G)^2+(R-B)^2+(G-B)^2}\\ l3=\frac{(G-B)^2}{(R-G)^2+(R-B)^2+(G-B)^2}\\ \end{array} $$

This is the l1l2l3 color space.

c1c2c3

Another color space derived from RGB color spaces, similar to l1l2l3, with invariance property regarding to shadowing: $$ \begin{array}{l} c1=arctan(R/max(G,B)))\\ c2=arctan(G/max(R,B)))\\ c3=arctan(B/max(R,G)))\\ \end{array} $$

This is the c1c2c3 color space.

CMYK

The color spaces I've spoken so far all follow a color model using three components, but nothing forbid to use a different number. The CMYK color model for example uses four components. It comes from the Eagle Printing Company who used for the first time in 1906 a mixture of cyan, magenta, yellow and black inks to reproduce other colors.

Contrarily to the RGB color model, which is an additive model, the CMYK is a substractive model. It's easy to understand why one is better adapted to monitor and the other to printer. The monitor starts black and goes toward white as you add/emit more light. The paper starts white and goes toward black as you add/print ink droplets which block light from being reflected by the paper.

As it is a device-dependent model, there is no general way to convert from CMYK from/to another color space. Instead lookup tables are used.

This is the CMYK color space.

One last word about color space names.

What the heck is happening in the colorimetry world ??? The guys there seem to enjoy naming their color spaces like a junior Python programmer is naming his variables... xyz and XYZ, mixed up into xyY (sooo easy to make the distinction when you speak); CIE Lab bumping into Hunter Lab, and replaced with L*a*b* (so easier to pronounce that nobody use it), while there seem to be absolutely no reason to stick to 'a' and 'b'; HLC and HCL, clearly not speaking about the same thing right?; and their respective LCh (oh sorry was it L*C*h*?) which should be clarify into LCh(uv) and LCh(ab) but who cares; YCbCr, maybe Y'CbCr, or maybe Y Pb/Cb Pr/Cr, but is also written as \(YC_BC_R\) or \(Y'C_BC_R\), oh wait that's also abbreviated, sometime, into YCC; etc...

Next time you work with color spaces, first thing to do: make sure everyone clearly is on the same page, understand what he's talking about, avoid shortcut at all cost even if it costs you a few hours of elocution classes.

2022-03-29
in All, Computer graphics,
84 views
Copyright 2021-2024 Baillehache Pascal