Page updated: April 14, 2020
Author: Curtis Mobley
View PDF

# From XYZ to RGB

#### From CIE XYZ to RGB Values

Computer monitors and TVs have light sources made of many groups of three small pixels. One pixel in each group generates visually red light, one green, and one blue. Each group can generate various levels of brightness for each color. Computer monitors thus use a triplet of red, green, and blue (RGB) values to deﬁne how much of each primary color is used to generate a desired color. In most monitors, each value of R, G, or B ranges from 0 (no light of that color emitted; the pixel is turned oﬀ) to ${2}^{8}-1=255$ (maximum brightness). This is usually called “8 bit/channel” or “24 bit,” i.e. $3×8$, color. These 256 brightness levels for each primary color give a total of $25{6}^{3}=16,777,216$ diﬀerent colors and levels of brightness that can be displayed, even though the human eye can perceive diﬀerences in far fewer colors and brightness levels. Digital cameras likewise store images in terms of RGB values.

As was seen on the Chromaticity page, converting a spectrum $\Lambda \left(\lambda \right)$ into CIE $\left(X,Y,Z\right)$ and then into $\left(x,y\right)$ chromaticity values is easy. Converting between $\left(X,Y,Z\right)$ and $\left(R,G,B\right)$ values is more complicated.

The personal computer industry (Microsoft and Hewlett Packard in particular, see Stokes et al., 1996) deﬁned an RGB color model or color space, i.e. a gamut of colors, for use with PC monitors. This color model, called sRGB, is the gamut of colors that can be generated on most PC computer monitors. (Not surprisingly, Apple has its own color model, as does Adobe, and there are at least a dozen others.)

The conversion from CIE XYZ to sRGB coordinates is given by

 $\left[\begin{array}{c}\hfill R\hfill \\ \hfill G\hfill \\ \hfill B\hfill \end{array}\right]=\left[\begin{array}{ccc}\hfill 3.2404542\hfill & \hfill -1.5371385\hfill & \hfill -0.4985314\hfill \\ \hfill -0.9692660\hfill & \hfill 1.8760108\hfill & \hfill 0.0415560\hfill \\ \hfill 0.0556434\hfill & \hfill -0.2040259\hfill & \hfill 1.0572252\hfill \end{array}\right]\left[\begin{array}{c}\hfill X\hfill \\ \hfill Y\hfill \\ \hfill Z\hfill \end{array}\right]$ (1)

In this equation, the $\left(X,Y,Z\right)$ values are assumed to be scaled from 0 to 1. The conversion matrix seen here comes from the excellent web site maintained by Bruce Lindbloom. The Lindbloom web site gives all of the details about color spaces and conversions from one color space to another, including online calculators and downloadable spreadsheets for doing various calculations.

Now consider CIE reference illuminant E, which is pure white, with equal energy at each wavelength. Setting $\Lambda \left(\lambda \right)=1$ for all $\lambda$ gives a values of $7.30\cdot 1{0}^{4}$ for each of $X,Y$, and $Z$. Rescaling these values to 1 and using them in Eq. (1) gives $\left(R,G,B\right)=\left(1.205,0.948,0.909\right)$, which can be rescaled to $\left(255,201,192\right)$. This result is not $\left(255,255,255\right)$ as might be expected for a pure white color. The computed RBG color is actually a pale red or pink. The reason for this color mismatch is that sRBG is based on the D65 reference illuminant, whereas the CIE 1931 chromaticity diagram uses reference illuminant E to deﬁne “white.”

If we let $\Lambda \left(\lambda \right)$ be the normalized D65 spectrum seen in the last ﬁgure of the Chromaticity page, then $\left(X,Y,Z\right)=\left(58228.0,61262.5,66713.0\right)$. Rescaling these values to a maximum value of 1 and inserting them into Eq. (1) then returns each of $R,G$, and $B$ as 0.918. Multiplying these values by 255 rescales them to $\left(234,234,234\right)$, which is a very light gray. Keep in mind that gray is just white that is not very bright, so these values can be rescaled to $\left(255,255,255\right)$ without changing the color. Thus the sRBG color model returns the D65 illuminant as the white color, and it returns the equal-energy spectrum E as a pink color.

The conversion from sRGB values to XYZ is given by the inverse of Eq. (1):

 $\left[\begin{array}{c}\hfill X\hfill \\ \hfill Y\hfill \\ \hfill Z\hfill \end{array}\right]=\left[\begin{array}{ccc}\hfill 0.4124564\hfill & \hfill 0.3575761\hfill & \hfill 0.1804375\hfill \\ \hfill 0.2126729\hfill & \hfill 0.7151522\hfill & \hfill 0.0721750\hfill \\ \hfill 0.0193339\hfill & \hfill 0.1191920\hfill & \hfill 0.9503041\hfill \end{array}\right]\left[\begin{array}{c}\hfill R\hfill \\ \hfill G\hfill \\ \hfill B\hfill \end{array}\right]$ (2)

