BookNotesSlidesP-sets Syllabusdraft · v0.2.49.1
◀▲⌂▶
💬Comments welcome. To leave a note, select any text and click the note / highlight button that pops up — or open the panel with the tab at the top-right (‹). Notes are visible only inside our private review group.
💡 In a hurry? Jump to this chapter’s 1 big lesson ↓

4.4 RGB color spaces⧉

An RGB space chooses primary chromaticities and a reference white; its stored representation also specifies a transfer function. Different choices serve different devices and workflows. sRGB is a common SDR delivery space. Display P3 extends its red and green coverage. Adobe RGB extends especially into greens and cyans useful in some print workflows. Rec. 2020 has still wider primary chromaticities. ProPhoto is a large working space with imaginary primaries.

With fixed integer precision, a larger gamut generally spreads codes more widely in color. The effect varies across the gamut and depends on the transfer function. Use sufficient precision for editing, then choose the delivery space from the output requirements. A screen cannot display every working-space value merely because software can store it.

fig-lightroom-export-color-space
Figure 4.4.1. The choice, as a photographer meets it. Lightroom's export panel asks for a color space alongside the file format and the JPEG quality, and the menu is the zoo of this chapter: sRGB for the web and for anyone whose screen you cannot know, Display P3 and Adobe RGB when the destination is wider, ProPhoto RGB and Rec. 2020 for editing and for delivery to displays that do not exist yet. Nothing in the pixel values says which one was meant, which is why the choice has to be recorded in the file and why getting it wrong shows up as color that is merely plausible rather than right. Screenshot of Adobe Lightroom Classic.
💡 Big lesson (L4.8) — there is no single RGB: gamut versus bit budget

Choose a working gamut large enough for the content and operations, with sufficient numeric precision. Choose a delivery space the receiving system can interpret. Wider primaries alone do not improve an image, and converting an sRGB image to a wider space does not recover colors previously clipped.

Display-oriented spaces describe a reference set of primaries. Working spaces can instead choose imaginary primaries to enclose more physical colors. ProPhoto’s green and blue are outside the spectral locus; its red is not the imaginary pair’s other member. Such coordinates are useful for calculation, but their nonnegative cube contains values no physical light can produce.

Camera raw is different. Its channels are spectral measurements, often one color sample per photosite in a mosaic, not weights of three emission primaries. A camera would admit an exact universal XYZ matrix if its sensitivities spanned the standard observer’s matching functions. Real cameras generally only approximate this condition, so color correction is fitted and depends on spectra and illumination. It is not meaningful to invert an arbitrary three-by-many sensitivity matrix and call the result three physical display primaries.

Camera profiles can provide multiple illuminant calibrations. Do not assume every DNG contains exactly two matrices at fixed temperatures; use the tags and conventions of the actual profile. Camera color-space menu settings usually govern rendered output and previews, while raw channel interpretation remains camera-specific.

The correction matrix also propagates noise. With equal independent input variances $\sigma^2$, output channel $i$ has variance $\sigma^2\sum_j M_{ij}^2$. More generally use $M\Sigma M^T$. Negative coefficients do not alone prove amplification; their magnitudes and the input covariance matter. The filter design and color fit balance sensitivity, color accuracy, and noise, as developed in Chapter 4.6, Sensing color: multiplexing strategies.

