# How are the matrices for the RGB to/from CIE XYZ conversions generated?

So far, I've seen two different sets matrices for RGB ⇄ CIE XYZ. One from the Rochester Institute of Technology:

\begin{align} \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} &= \begin{bmatrix} 0.412453 & 0.357580 & 0.180423 \\ 0.212671 & 0.715160 & 0.072169 \\ 0.019334 & 0.119193 & 0.950227 \end{bmatrix} \begin{bmatrix} R \\ G \\ B \end{bmatrix} \\ \begin{bmatrix} R \\ G \\ B \end{bmatrix} &= \begin{bmatrix} 3.240479 & -1.537150 & -0.498535 \\ -0.969256 & 1.875992 & 0.041556 \\ 0.055648 & -0.204043 & 1.057311 \end{bmatrix} \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} & \end{align} And another from Wikipedia: \begin{align} \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} &= \frac{1}{0.17697} \begin{bmatrix} 0.49000 & 0.31000 & 0.20000 \\ 0.17697 & 0.81240 & 0.01063 \\ 0.00000 & 0.01000 & 0.99000 \end{bmatrix} \begin{bmatrix} R \\ G \\ B \end{bmatrix} \\ \begin{bmatrix} R \\ G \\ B \end{bmatrix} &= \begin{bmatrix} 0.41847 & -0.15866 & -0.082835 \\ -0.091169 & 0.25243 & 0.015708 \\ 0.00092090 & -0.0025498 & 0.17860 \end{bmatrix} \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} \end{align}

These numbers are much different from each other. I'd like to know how these matrices were developed and how I can "create" these conversions given parameters for some sort of standard illuminant.

In the case of D65 at 2°, those parameters would be $$x=0.31271$$, $$y=0.32902$$, and $$Y=100$$, from which I could acquire the missing tristimulus values of $$X$$ and $$Z$$ by this set of equations. From these values I should end up with matrices equal to RIT's.

From these values, how do I create the matrices required for RGB ⇄ CIE XYZ conversion?

(Moved from Math StackExchange)

• Isn’t this more about human visual perception than physics? Jun 24, 2019 at 3:12
• I originally posted this in math.se and I moved it here by moderator request. Don't know where else I should be putting this, I just want to know how these matrices are made and why so I can generate them properly in the program I'm writing. @G.Smith
– Aly
Jun 24, 2019 at 3:29
• @G.SmithG I recommended physics because I thought optics people might know something about this. If not, do you have a better idea on where to fit this question? Jun 24, 2019 at 21:19

# Note about RGB color space(s)

