## Chromaticity, Gamut, and the Scary World of Imaginary Colors

### Introduction

In the previous tutorial, we built a color space by specifying the primary lights and the reference white. The significance of a color space is that it allows us to precisely describe a color as three values (e.g., RGB). However, the RGB values are not quite intuitive to human. For instance, if increase R by 20, G by 30, and decrease B by 24, how is the color changed? Will it become brighter? Will it look like a different color? To answer these questions, we want to decouple the inherent attribute of a color from its intensity, which gives rise to the notion of *chromaticity*. This is one of the core underlying ideas behind many perceptual color spaces such as HSV/HSB/HSL, Munsell Color System, and CIELAB (although they use different mathematical formulations than what's presented here).

The notion of chromaticity is inherent to color, so it exists in any color space. We will focus ourselves on RGB-like color spaces. The idea we describe here will help you understand other color spaces such as HSV and CIELAB. Better yet, using RGB chromaticity we can gain lots of intuitions about the fundamental attributes of color, color space, and human color perception. This tutorial first introduces the idea of chromaticity, discusses how chromaticity could be derived from a RGB space, and explores some important uses of chromaticity.

### Step 0: Picking a Color Space

To be concrete, you will need a specific RGB color space for this tutorial. We invite you to build your own and use it to drive the rest of the tutorial. We know that a color space is uniquely defined by its primaries and the reference white. For simplicity, we will assume CIE Standard Illuminant E (Equal-Energy White) as the reference white, and provide you five ways to pick the primaries.

**Spectral Primaries:**

- : spectral lights $445~nm$, $540~nm$, and $590~nm$. This will build a color space that allows us to have an intuitive geometric interpretation of color space.
- : spectral lights $415~nm$, $500~nm$, and $540~nm$. Use this option if you want to explore a counter-intuitive color space (see Step 2.4).
- . This will allow you to select three spectral lights as the primaries, exactly like what you did in the previous tutorial.

**Non-Spectral primaries:**

- : primaries are physically-unrealizable lights, each exclusively stimulating only the L, M, and S cone, respectively. This constructs the LMS color space.
- . You can draw the spectral power distribution (SPD) of the primaries in the right chart below. You can to start over.

Once the primaries are picked, we can , which will affect the rest of the tutorial. If you want to use a different color space, simply make the change and click the button again. The color space is built, under the hood, by calculating the Color Matching Functions (CMFs) using the method we explored in the previous tutorial.

### Step 1: Decoupling Quality (Chromaticity) and Quantity (Brightness)

The plot below is the spectral locus in your RGB space. Hover over any point on the locus to reveal the coordinates of the corresponding spectral light. Recall what the coordinates (of any point) mean: they represent the amount of primaries needed to match the color of that spectral light.

Now toggle the "Show Equi-Ratio Lines" switch. You will see a set of lines, each of which starts from the origin and goes through a spectral light. By simple geometry, we know that points on a line, while requiring different absolute amounts of RGB primaries (different coordinates in the RGB space), all have the same R:G:B ratio. This conclusion generalizes too any line, not just the lines that go through the locus.

How do a color that's mixed from 1:2:4 units of RGB primaries and a color that's mixed from a 2:4:8 units of the primaries relate? Recall from the previous tutorial that the amount of a primary is directly proportional to the power of that primary. So the second color can be obtained by doubling the power of each primary in the first color; similarly, halving the power of each primary in the second color gets us the first color. Intuitively, lights that have the same primary quantity ratio are said to have the same "objective color quality" while differing in the intensity.

Show the equi-rgb-ratio lines. All the points along the same line have the same R:G:B ratio.

Show the chromacitities of the spectral lights.

The chromaticities of all colors lie on this plane.

Project the 3D plot to the r-g plane.

More formally, we can calculate the primary ratio $r:g:b$ of a color and then normalize the ratio such that $r+g+b = 1$ (100%). The so-calculated $r, g, b$ values of a color are called the (RGB) **chromaticity** values of that color. Mathematically, the chromaticity of a color are calculated from its absolute quantity by:

$r = \frac{R}{R+G+B},~~~g = \frac{G}{R+G+B},~~~b = \frac{B}{R+G+B}$.

Each color now has an rgb triplet, representing the color's chromaticity. Similar to how we represent colors in the RGB space, we can also plot the colors using their chromaticities. Toggle the "Show Locus in Chromaticity" switch to reveal the spectral locus in chromaticity. Hover over a chromaticity point and the corresponding RGB point on the same line; check the primary ratio in the tooltips and you can see that the primary ratio doesn't change when you plot a color using its chromacitity.

**Why Chromaticity?** Knowing the chromaticity of a color tells us the **inherent attribute** of the color, and we can make that color brighter or darker by increasing or decreasing the amount of the primaries *while keeping the chromaticity constant*. In many practical color applications such as color photography and digital displays, chromaticities of a color is what we strive to capture (in the case of photography) or reproduce (in the case of display), and we are almost never be able to capture/reproduce the exact intensity of light in the scene (think about the power of the sun!).

**Chromaticity Diagram.** Spin around the plot. Notice how all the spectral lights are now on the same plane. That's the natural implication of how chromaticities are defined: since we enforce $R+G+B=1$, all colors' chromaticities naturally lie on the $R+G+B=1$ plane. Toggle the "Show R+G+B=1 Plane" switch to convince yourself of that. If we were to define chromaticity such that $R+G+B=1.5$, all the colors will then lie on that plane. One way to think of chromaticities is that we shoot rays from the origin to go through all the spectral lights, and then intersect all those lines using the $R+G+B=1$ plane. Geometrically, this is equivalent to a perspective projection of the RGB colors onto the $R+G+B=1$ plane with the origin as the point of projection.

Since the chromaticities of all colors lie on one plane, we can represent them in a 2D plot. The convention is to project the $R+G+B=1$ plane onto the r-g plane, and the resulting plot is called the *rg-chromaciticy plot*. You should try to spin the 3D plot around to project yourself, and you can also toggle the "Project" switch, which does the projection for you.

**Chromaticity in Other Color Spaces. **This way of calculating chromaticity applies to any RGB color space (or any color space that's a linear transformation away from it, e.g., CIE XYZ, LMS). In some sense, color chromaticity is implicit in these color spaces. There are other color spaces where chromaticity is an explicit part of how a color is described. For instance, HSV/HSB/HSL color spaces describe a color using three numbers: hue, saturation, and value (brightness, lightness). Hue and saturation are two explicit descriptions of a color's chromaticity and have intuition interpretations than r, g, or b. CIELAB provides a perceptually more uniform way of describing chromaticity.

### Step 2: Color Gamut

What are all the colors that human can see? Is there a color space that can produce all the colors that human can see? To answer these questions, one could construct every single real light one by one and find its color. While we can't really do that in practice, constructing a few lights that way would help us build the intuitions. These intuitions turn out to be really easy to explain in the chromaticity diagram.

If spectral lights are all above or all below this plane (e.g., if you use Preset 1), the HVS gamut in chromaticity is bounded by the convex hull of the spectral colors.

Show the human visible gamut in chromaticity. Enabled only if all spectral colors are above or below the R+G+B=0 plane at the same time. Otherwise the HVS gamut in chromaticity is unbounded and hard to visualize.

Show partial boundary of human visible gamut in the RGB space. The real gamut extends to infinity as one increases the light power. Any point inside the boundary is a real color.

#### 2.1 Building the Intuition

**Mixing Two Lights.**
We could think of the SPD of a light as the "recipe" of making that light — by mixing different amount of spectral lights specified in the SPD. Let's start by mixing two lights and see what happens to the resulting color. If you toggle the "Pick 2 Colors" switch, you can click 2 arbitrary points $\mathbf{A}$ and $\mathbf{B}$ along the RGB locus. What you will get is a line segmentation $\overline{\mathbf{AB}}$. Any point on $\overline{\mathbf{AB}}$ represents a color producible by mixing some portion of colors $\mathbf{A}$ and $\mathbf{B}$.

Assuming that the two (spectral) lights you picked have a spectrum of $\Phi_1$ and $\Phi_2$, respectively, and their RGB triplets are $[R_1, G_1, B_1]$ and $[R_2, G_2, B_2]$, respectively. From simple convex geometry, we know that any point $\mathbf{T}$ on the line segment between the two points can be expressed as $[R_t, G_t, B_t] = \alpha[R_1, G_1, B_1] + (1-\alpha)[R_2, G_2, B_2], \alpha \in [0, 1]$. We will show that $[R_t, G_t, B_t]$ is a color that can be produced by mixing two lights: $\alpha\Phi_1$ and $(1-\alpha)\Phi_1$. Note that nothing in the proof below relies on $\Phi_1$ and $\Phi_2$ being spectral, and so the conclusion applies to any lights (and two points in the RGB space).

Based on how RGB triplets are calculated from the CMFs ($\bar{r(\lambda)}, \bar{g(\lambda)}, \bar{b(\lambda)}$), we have:

$R_1 = \sum_{\lambda} \Phi_1(\lambda) \bar{r}(\lambda), G_1 = \sum_{\lambda} \Phi_1(\lambda) \bar{r}(\lambda), B_1 = \sum_{\lambda} \Phi_1(\lambda) \bar{r}(\lambda)\\$ $R_2 = \sum_{\lambda} \Phi_2(\lambda) \bar{r}(\lambda), G_2 = \sum_{\lambda} \Phi_2(\lambda) \bar{r}(\lambda), B_2 = \sum_{\lambda} \Phi_2(\lambda) \bar{r}(\lambda)$

The RGB triplet of the new light mixed from $\alpha\Phi_1$ and $(1-\alpha)\Phi_1$ is:

$\sum_{\lambda} [\alpha\Phi_1(\lambda) + (1-\alpha)\Phi_2(\lambda)] \bar{r}(\lambda) = \alpha\sum_{\lambda} \Phi_1(\lambda)\bar{r}(\lambda) + (1-\alpha)\sum_{\lambda} \Phi_2(\lambda)\bar{r}(\lambda) = \alpha R_1 + (1-\alpha) R_2 = R_t\\$ $\sum_{\lambda} [\alpha\Phi_1(\lambda) + (1-\alpha)\Phi_2(\lambda)] \bar{g}(\lambda) = \alpha\sum_{\lambda} \Phi_1(\lambda)\bar{g}(\lambda) + (1-\alpha)\sum_{\lambda} \Phi_2(\lambda)\bar{g}(\lambda) = \alpha G_1 + (1-\alpha) G_2 = G_t\\$ $\sum_{\lambda} [\alpha\Phi_1(\lambda) + (1-\alpha)\Phi_2(\lambda)] \bar{b}(\lambda) = \alpha\sum_{\lambda} \Phi_1(\lambda)\bar{b}(\lambda) + (1-\alpha)\sum_{\lambda} \Phi_2(\lambda)\bar{b}(\lambda) = \alpha B_1 + (1-\alpha) B_2 = B_t$

Q.E.D.

How does the mixed color look like in chromaticity? The line segment $\overline{\mathbf{AB}}$ in the RGB space is mapped to a line segment $\overline{\mathbf{ab}}$ in the chromaticity plane. $\overline{\mathbf{ab}}$ connects two points $\mathbf{a}$ and $\mathbf{b}$, which represent the chromaticity of the spectral colors $\mathbf{A}$ and $\mathbf{B}$, respectively. Meanwhile, a point $\mathbf{T}$ on $\overline{\mathbf{AB}}$ gets mapped to a point $\mathbf{t}$ on the chromaticity plane. $\mathbf{t}$ represents the chromaticity of color $\mathbf{T}$. Where is $\mathbf{t}$? $\mathbf{t}$ will be within $\overline{\mathbf{ab}}$ if $\overrightarrow{\rm \mathbf{OA}}$ and $\overrightarrow{\rm \mathbf{OB}}$ intersect the $R+G+B=1$ plane either both positively or both negatively ($\mathbf{O}$ is the origin). Informally, this requires that $\mathbf{A}$ and $\mathbf{B}$ are both below or both above the $R+G+B=0$ plane. Toggle the "Show R+G+B=0 Plane" and spin the plot to convince yourself.

*all the spectral colors are all above or all below the $R+G+B=0$ plane*, there exists a very powerful interpretation of the chromaticity diagram: connect any two points $\mathbf{a}$ and $\mathbf{b}$ in the chromaticity diagram and form a line segment $\overline{\mathbf{ab}}$, points on $\overline{\mathbf{ab}}$ represent the

*chromaticities*of all the colors that can be produced by mixing two colors whose chromaticities are $\mathbf{a}$ and $\mathbf{b}$, respectively.

Visualizations of the spectral locus you can find on the Internet usually in a color space where the primaries are carefully picked such that the condition above is met. The CIE XYZ color space and the LMS cone space meet this condition, too. The primary choice in Preset 1 is one such example. We will assume such a color space for now. In Step 2.4, we will explain what happens when you build a color space that does not meet the above condition.

**Mixing Three Lights.** The same intuition applies to three colors. Toggle the "Pick 3 Colors" switch, and pick three colors on the RGB spectral locus, which will form a triangle. Any point on that triangle represents a color that is produced from mixing the three chosen spectral lights. That triangle is mapped to another triangle in the chromaticity diagram. In general, if you pick three colors $\mathbf{a}$, $\mathbf{b}$, and $\mathbf{c}$ in the chromaticity diagram, the triangle $\triangle \mathbf{abc}$ contains the chromaticities of all the colors that can be produced from three lights whose chromaticities are $\mathbf{a}$, $\mathbf{b}$, and $\mathbf{c}$, respectively.

**Mixing Four Lights. **Let's try one more. Toggle the "Pick 4 Colors" switch and pick four colors on the RGB spectral locus. What you get is a tetrahedron. Any point within that tetrahedron represents a color that is produced from mixing the four chosen spectral lights. That tetrahedron is mapped to a quadrilateral in the chromaticity diagram. In general, if you pick four colors $\mathbf{a}$, $\mathbf{b}$, $\mathbf{c}$, and $\mathbf{d}$ in the chromaticity diagram, the quadrilateral $\square \mathbf{abcd}$ contains the chromaticities of all the colors that can be produced from four lights whose chromaticities are $\mathbf{a}$, $\mathbf{b}$, $\mathbf{c}$, and $\mathbf{d}$, respectively.

#### 2.2 Color Perception Limit of Human Visual System (HVS)

**Generalization.** We can keep playing this game. If a light is made of five spectral lights, its chromaticity will fall in the pentagon formed by the five lights; if a light is made of six spectral lights, its chromaticity will fall in the hexagon formed by the six spectral lights. Essentially, given a light's SPD $\Phi$, we can find its constituting spectral lights, which form a polygon in the chromaticity diagram. The chromaticity of $\Phi$ falls in the polygon.

If we exhaust all combinations of all wavelengths in the visible spectrum, we will have found all possible colors, which we call the **gamut of human color vision**. What's the geometric structure of the gamut? Generalizing the intuition we have built so far, it's not difficult to see that the chromaticities of all colors must reside in the convex hull of the spectral locus in the chromaticity diagram. Click the button "Show HVS gamut in Chromaticity" to reveal it. If you choose the Preset 1 primaries, it happens to be the case that the spectral locus itself is a convex set, in which case the gamut is simply the area under the locus.

**Gamut is a 3D Concept.** Visualizing the gamut of human color vision in chromaticity is nice, but the actual HVS gamut lives in the RGB space and so is a 3D concept. How does HVS gamut look like in RGB? We can't possible visualize it, because you can just keep increasing the power of a light and get infinite amount of colors — ignore the fact that high-intensity lights destroy retinas for a moment. But we can get a sneak peak of the *bounds* of HVS gamut in the RGB space. Toggle the "Show HVS Gamut Boundary in RGB" switch. It will show the boundary of the gamut in the RGB space. The boundary here is plotted using the canonical method that cycles through continuous equal-peak-energy stimuli. Play with this interactive app to see how the gamut boundary is formed. The actual boundary grows forever by scaling what's plotted. Any point within the boundary is a real color, i.e., a part of the human visual gamut.

#### 2.3 Gamut of a Color Space

Many lights that enter our eyes are not natural lights, but lights from various light-generating devices such as smartphones, computers, and printed paper. Each output device has its own color space, such as sRGB, CMYK, and DCI-P3. All the colors that can be produced by a color space is called the **gamut of the color space**. Is there a color space that can produce all the colors?

The answer is no, and we can have a very intuitive explanation. Look at the chromaticity diagram of the color space built using the Preset 1 primaries. No matter what colors and how many colors you choose as primaries to build a color space, the primaries of any color space must reside inside the spectral locus, and all the colors that are producible from that color space must be inside the polygon formed by the primaries. Since the spectral locus is convex, the polygon is guaranteed to be enclosed by the locus. Therefore, the gamut of any color space is guaranteed to be a subset of the color gamut of HVS. In addition, since the polygon is always enclosed by the locus, it's impossible to find a polygon that includes all the spectral colors. That is, no color space can produce all spectral colors.

These conclusions, however, apply only to color spaces whose primaries are real colors. If a color space, such as CIE XYZ, LMS, and ProPhoto RGB, uses imaginary primaries, its color gamut could include imaginary colors and thus is not a subset of HVS gamut. The color gamut of CIE XYZ completely covers the entire HVS gamut (and by extension all the spectral colors). We will explore imaginary colors in more details in Step 4.

#### 2.4 Visualizing a Counter-Intuitive Color Space

The primaries in Preset 1 lead to a color space where the spectral colors are all above the $R+G+B=0$ plane. However, that condition is not always met for any arbitrary choice of primaries. Preset 2 is a counter-example. Select that preset and compare the RGB locus points with the $R+G+B=0$ plane. Then pick two colors $\mathbf{A}$ and $\mathbf{B}$, one above and the other below the $R+G+B=0$ plane. You will see that a point on $\overline{\mathbf{AB}}$ won't be mapped to a point on $\overline{\mathbf{ab}}$ after being projected through the origin. We have cooked an example for you. Click "Unusual Example" to see it. In general, when the spectral colors are separated by the $R+G+B=0$ plane, the HVS gamut extends to infinity in the chromaticity , which becomes hard to visualize. Under that circumstance, we disable the "Show HVS Gamut in Chromaticity" button.

Also try showing the locus in chromaticity; see how weird that locus becomes. This could initially seem odd; how could a nice smooth curve in RGB become so entangled in the rgb space? The reason is that the transformation from RGB to rgb isn't linear (or affine for that matter); it's a perspective transformation.

Nothing is wrong with a color space where spectral colors are separate by the $R+G+B=0$ plane. It just means we can't use the chromaticity diagram to easily reason about the effect of mixing colors in that color space. For instance, we can't say the HVS gamut in such a color space is the area under the convex hull of the locus. In addition, since the spectral colors do not form a convex set anymore, it's possible to pick three spectral colors such that the resulting triangle in chromaticity contains other spectral colors. It doesn't mean all of a sudden we can build a RGB color space that can produce spectral colors. We didn't (and couldn't) change the fundamental, inherent properties of color, which hold regardless in which color space we represent colors. However, it does mean that the intuitive interpretations of the chromaticity diagram we developed above don't apply to these "usual" color spaces.

### Step 3: Physically-Unrealizable Lights and Imaginary Colors

From the visualization above, we can see that the HVS gamut occupies a subset of the entire RGB space. A natural question then is: what about those RGB points that are outside the HVS gamut? What exactly are they? Can we generate colors at those points? It turns out that we can mathematically construct "imaginary colors" whose RGB triplets are outside the HVS gamut — from physically-unrealizable lights.

**Physically-Realizable Lights.** Lights whose SPDs are non-negative everywhere are physically-realizable. We can, in theory, generate such lights by collecting photons at different wavelengths as specified by the SPD. The RGB triplet of a physically-realizable light corresponds to a real color. As discussed above, a real color is a part of the gamut of human color perception; in the chromaticity diagram, a real color falls within the area under the locus if the locus is convex, which is the case if you use Preset 1.

Since photons always have positive energy, a "light" would be physically-unrealizable if its SPD is negative at certain wavelengths. Mathematically, however, nothing prevents us from calculating the RGB triplet of a physically-unrealizable light using the CMFs of a color space. An RGB point would not represent a real color if the RGB triplet can not be produced from *any* physically-realizable light. We call such a color an *imaginary color*.

**The Math of Imaginary Colors.** Given an RGB color space, can you find all the imaginary colors, those that can never be generated from real lights? Intuitively, any point outside the gamut is an imaginary color, but let's reason about this a bit more rigorously. Mathematically stated, given an RGB point $[R_t, G_t, B_t]$ in a color space whose CMFs are $\bar{r}(\lambda), \bar{g}(\lambda), \bar{b}(\lambda)$, we want to know whether the following *constrained* system of equations have a solution:

$ \begin{bmatrix} R_t \\ G_t \\ B_t \end{bmatrix} = \begin{bmatrix} \bar{r}(380) & \cdots \bar{r}(500) & \cdots & \bar{r}(780) \\ \bar{g}(380) & \cdots \bar{g}(500) & \cdots & \bar{g}(780) \\ \bar{b}(380) & \cdots \bar{b}(500) & \cdots & \bar{b}(780) \end{bmatrix} \times \begin{bmatrix} \Phi(380) \\ \cdots \\ \Phi(500) \\ \cdots \\ \Phi(780) \end{bmatrix} $, $\Phi(\lambda) \ge 0 ~~ \forall \lambda \in [380, 780] $, where $\Phi(\lambda)$ is the SPD to be solved for.

If not, $[R_t, G_t, B_t]$ is an imaginary color. Without the constraint that the SPD is non-negative at every wavelength, this system of equations is under-determined and so has infinitely many solutions. But with the constraint, it's possible that there's no solution.

**Finding Imaginary Colors.** You can verify this for yourself. Look at the gamut on the right and use your intuition to identify a point that you believe should be an imaginary color. Then put the RGB coordinates of that point in the input boxes below, and hit the "Find SPD" button. One of two things will happen.

- If the color is a real color (think harder!), there are many spectra that could have led to that particular RGB triplet; we just plot one such spectrum. You will see that the RGB point falls within the gamut and the chromaticity is within the convex hull of the spectral locus.
- If the color is indeed an imaginary color (great job!), there isn't a real light that could lead to that RGB point, but a physically-unrealizable light could. To convince yourself of this, click the "Find an Unreal Light" button. A light that mathematically gives the target RGB triplet but with negative SPD values is plotted. You will also see that the RGB triplet is outside the gamut and the chromaticity is outside the convex hull of the locus.

You are invited to change the color space, and see how a RGB point that represents a real color in one color space will represent an imaginary color in another color space.

**LMS is a Color Space with Imaginary Primaries.** Since a color can be represented as a LMS triplet, we can think of LMS as a color space, too. The CMFs of the LMS space are the cone sensitivity functions. What are the primary lights of the LMS color space? By definition, the primaries of a color space sit on the axes. Therefore, each LMS primary should stimulate exclusively only one cone type. What should these colors look like? Pick Preset 3 in Step 0, which will calculate three lights that exclusively stimulate only one cone type each (there are infinitely many such lights; we plot the ones that generate equal LMS responses at unity). See how they all have negative portion in the SPDs. That is, primaries of the LMS space are physically-unrealizable lights.

Now you can plot the locus in the LMS space. Note how all the spectral colors are in the positive octane of the LMS space, meaning any real color can be expressed as a positive combination of the LMS primaries. That means LMS *is* a color space whose gamut includes the HVS gamut. However, any point on the axes is out of the HVS gamut, showing that the LMS primaries are imaginary colors. This also shows that not all positive LMS combinations can be generated by a physically-realizable light. Note that invisible (but physically realizable) lights such as IR or UV lie on the origin of the LMS space.

**Real and Unreal Lights Could Generate the "Same Color".** Interestingly but perhaps unsurprisingly, it is possible that a real light and an unreal light are mapped to the same RGB point. This is because the system of equations above is under-determined. It could have two solutions, one meets the non-negative constraints and the other does not. That is, a real light can be a metamer of an unreal light, mathematically!

To verify that, click the "Draw Light" switch above and draw an SPD. Then click "Calculate color", which will show you whether that SPD corresponds to a real color or an imaginary color. Try intentionally giving some negative power to a light to see if you can generate a real color.