fig-gamut-primaries
Figure 4.4.2. RGB primaries on the chromaticity diagram. The triangle vertices are the red, green, and blue primaries of each space, and the triangle they enclose is that space's gamut. sRGB / Rec. 709 is the small triangle, and Adobe RGB, Rec. 2020 and ProPhoto enclose progressively larger areas: each really does contain the one before it, primary by primary. ProPhoto is the one to look at twice. Two of its three primaries lie outside the spectral locus, so they are not colors at all, and a corner of its triangle names nothing that can be seen. A change of space is a $3\times3$ matrix between these triangles.
fig-gamut-primaries-uniform
Figure 4.4.3. The same RGB gamuts on a perceptually uniform diagram. The identical sRGB, Adobe RGB, BT.2020 and ProPhoto primaries of the previous figure, replotted on the CIE 1976 UCS ($u'v'$) chromaticity diagram, which spaces colors far more evenly by perceived difference. Compared with the $xy$ diagram, the oversized green lobe collapses and the blues open up, so the triangles take on very different shapes and relative areas, from the very same numbers. The lesson: $xy$ (and $XYZ$) measures color, it does not tell you how different two colors look. Rendered by colour-science.
fig-color-spaces-demo
Figure 4.4.4. Chromaticity and color spaces, interactive. Every gamut is drawn at once on the CIE horseshoe, faintly, and one is selected from the row of buttons: that one is drawn in full, carries the draggable handles, and drives everything else. Selecting it also sets the encoding that space is really used with, sRGB, Adobe RGB and Display P3 at $\gamma \approx 2.2$ in 8 bits, Rec. 2020 at 2.4 in 10, ProPhoto at 1.8 in 16; both sliders stay free afterwards. The axes run a little below zero so a primary can be dragged outside the locus, which is where two of ProPhoto's live. A checkbox swaps $xy$ for the perceptually uniform $u'v'$ diagram, and the coverage readout is measured in $u'v'$ either way: sRGB holds 33.3% of the visible chromaticities, Adobe RGB 38.8% (1.17× sRGB), Rec. 2020 57.4% (1.72×), ProPhoto 76.7% (2.30×), and the editable triangle live as you drag it. Below the diagram, what quantization costs in that space. At every code in the space's own cube, step one level along $R$, $G$ and $B$, decode both ends through that space's transfer and that space's primaries, and measure the step as a full CIELAB $\Delta E$, lightness and chroma together and not brightness alone; the histogram is the distribution of those steps, and 1 $\Delta E$ serves as a rough proxy for a just-noticeable difference, which in practice varies with the color and the viewing conditions. Its axis is fixed, $0.001$ to $10\,\Delta E$, so two spaces can be compared by eye rather than by reading the ticks; steps past either end are counted into a bar outside the axis instead of being squeezed in. It answers to all three knobs. Widen the primaries and the same codes have more color to cover: at 8 bits and $\gamma = 2.2$, 0.3% of sRGB's code steps are visible, against 8.0% for Rec. 2020 and 23.3% for ProPhoto, which is exactly why ProPhoto is specified at 16, where it is back to 0.0%. Change $\gamma$ instead, in sRGB at 8 bits, and you get the other half of the story: 6.5% of steps visible at $\gamma = 1$, 0.3% at 2.2, none at 3.0, while the median step grows. Gamma does not remove the error, it levels it. Underneath, the dynamic range those same codes buy, from the dimmest non-black code up to white: 8.0 stops at $\gamma = 1$, which is one stop per bit and no more, against 17.6 at $\gamma = 2.2$ in the same 8 bits, 24.0 for Rec. 2020's 10 bits at 2.4, and 28.8 for ProPhoto's 16 at 1.8. Unlike the histogram, that number is set by the encoding alone and not by the primaries, since every space here puts white at $Y = 1$. Read it as an upper bound: the slider is a pure power, whose slope at zero is infinite, so it reaches further into the dark than a real transfer curve with a linear toe. sRGB's actual piecewise curve gives 11.7 stops at 8 bits, not 17.6. On the right, one sample throughout, a measured reflectance cube rendered under D65, with every pixel the selected space cannot hold flagged. Only 2.4% of these paints leave sRGB, 0.6% leave Display P3 and none leaves Rec. 2020, which is this section's argument in three numbers: real pigments barely need more than the oldest gamut.

This distinction explains two different kinds of color-conversion experiment. Between linear RGB working spaces built from the same standard observer, convert a color to XYZ and then to the destination coordinates; the two matrices compose into one exact coordinate transform. For a camera, photograph a set of known reflectances under a specified light and fit a matrix from the measured camera responses to their target XYZ values. It can fit those samples well and still make errors on other spectra. Two spectra that the camera records identically cannot be separated by any later matrix, even if the standard observer distinguishes them. More training patches improve the fit over a chosen population; they do not restore spectral information absent from the three measurements.