The RGB values in Eq. (2) are considered to be between 0 and 1. If we rescale $\left(R,G,B\right)=\left(255,255,255\right)$ to $\left(1,1,1\right)$ and insert into this equation, it returns $\left(X,Y,Z\right)=\left(0.950,1.000,1.089\right)$, which gives the CIE chromaticity coordinates $\left(x,y\right)=\left(0.313,0.329\right)$. This is the slightly bluish color of the D65 spectrum shown by the box symbol in Fig. 1.

Using Eq. (2) to convert $\left(R,G,B\right)=\left(1,0,0\right)$ gives $\left(X,Y,Z\right)=\left(0.4125,0.2127,0.01933\right)$, which gives $\left(x,y\right)=\left(0.640,0.330\right)$. Converting (0, 1, 0) gives $\left(x,y\right)=\left(0.30,0.60\right)$, and (0, 0, 1) gives $\left(x,y\right)=\left(0.15,0.06\right)$. These three (x,y) values deﬁne the vertices of the sRBG gamut triangle seen in Fig. 1. It is clear that this gamut cannot accurately reproduce many of the colors visible to the eye (nor can any of the other gamuts used in computer montors and TVs). Indeed, the sRGB color space represents only 35% of the CIE (x,y) color space. In other words, only 35% of the colors as seen by the eye can be accurately reproduced on a computer monitor using the sRBG color model. Figure 1: The CIE chromaticity diagram with the sRGB gamut shown by the triangle. The circle is the CIE illuminant E white point, and the box is the sRGB D65 illuminant white point.

It was mentioned on the Color Vision page that “brown is just red that is not very bright.” Figure 4 of that page showed a sequence of color patches that were generated by turning on only the red pixels of a monitor, but with decreasing intensities. The perceived color went from bright red for $\left(R,G,B\right)=\left(255,0,0\right)$ to a dark reddish brown for $\left(R,G,B\right)=\left(125,0,0\right)$. Those two color patches are reproduced in Fig. 2. If the RGB values for these two color patches are rescaled to (1,0,0) and (0.49,0,0), respectively, and inserted into Eq. ( 2), the resulting CIE chromaticities are the same for each: $\left(x,y\right)=\left(0.640,0.330\right)$. What is diﬀerent is the luminance: $Y=0.2127$ for the bright red patch, and $Y=0.1043$ for the dark brown patch. It is likely that most people would call these patches diﬀerent colors, but in the language of color science, they are the same color but diﬀerent brightnesses (same chromaticity but diﬀerent luminances). Figure 2: Two color patches with the same chromaticities $\left(x,y\right)=\left(0.64,0.33\right)$ but with diﬀerent luminances $Y=0.2127$ and $Y=0.1043$.

There are additional complications to mention in the conversion from XYZ to RGB color speciﬁcations. The ﬁrst is that the eye does not respond in a linear fashion to diﬀerences in brightness. In particular, the eye is more sensitive to diﬀerences in darker color tones than it is to diﬀerences in brighter tones. Therefore, a linear spacing of RGB values allocates more of the 0-255 range to high values, which the eye cannot distinguish well, than to low values where the eye sees greater diﬀerences for a the same diﬀerence in RGB values. Therefore, after using Eq. (1) to obtain “linear” RGB values, is it customary to apply a gamma correction to the result. A gamma correction is a non-linear “stretching” of the RGB values so as to make better use of the limited range of values (usually 0 to 255) available for storing the color information. The gamma correction for the sRGB color model is given by

$\begin{array}{llll}\hfill if\phantom{\rule{1em}{0ex}}R\le & \phantom{\rule{1em}{0ex}}0.0031308,\phantom{\rule{1em}{0ex}}then\phantom{\rule{1em}{0ex}}reset\phantom{\rule{1em}{0ex}}R\phantom{\rule{1em}{0ex}}to\phantom{\rule{1em}{0ex}}12.92R\phantom{\rule{2em}{0ex}}& \hfill & \phantom{\rule{2em}{0ex}}\\ \hfill if\phantom{\rule{1em}{0ex}}R>& \phantom{\rule{1em}{0ex}}0.0031308,\phantom{\rule{1em}{0ex}}then\phantom{\rule{1em}{0ex}}reset\phantom{\rule{1em}{0ex}}R\phantom{\rule{1em}{0ex}}to\phantom{\rule{1em}{0ex}}1.055{R}^{1∕2.4}-0.055\phantom{\rule{0.3em}{0ex}}.\phantom{\rule{2em}{0ex}}& \hfill & \phantom{\rule{2em}{0ex}}\end{array}$

The same transformation is applied to the G and B values. Here the gamma value is $\gamma =2.4$. After this gamma correction, an input of $\left(X,Y,Z\right)=\left(1,1,1\right)$ results in $\left(R,G,B\right)=\left(255,230,225\right)$ rather than the values of (255, 201, 192) found above using only Eq.(1). Conversely, if gamma-corrected RGB values are to be converted to XYZ values, the gamma correction needs to be undone via

