The RGB Colour Space

The RGB colour space is arguably the most common colour space. It is an additive system that describes colours through the mixing of three primaries. The most common RGB colour space is sRGB (standard Red Green Blue), jointly introduced by HP and Microsoft in 1996, which has gradually gained widespread support across various industries and software.

An RGB colour space, as exemplified by sRGB, is primarily defined by three components: the colorimetric definition of its RGB primaries and white point, a non-linear transfer function, and the viewing environment. For instance, sRGB defines the xy colour coordinates for its red, green, and blue primaries as (0.64, 0.33), (0.30, 0.60), and (0.15, 0.06) respectively, with the white point coordinates at (0.3127, 0.3290); it employs a transfer function that approximates a gamma of 2.2; and it specifies the viewing environment’s illuminance, ambient reflectance, and even glare.

For details, please see the definition of sRGB.

Based on the first two parts of the definition—the three primaries and the white point, and the transfer function—the conversion sequence can be established as RGB -> Linear RGB -> XYZ. The conversion from linear RGB to XYZ is achieved using a matrix. This matrix effectively describes the positions of the three primaries within CIEXYZ and the proportions in which they are mixed to produce the white point.

Building the Conversion Matrix

Key: Determining the “Proportions” of the Primaries

The definition only provides the “colour coordinates” for the primaries, and colour coordinates contain no luminance information. Imagine we have red, green, and blue LED light sources. By adjusting their brightness, we can mix them to create different colours. Our goal now is to find the proportions that, when mixed, produce the white point colour coordinates defined in the specification.

A straightforward method is as follows (provided by Claude 3.7 Sonnet):

  1. First, preset the luminance of the three primaries and the white point to 1 (Y=1), and calculate their corresponding CIEXYZ values (by converting from xyY to XYZ).

  2. Since CIEXYZ is linear, solve for the proportions in which the three primaries (each with a luminance of 1) must be combined to produce the white point. This gives the actual XYZ values for the primaries.

  3. Following the definition of matrix multiplication, describe the linear combination of the primaries as a matrix to construct the conversion matrix.

Mixing Colour Coordinates

The following is a more convoluted process I worked through while thinking about this problem. The method above is sufficiently concise and intuitive, so you can skip the following section and proceed to the part about the transfer function. I’m leaving this here purely because I couldn’t bring myself to delete it.

How do we determine the new colour coordinates after mixing three sets of colour coordinates?

First, convert the xy colour coordinates to CIEXYZ tristimulus values. The Z value is not important for the subsequent mixing, so its transformation is omitted here. Y is the proportion we are looking for.

$$ \begin{align*} &X+Y+Z=\frac{Y}{y} \\ &X=x(X+Y+Z)=\frac{xY}{y} \\ \end{align*} $$

We use subscripts to denote the three components, while variables without subscripts represent the mixed colour. CIEXYZ is linear, so values can be summed. Here, we calculate the X and Y values of the mixed colour, as well as the sum of X, Y, and Z (used for later calculation of the colour coordinates).

$$ \begin{align*} & Y=Y_{1}+Y_{2}+Y_{3} \\ & X=\frac{x_{1}Y_{1}}{y_{1}}+\frac{x_{2}Y_{2}}{y_{2}}+\frac{x_{3}Y_{3}}{y_{3}} \\ & X+Y+Z=\frac{Y_{1}}{y_{1}}+\frac{Y_{2}}{y_{2}}+\frac{Y_{3}}{y_{3}} \\ \end{align*} $$

Let $X+Y+Z=S$. After summing the tristimulus values, we convert back to xyY colour coordinates. The mixed colour coordinates are:

$$ \begin{align*} \\ & y=\frac{Y}{S} \\ & x=\frac{X}{S} \end{align*} $$

That is:

$$ \begin{align*} &S=\frac{Y}{y} \\ &X=xS=\frac{xY}{y} \end{align*} $$

When the colour coordinates of the three primaries and the white point are known, the following system of equations can be constructed.

$$ \left\{ \begin{align*} & Y_{1}+Y_{2}+Y_{3}=Y \\ & \frac{1}{y_{1}}Y_{1}+\frac{1}{y_{2}}Y_{2}+\frac{1}{y_{3}}Y_{3}=\frac{Y}{y} \\ & \frac{x_{1}}{y_{1}}Y_{1}+\frac{x_{2}}{y_{2}}Y_{2}+\frac{x_{3}}{y_{3}}Y_{3}=\frac{xY}{y} \end{align*} \right. $$

Expressed in matrix form:

$$ \begin{bmatrix} 1 & 1 & 1 \\ \frac{1}{y_1} & \frac{1}{y_2} & \frac{1}{y_3} \\ \frac{x_1}{y_1} & \frac{x_2}{y_2} & \frac{x_3}{y_3} \end{bmatrix} \begin{bmatrix} Y_1 \\ Y_2 \\ Y_3 \end{bmatrix} = \begin{bmatrix} Y \\ \frac{Y}{y} \\ \frac{xY}{y} \end{bmatrix} $$

Typically, Y is set to 1 (i.e., the white point luminance is normalised). This allows us to solve for the proportions (the luminance Y of each primary) in which the three primaries must be mixed to obtain the specified white point.

The Conversion Matrix

After finding the xyY values for the three primaries, we convert them to XYZ. It is easy to see that we have now calculated the corresponding XYZ tristimulus values for the basis vectors in the RGB space.

Therefore, the conversion matrix from RGB to XYZ is as follows. To convert from XYZ to RGB, one simply needs to find the inverse of this matrix.

$$ \begin{bmatrix} X_{r} & X_{g} & X_{b} \\ Y_{r} & Y_{g} & Y_{b} \\ Z_{r} & Z_{g} & Z_{b} \\ \end{bmatrix} \begin{bmatrix} R \\ G \\ B \end{bmatrix} = \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} $$

The Non-linear Transfer Function

To better match the perceptual characteristics of the human eye, values in an RGB space are typically passed through a non-linear transfer function, converting linear RGB to non-linear RGB. For example, sRGB uses a non-linear transfer function that approximates a gamma of 2.2 and corrects for potential issues near zero during the inverse transformation.

The conversion function from linear sRGB to non-linear sRGB is as follows. Although the exponent is 2.4, it is actually closer to $x^{2.2}$.

$$ \begin{align*} & R' = \begin{cases} 12.92R & R \leq 0.0031308 \\ 1.055R^{1/2.4}-0.055 & R > 0.0031308 \end{cases} \end{align*} $$

Thoughts

How can one determine if a given set of tristimulus values lies within a specific RGB colour space?

How to determine if given XYZ tristimulus values fall within a colour gamut.
The gamut is defined by four CIE xy coordinates representing red, green, blue, and white (assume white point luminance has been normalised to 1.0).
Please provide the Python code.

The first model to answer this question correctly without an internet connection was Deepseek R1 (referring to the first generation). It required an output of about ten thousand tokens, and most platforms deploying R1 do not support such long outputs.

Models that subsequently answered correctly: Gemini 2.5 Pro, OpenAI o3 Pro, Deepseek V3-0324, Claude 3.7 Sonnet, Grok 4, Kimi K2.

Models that failed: GPT 4.1, Qwen, Claude Sonnet 4 (while 3.7 could reason its way to the correct answer, 4 could not, even with reasoning).

The key issue was whether luminance was correctly considered. The correct approach is to construct the conversion matrix, transform the XYZ values to RGB, and then check if any of the resulting RGB components are less than 0 or greater than 1. A typical mistake is to convert the XYZ values to xy colour coordinates and check if the point lies within the triangle formed by the three primaries.