The choice of a working gamut also affects quantization. With a fixed integer bit depth, a wider set of primaries spreads the available code combinations over a larger range of colors. It can retain a saturated color that a smaller space clips, yet give coarser steps in a region shared by both spaces. Increasing bit depth or using floating point reduces that pressure. This is why a space suited to intermediate editing need not be the best choice for compact delivery. The working space must retain the colors the pipeline needs; the output space must match the interpretation supported by the destination.

A caution about that diagram before we read too much into the triangle sizes: the $xy$ chromaticity plane is a space for measuring color, not for judging how different two colors look. It stretches the greens enormously and cramps the blues and purples, so neither the relative areas of these gamuts nor the distances between their primaries track perceived difference. Re-plot the identical primaries on a perceptually more uniform diagram, the CIE 1976 UCS ($u'v'$) space, and every triangle changes shape (Figure 4.4.3): the relative areas and distances change. The newer diagram is more uniform, but it is still not a universal perceptual ruler. That $XYZ$ (and its $xy$ projection) is not perceptually uniform is precisely what will force the deliberately non-linear spaces of Chapter 4.5, Advanced color: opponents, perceptually-uniform, and preferred.

Two design processes can lead to an RGB space. In a display-oriented design, begin with the primaries a reference display can emit, then describe colors as amounts of those lights. In a working-space design, begin with the colors that editing should retain, then choose a coordinate system that encloses them. The latter need not correspond to a manufacturable display. An imaginary primary is acceptable as a coordinate axis because no lamp is being asked to emit it while the image is stored or edited. Physical realizability becomes an output constraint when those values are converted for a screen or printer.

This distinction explains why choosing a larger working space does not upgrade the monitor. It changes which intermediate colors can be represented without clipping to the working cube. Displaying them still requires conversion and, where needed, gamut mapping. Conversely, a delivery space can be chosen for compatibility with the intended viewing path even when a larger space was useful during editing. The export dialog asks for an engineering choice about that destination, not a ranking in which the largest triangle is always best.

The noise formula can be read numerically. A correction row with coefficients 1.8, -0.9, and 0.1 has squared length 4.06. With equal independent input noise, its output standard deviation is therefore about 2.01 times the standard deviation of one input channel. The row may improve the color fit while increasing that channel's noise. This is why a camera characterization should be evaluated for both reconstruction error and noise propagation, using the actual covariance rather than assuming that every color matrix has the same cost.

4.4.1 Two different words for impossible⧉

A chromaticity can be physically realizable yet outside a display’s primary triangle. Conversely, an RGB space with imaginary primaries can encode chromaticities no nonnegative spectrum produces. These are different limitations. Signed floating-point RGB can also represent colors outside its positive-primary triangle, provided subsequent operations preserve the signed values.

fig-encodable-vs-realizable
Figure 4.4.5. Encodable is not realizable. Left and middle, the same two conditions drawn on the CIE 1976 $u'v'$ diagram: the shape is the set of real chromaticities (the convex hull of the spectral locus, closed by the line of purples), the triangle is what the space can write with non-negative coordinates, and the two hatchings are the two ways a color can be impossible. sRGB's triangle lies entirely inside the locus, so it has no imaginary codes at all and misses two thirds of the visible. ProPhoto's green and blue primaries sit outside the locus, so part of its triangle is hatched the other way: code space that no spectrum can reach. Right, the same thing as a Venn diagram, with the circles sized and spaced to match the measured areas: 23% of the visible world ProPhoto cannot write, 77% both, and a further 10% of that area encodable but not a color. Against ProPhoto's own code space, 12% of it is imaginary.