$\begin{array}{llll}\hfill if\phantom{\rule{1em}{0ex}}R\le & \phantom{\rule{1em}{0ex}}0.04045,\phantom{\rule{1em}{0ex}}then\phantom{\rule{1em}{0ex}}reset\phantom{\rule{1em}{0ex}}R\phantom{\rule{1em}{0ex}}to\phantom{\rule{1em}{0ex}}R∕12.92\phantom{\rule{2em}{0ex}}& \hfill & \phantom{\rule{2em}{0ex}}\\ \hfill if\phantom{\rule{1em}{0ex}}R>& \phantom{\rule{1em}{0ex}}0.04045,\phantom{\rule{1em}{0ex}}then\phantom{\rule{1em}{0ex}}reset\phantom{\rule{1em}{0ex}}R\phantom{\rule{1em}{0ex}}to\phantom{\rule{1em}{0ex}}{\frac{\left(R+0.055\right)}{1.055}}^{2.4}\phantom{\rule{0.3em}{0ex}}.\phantom{\rule{2em}{0ex}}& \hfill & \phantom{\rule{2em}{0ex}}\end{array}$

The same transformation is applied to the gamma-corrected G and B values. The resulting “linear” RBG values can then be used is Eq. 2.

Second, you often have to make a subjective decision on how to rescale the RGB values to get the right brightness when displayed. For example, Dierssen et al. (2006) found that scaling $\left(X,Y,Z\right)$ so that $Y=0.4$ gave RGB values in the mid-range of brightness and reasonable screen colors from RGB values computed by Eq. (1). The value of 0.4 was an ad hoc choice determined by trial and error for visual appearance of ocean radiance spectra colors. As was seen in Fig. 2, the brighness aﬀects the perceived color.

Third, note that the 3x3 transformation matrix in Eq. (2) has positive elements. Thus any $\left(R,G,B\right)$ triplet of positive numbers generates an $\left(X,Y,Z\right)$ triplet of positive numbers, i.e. a valid point $\left(x,y\right)$ in the CIE chromaticity diagram. That is to say, any RGB color can be represented on the CIE diagram. However, some of the matrix elements in Eq. (1) are negative. This means that not every valid $\left(X,Y,Z\right)$ or $\left(x,y\right)$ can be represented by valid $\left(R,G,B\right)$ values; some of the $R,G$, and $B$ values may be negative. When that happens, about all you can do is set the negative value to 0 and hope that the displayed color is not too diﬀerent from what your eye would see in nature.

Fourth, color reproduction gets even more complicated when printing. Computer monitors are emitting light, and various colors are generated by adding together diﬀerent amounts of red, green, and blue light. Thus yellow is generated by turning on the red and green pixels. The RGB system is an additive color system. When viewing colors on a printed page, you are seeing reﬂected light. The dyes in the ink absorb, or subtract, various colors from the incident (usually white) light. The printing industry thus deals with subtractive colors, e.g., green is generated by subtracting (absorbing) blue and red from white. Color printers thus use the CMYK (cyan, magenta, yellow, black) subtractive color system, which speciﬁes how much ink of various colors to put onto the page, rather than how much light to generate. Some printers have additional ink colors. Thus the color space or gamut for a printer, when plotted on a CIE diagram, will have more than three vertices if the printer uses more than three colors of ink. This can give better coverage of the human vision color space than can a three-color RGB system. Needless to say, converting a computer screen image from RGB to CMYK values is a messy business, and full account of the reference illuminants and color models for the monitor and the printer must be taken into account. This is what is done in PhotoShop, for example, when you do a “save as CMYK” on an RGB jpeg ﬁle. The resulting printed image may or may not be satisfactory, depending on whether or not the underlying color models are consistent with the printer to be used.

The HydroLight radiative transfer model computes the $\left(x,y,Y\right)$ values for ${L}_{w},{L}_{u},{E}_{d}$, and ${E}_{u}$ whenever the run covers at least the 400-700 nm range. These quantities are uniquely determined for each spectrum. However, HydroLight does not attempt to compute corresponding RGB values because those values are device dependent and may require subjective scaling to get good color reproduction. If you want to turn your spectra into RGB or CMYK values, you can start with the HydroLight-computed $\left(X,Y,Z\right)$ values, but beyond that you are on your own. Note that given $\left(x,y,Y\right)$, you can recover $\left(X,Y,Z\right)$ from

$\begin{array}{llll}\hfill X=& \phantom{\rule{1em}{0ex}}\frac{xY}{y}\phantom{\rule{2em}{0ex}}& \hfill & \phantom{\rule{2em}{0ex}}\\ \hfill Y=& \phantom{\rule{1em}{0ex}}Y\phantom{\rule{2em}{0ex}}& \hfill & \phantom{\rule{2em}{0ex}}\\ \hfill Z=& \phantom{\rule{1em}{0ex}}\frac{\left(1-x-y\right)Y}{y}\phantom{\rule{2em}{0ex}}& \hfill & \phantom{\rule{2em}{0ex}}\end{array}$

where Y is in the range [0, 1].

This is enough to say about colors. This page barely gets you started into the very complicated business of color management and rendering on speciﬁc monitors or printers. The previously mentioned web site maintained by Bruce Lindstrom is an excellent place to start if you wish to dig deeper into these topics.