You will need to be specific about which color space you mean when you say 'RGB'. There are a lot! The wikipedia article you linked to refers to the CIE RGB color space, which is mostly historical. CIE RGB is quite different from say, the sRGB color space, which is much more commonly used for encoding digital images. (See https://en.wikipedia.org/wiki/RGB_color_space for more info.)

This explains why you found different matrix values: they were meant for different RGB color spaces. (The MIT link didn't seem to specify which color space their 'RGB' refers to; tsk tsk.)

# How to calculate the RGB-to-XYZ conversion matrix

A guy named Bruce Lindbloom has a great explanation of how to do this. I've taken the info directly from here: http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html

In the end, it's just straight linear algebra, transforming one set of values into another. You need to know the tristimulus XYZ of your RGB primaries, as well as of your target White point (commonly D65). These four points form the basis of your transformation, as any color in the RGB system is just some recombination of these values.

Let's look at the matrix M:

\begin{align} \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} &= M \begin{bmatrix} R \\ G \\ B \end{bmatrix} \\ \end{align}

which is really comprised of components, where: \begin{align} M &= \begin{bmatrix} SrXr & SgXg & SbXb \\ SrYr & SgYg & SbYb \\ SrZr & SgZg & SbZb \end{bmatrix} \\ \end{align}

and: \begin{align} \begin{bmatrix} Sr \\ Sg \\ Sb \end{bmatrix} &= \begin{bmatrix} Xr & Xg & Xb \\ Yr & Yg & Yb \\ Zr & Zg & Zb \end{bmatrix}^{-1} \begin{bmatrix} Xw \\ Yw \\ Zw \end{bmatrix} \end{align}

The derivation of this ultimately comes from knowing that Xr + Xg + Xb = Xw, (meaning the sum of the primaries must equal the white point), and the same for Y and Z.

I see you know how to get the tristimulus XYZ from CIE 1931 Yxy values, but for those who don't:

xyz from XYZ:

• x = X / (X + Y + Z)
• y = Y / (X + Y + Z)
• z = Z / (X + Y + Z) = 1 - x - y

Going the other direction, XYZ from Yxy:

• X = x * Y/y
• Y = y * Y/y = Y (also, just Y = Y.... :)
• Z = z * Y/y = (1 - x - y) * Y/y

Hopefully you can now calculate your matrix M for any desired RGB color space, as long as you know the XYZ (or Yxy values to calculate XYZ) for the 4 RGBW colors used in that color space. But be careful when designing a color space! Remember that R + G + B = W must hold for all 3 tristimulus values.

The easiest way to tweak a color space is to scale one or more of the primaries: multiply all three tristimulus values by a scale factor. This keeps the relative chromaticity the same (XYZ scale together), but the resulting sum for white's color point is shifted. If you increase the scale on the red primary, its color stays the same, while your white point becomes 'redder', etc.

The previous answer is completely correct, but I interpret the question a little differently - rather than how to calculate the matrix, which of the matrices is correct?

Short answer: Wikipedia is wrong (and has since been corrected).

Longer answer: I will assume we are talking about CIE RGB space (and not a display color space - the previous answer covers that well). If that's the case, then the issue is with that funny value of (1/0.17697).

Two similar, but in some ways importantly different, types of perception measurements were done in the late 1910s and early 1920s. The first are the famous Guild and Wright experiments, color matching the spectral colors with three spectral primaries (red, green and blue). The second type of experiment was measuring the sensitivity of the eye to different wavelengths of light. This was done for both day and night vision, but only the day vision is important here. This gave a bell-shaped function.

The data from Wright and Guild were combined mathematically, giving three color matching functions (one each for red, green and blue). These three functions were normalized such that the areas beneath the curves were the same. Meanwhile, the intensity data from the second type of experiment were also normalized, in this case such that the maximum value (around 560 nm, I can't recall the exact value) was set to 1.

Now comes the rub. It seems useful that the two types of functions (color matching and perceived intensity) should somehow be made to be mathematically related to one another. It seems obvious, to me, that this should be done by scaling the r(lambda) g(lambda) b(lambda) functions such that their areas equaled the area under the intensity curve (note: the symbols r g b should each have a hat, but I can't figure out how to format that). However, the CIE went a different route - they set the value of the r(lambda) function at 700 nm to be equal to the value of the intensity function at 700 nm. I wasn't around at the time, but I assume this made sense in some way that I just can't see - I'm guessing that it might have to do with the fact that only one type of cone cell in the eye (the L cell) absorbs this wavelength.

As a result, the areas under the r(lambda) g(lambda) b(lambda) curves did not come out to some simple value like 1.0, but instead were off from that by a factor of 0.17697. It would be useful that the R G and B tristimulus values for illuminant E (equal intensity across the visible spectrum), would be 1 (or 100), so when calculating these tristimulus values from the color matching functions, the R G B values were all scaled by this amount.

When developing XYZ color space, the CIE decided (and I agree) that it would be better if the areas under the curves (and so the tristimulus values of illuminant E) came out to 1 (or 100, depending on whether you like fractions or percentages), and so this value of 0.17697 came back into play. (the main benefit of doing this is that the y(lambda) function could be exactly equal to the perceived intensity function, rather than off by some factor).

The overall effect was that when converting from the r(lambda) g(lambda) b(lambda) color matching functions to the x(lambda) y(lambda) z(lambda) color matching functions, you had to include the factor of 0.17697. However, when converting between tristimulus values R G B to tristimulus values X Y Z, we don't use this factor because it is already "baked in" to the R G B values, since that factor was used to make the R G B values be 1.0 (or 100) for illuminant E.

This leads to a great opportunity for confusion, as evidenced by the fact that the Wikipedia matrix was incorrect for several years, but at least we can see where that funny factor comes from and where it is, and is not, needed.