A chromaticity triangle omits luminance. Even a chromaticity inside the triangle may require more light than a display can emit at the requested luminance. Similarly, reflectance is bounded by one: under fixed broadband illumination, pushing a surface color toward a spectral endpoint usually restricts the wavelengths it reflects and reduces its possible luminance. This helps explain the shape of the object-color solid, but does not imply that ordinary pigments always fit sRGB. Saturated flowers, paints, fabrics, structural colors, and colored lights can require gamut mapping.

fig-optimal-reflectance
Figure 4.4.6. The brightest reflectance that can make a given color, interactive. Pick a chromaticity on the CIE $xy$ diagram; of all reflectances with values in $[0,1]$ that produce it under an equal-energy light, the one that reflects the most power is a Schrödinger optimal color (Schrödinger 1920 (optimal colors)), a reflectance that is 1 on a band of wavelengths and 0 elsewhere (or its complement). The panels show that optimal reflectance spectrum, its L/M/S cone response, its average albedo (the unweighted mean reflectance, not luminance), and its RGB rendition, all normalized so a flat spectrum ($R=1$ everywhere) renders white. That rendition is gamut-mapped, and it has to be: most of the horseshoe is outside anything your screen can emit. The swatch is slid along a straight line toward the neutral of the same luminance until it just fits, which keeps the linear-sRGB luminance and spends saturation instead, though it does not guarantee that perceived hue and lightness stay constant; switch the mapping off and each channel is clipped on its own, which moves the hue as well, the reason a clipped sunset comes out the wrong color. With show where it lands on, the diagram plots the chromaticity you are actually being shown next to the one you asked for, joined by the walk between them. The gamut picker draws any of five real RGB spaces, or all five at once so the overlaps are plain: sRGB inside both Display P3 and Adobe RGB, which overlap without either containing the other (P3 reaches further into the reds, Adobe RGB into the greens), Rec. 2020 wider still, and ProPhoto reaching outside the horseshoe altogether, into primaries no light can make. The figure searches band-pass and band-stop reflectances sampled every 5 nm from 390 to 700 nm and snaps to the nearest candidate in $xy$, so it illustrates the family of optimal colors rather than computing the exact maximum at the point you pick. Near the white point the band is wide and the surface is bright; out near the spectral locus it collapses to one wavelength, monochromatic and very dark. That saturation-versus-brightness trade is why bright, saturated surfaces are physically rare, and why a modest display gamut copes as well as it does.

The RGB cube shows the bounded encoding in three dimensions. Its geometry depends on whether its coordinates are linear or nonlinear; its Euclidean distances are not perceptual color differences.

fig-rgb-cube
Figure 4.4.7. The RGB cube. The three channels are orthogonal axes; black is at the origin $(0,0,0)$, white at $(1,1,1)$, the primaries and their pairwise sums (cyan, magenta, yellow) at the other corners, and the neutral gray axis is the cube's main diagonal. Saturation is distance from that diagonal. The cube is the geometric picture behind every RGB manipulation.

The optimal-reflectance experiment makes the brightness constraint concrete. Under a fixed broadband light, an ideal white reflector returns light across the whole spectrum. Restricting reflection to a narrow wavelength interval rejects the power outside that interval. The resulting chromaticity can be very saturated while the available reflected luminance becomes small. An emitter need not pay this same price: it can put substantial power directly into a narrow band. This is a reason to distinguish surface-color limits from the gamut of colored lights. It does not imply that all colors outside sRGB are nearly monochromatic or that saturated ordinary materials can be ignored.

4.4.2 Reference: primaries, matrices, and transfer functions⧉

Each space named above is fixed by two things: its primaries and white point, which set the linear RGB-to-XYZ matrix, and its transfer function, the gamma curve that encodes the linear values for storage. The matrices below carry linear light, no diacritic, into $\mathrm{XYZ}$; the transfer is applied afterward to get the stored $R'G'B'$ (the primes of Chapter 4.3, Encoding: linear, gamma or log). The middle row of each matrix is that space's luminance $Y$ weighting, the coefficients also used, with the specified nonlinear encoding, to define a corresponding luma (L4.5).

sRGB and Rec. 709 primaries (D65) share this linear matrix, though their transfer conventions differ:

