Published March 10, 2015 by Scott Allen Burns; last updated May 28, 2021
4/29/15 Separated portion on generating reflectance curves into a separate publication.
9/19/17 Updated symbols to reflect common colormetric usage: instead of , instead of , instead of , instead of .
9/26/18 Added link to a fast reflectance reconstruction method.
10/2/18 Changed matrix to be called to reflect established terminology.
10/2/18 Added link to applying the optimization methods to Rec. 2020 color space.
2/15/20 Added note about WGM mixing and possible gamut violations.
5/28/21 Divided long web page into a series of smaller ones for faster loading.
5/28/21 Added notice of new LHTSS method that performs better than ILLSS.
I present an algorithm for computationally mixing screen colors (RGB colors) subtractively, written for a general audience. The question it addresses is, “Given two colors specified by their RGB triplets, what RGB triplet should be used to represent the color that would arise if the two colors were mixed like paint colors, i.e., mixed subtractively?” The only way I can think of doing this in a rigorous way is to employ the math behind how a stimulus (a continuous spectral power distribution) enters our eyes and is transformed into a three-dimensional color sensation by our brain. Once this process has been adequately modeled, subtractive color mixture follows directly. The approach I present here is to convert the RGB colors to spectral reflectance curves, mix the curves using the weighted geometric mean, and then convert the result back to RGB.
The algorithm described here provides a representative model for subtractive color mixture. The way actual paints mix, for example, is highly dependent upon the particular pigments being used, as well as many other factors. Be aware that you can mix a blue and a yellow paint to get green in one case, and then mix another blue (that appears IDENTICAL to the first blue and has the same RGB value) and another yellow (appearing IDENTICAL to the first yellow, with the same RGB value) and get brown or some other color as a result! There is no way to differentiate between these two different outcomes based on the RGB values of the source colors. Consequently, the colors calculated by my algorithm are plausible, generic, representative color mixture outcomes, and certainly are not predictive of any one specific paint chemistry. Some of the factors that contribute to the unpredictability of paint mixture, not represented by the RGB description of the source colors, include:
- The varying degree to which light is reflected directly off the top layer of grains of pigment and mix additively in our head.
- The “glazing” effect that comes from the ordering of layers of transparent paints, giving different results according to the order of application.
- The shift in hue that results from mixing a color with white paint due to the “undertones” of pigments.
- The difference in how transparent paints mix compared to opaque paints, due to the additional scattering possible within transparent paint layers.
- The fact that two visually identical pigments can have very different spectral reflective properties, strongly impacting how they mix with other colors.
- The difference in pigment grain sizes, which affect how they respond to tinting and shading actions.
With that said, I believe the algorithm I describe here will give very plausible results in computer graphics applications intended to mimic realistic paint mixture.
Introduction to RGB Color
The colors we see on our TVs, computers, and phones, if we look closely enough, are produced by an array of tiny red, green, and blue dots. By varying the relative brightness of these three colors, we can produce a wide range of other colors through “additive” color mixture. We describe these colors using three numbers, the brightness of the R, G, and B dots, typically with whole numbers in the range 0-255, such as (R,G,B)=(217,15,145). This is how a program like Photoshop describes its RGB colors. In other settings, the RGB values are treated as floating point numbers the range 0.0 to 1.0, like (RGB)=(0.7263, 0.0112, 0.8956). Programs like Matlab use this convention.
The RGB “color space” is a three-dimensional space spanned by the R, G, and B axes. A point within this space represents a unique color. The origin, RGB=(0,0,0), represents black (or the darkest color the screen can produce, which is typically quite far from true black). The color RGB=(1.0,1.0,1.0) represents the color produced when R, G, and B are at their brightest, and is usually called white. There are many different RGB color spaces, differing in what specific red, green, and blue lights are used for the primaries, and what specific color it considers to be white, called the “reference white.” This document will focus on one specific space called the sRGB color space, which is commonly used with RGB display devices. It has a very specific definition that aims to make color images appear consistent across a wide variety of computer screen types.
Additive vs Subtractive Mixture
When we overlap the beams of two colored flashlights on a white wall, they mix additively. When we mix two paints of different colors, they mix subtractively. The rules for color mixing are very different in the two cases. Mixing blue and yellow paint, for example, usually gives some sort of green. But mixing blue and yellow light will typically give white or a neutral gray. Mixing red and green paint usually gives a muddy color, but with light, the combination is yellow.
There are computer graphics applications where a programmer needs to mimic subtractive color mixture. An obvious example is a program that teaches how to mix paints, such as this one. But other applications, like painting programs and photo-realistic scene generation can benefit from being able to model subtractive color mixture. Yet, finding an algorithm for realistically mixing colors this way is surprisingly difficult.
Why is This a Problem?
Here are the RGB values for some basic colors:
- cyan=(0,1,1) .
Cyan, magenta, and yellow are often used as subtractive “primaries.” Note how well the math works when we multiply the RGB values together when mixing them:
- cyan=(0,1,1) times magenta=(1,0,1) is blue=(0,0,1)
- magenta=(1,0,1) times yellow=(1,1,0) is red=(1,0,0)
- cyan=(0,1,1) times yellow=(1,1,0) is green=(0,1,0)
This is just what we would expect from a subtractive mix of these colors. Unfortunately, the multiplicative mixture model breaks down pretty quickly for other pairs of colors. Mixing red and yellow, for example, just gives red as the multiplicative result, not orange as we would expect. Even worse, it appears that mixing white with any other color has no effect at all! There is no way to produce a tint of a color in this mixing model.
Others have suggested converting the RGB to other color spaces, such as L*a*b* color space (a “perceptually uniform” color space), CMYK color space, or HSV color space, before doing the mixing to help with the subtractive mix computation. In my experience, I’m not aware of any successful attempts at doing this.
The only way I can think of doing this in a robust way is to first understand how the brain sees colors and then adapt this process to the subtractive mixture of RGB-based colors. The next section will discuss the mathematics of human color perception.
The presentation is spread over several web pages. Click the Next Page or Previous Page links to move sequentially. To access a page directly, use these links:
1. Introduction (this page)
2. The Mathematics of Human Color Perception
3. Subtractive Mixture of Two Reflectance Curves
4. Cataloged Reflectance Curves
5. Computing Reflectance Curves Directly from sRGB Values