$$ M_{\text{sRGB}} : \mathrm{RGB}_{[\text{D65}]} \to \mathrm{XYZ} = \begin{pmatrix} 0.4124 & 0.3576 & 0.1805 \\ 0.2126 & 0.7152 & 0.0722 \\ 0.0193 & 0.1192 & 0.9505 \end{pmatrix} $$

sRGB transfer: piecewise, a linear segment $R' = 12.92\,R$ for $R \le 0.0031308$ splicing into $R' = 1.055\,R^{1/2.4} - 0.055$, overall close to $\gamma = 2.2$.

Adobe RGB (1998) (D65), wider greens for print work:

$$ M_{\text{Adobe}} = \begin{pmatrix} 0.5767 & 0.1856 & 0.1882 \\ 0.2974 & 0.6274 & 0.0753 \\ 0.0270 & 0.0707 & 0.9911 \end{pmatrix} $$

Transfer: a pure power law, $\gamma = 2.19921875$ (that is $563/256$).

Display P3 (D65), the DCI-P3 primaries on the sRGB white:

$$ M_{\text{P3}} = \begin{pmatrix} 0.4866 & 0.2657 & 0.1982 \\ 0.2290 & 0.6917 & 0.0793 \\ 0.0000 & 0.0451 & 1.0439 \end{pmatrix} $$

Transfer: the sRGB piecewise curve.

ITU-R BT.2020 / Rec. 2020 (D65), ultra-high-definition with very wide primaries (its red is a near-monochromatic 630 nm):

$$ M_{\text{2020}} = \begin{pmatrix} 0.6370 & 0.1446 & 0.1689 \\ 0.2627 & 0.6780 & 0.0593 \\ 0.0000 & 0.0281 & 1.0610 \end{pmatrix} $$

Transfer: BT.2020 specifies a camera-side piecewise encoding with a 0.45-power segment and linear toe. Specify the display response separately. Rec. 2100 uses the same primary chromaticities with PQ or HLG HDR systems (Chapter 4.3, Encoding: linear, gamma or log).

ProPhoto RGB (ROMM) (white point D50), a large editing space with imaginary green and blue primaries:

$$ M_{\text{ProPhoto}} : \mathrm{RGB}_{[\text{D50}]} \to \mathrm{XYZ} = \begin{pmatrix} 0.7977 & 0.1352 & 0.0313 \\ 0.2880 & 0.7119 & 0.0001 \\ 0.0000 & 0.0000 & 0.8249 \end{pmatrix} $$

Transfer: $\gamma = 1.8$, with a short linear segment (slope $16$) below $R = 1/512$.

Two reminders the type system enforces. The matrices are all defined on linear light, so a conversion between two of these spaces is $M_2^{-1} M_1$ applied to linear RGB, never to the stored $R'G'B'$: decode first. And the white points are not all the same (ProPhoto is D50, the rest D65), so a white-relative ProPhoto-to-sRGB conversion includes chromatic adaptation (often Bradford, Chapter 4.2, White balance and white point) between the XYZ stages. A stimulus-preserving conversion has a different objective and does not silently adapt the white.

For a white-relative conversion, the full order is

linear_source = decode_source(encoded_source)
XYZ_source = M_source @ linear_source
XYZ_target = adapt_white(XYZ_source, source_white, target_white)
linear_target = solve(M_target, XYZ_target)
# Retain extended range while working; map gamut for the chosen output.
encoded_target = encode_target(mapped_linear_target)

The printed matrices are rounded reference values. Use a consistent precision and white normalization in code. Verify that RGB white maps to the stated XYZ white and that an unmodified in-gamut round trip returns its input.

Recap: big lessons of this chapter

💡 Big lesson (L4.8) — there is no single RGB: gamut versus bit budget

Choose a working gamut large enough for the content and operations, with sufficient numeric precision. Choose a delivery space the receiving system can interpret. Wider primaries alone do not improve an image, and converting an sRGB image to a wider space does not recover colors previously clipped.