1. Introduction
In this tutorial, we’re going to have a look at how computers represent color compared to how they work in nature, and then we’ll see how to convert between the two.
2. How Light Frequency Works
What we perceive as light is really a portion of the electromagnetic spectrum. Specifically, the human eye is able to perceive frequencies between about 400 and 790 THz. The receptors within our eyes – in particular, the cone cells – react differently to different frequencies of light, which our brains then perceive as different colors.
We’ll often see this referred to in terms of wavelength instead. Frequency and wavelength directly correlate to each other by , where is the speed of light, is the frequency, and is the wavelength.
If our eyes receive the light of a single discrete frequency, then we’ll perceive this as a discrete color:
Frequency (THz)
Wavelength (nm)
Color
< 400
> 750
Infra-Red
400 – 480
625 – 750
Red
480 – 510
590 – 625
Orange
510 – 530
565 – 590
Yellow
530 – 600
500 – 565
Green
600 – 620
485 – 500
Cyan
620 – 670
450 – 485
Blue
670 – 790
380 – 450
Violet
> 790
< 380
Ultra-Violet
In reality, most light is actually a combination of different frequencies at the same time. In this case, our eyes will perceive these different frequencies, and our brains will interpret them as a mixture. For example, a mixture of red and green will be interpreted as yellow. If we mix all of these frequencies together into one, then this is perceived as white.
3. How Computers Represent Color
Computer screens – and indeed, all modern displays – don’t work in these terms. Instead, they work using an RGB color model. This means that every color is actually represented as a mixture of Red, Green, and Blue.
In physical displays, this is handled by having actual colored lights of these three colors for every pixel. We then turn each of these on to an appropriate amount, and the human eye perceives light as the mixture of these colors.
This works because red, green, and blue are considered additive primary colors. It’s possible to represent almost every natural color by mixing various intensities of these three colors.
For example, we might want to display a Royal Blue color:
In order to achieve this color, we need to mix 33% Red, 48% Green, and 86% Blue.
These RGB colors are typically represented as a set of color codes expressed as 3 pairs of hex digits. The above color is #557BDC, meaning:
- The red component is 0x55 (85), out of a possible maximum of 0xff (255)
- The green component is 0x7b (123), out of a possible maximum of 0xff (255)
- The blue component is 0xdc (220), out of a possible maximum of 0xff (255)
This is the same as we saw earlier, only restricted to the primary colors instead of the entire color spectrum.
4. Converting Light Frequency to RGB Color
Now that we know how colors work in these different models, how do we convert between them?
Remember that computer displays are only capable of representing the three primary colors – red, green, and blue. As such, we need to be able to determine, for any given frequency of light, the intensities of red, green, and blue light that would need to be mixed to achieve the same thing.
Unfortunately, there’s no direct mapping between the two. We’ll see a couple of heuristics here that will get a good approximation.
4.1. Simplified Mapping
Earl F. Glynn is known for creating a simplified mapping of light wavelengths to RGB colors. This isn’t as accurate as other methods, but it’s simple to implement and often good enough.
This heuristic works by breaking the entire range of wavelengths into sections, each of which maps colors in a different way:
Wavelength (nm)
Red
Green
Blue
645 – 780
1.0
0.0
0.0
580 – 645
1.0
-(\lambda – 645) / (645 / 580)
0.0
510 – 580
(\lambda – 510) / (580 – 510)
1.0
0.0
490 – 510
0.0
1.0
-(\lambda – 510) / (510 – 490)
440 – 490
0.0
(\lambda – 440) / (490 – 440)
1.0
380 – 440
-(\lambda – 440) / (440 – 380)
0.0
1.0
Applying these functions will give us values for red, green, and blue that are between 0.0 and 1.0.
Next, we generate a fading factor to reduce the intensity of the generated color at the extreme ends of the spectrum:
Wavelength (nm)
Factor
700 – 780
0.3 + 0.7 * (780 – \lambda) / (780 – 700)
420 – 700
1.0
380 – 420
0.3 + 0.7 * (\lambda – 380) / (420 – 380)
Once we have these values, we can use them to generate the final RGB colors. For each of the red, green, and blue channels, we apply the formula . This then gives us three values in the range of , ready for use as our color.
Let’s actually work through this. We’ll convert a wavelength of – which is in the violet range – to RGB.
Firstly, we’ll work out the raw red, green, and blue values:
- Red = = = =
- Green = 0.0
- Blue = 1.0
Next, we need our fading factor. This is = = = .
Now we can plug it all together to get our final values:
- Red = = = 0x82.
- Green = = = 0x00.
- Blue = = = 0xB5.
So we have a color of #8200B5, which looks like this:
If we then do this for the entire range of visible light, then the result is:
The white bars indicate the bounds in our original table, indicating which discrete color each frequency maps onto.
4.2. CIE Color Matching
Another possible algorithm is the CIE color-matching algorithm. This is based on the CIE 1931 color model, which is a mathematical model of how the human eye perceives color that was developed by the International Commission on Illumination in 1931.
This is more complicated but gives a better end result. It works by calculating values in the CIE XYZ color space for the light based on the wavelength and then converting this into RGB values. In this color space:
- X is considered to represent the hue and saturation on the red-green axis.
- Y is considered to represent the luminosity.
- X is considered to represent the hue and saturation on the blue-yellow axis.
This color space more closely models how humans perceive light, as opposed to how computers can generate it.
Our X value is calculated as follows:
Our Y value is then calculated as:
And finally, our Z value is then calculated as:
Once we have these, we can combine them to calculate our raw RGB values:
Finally, before these values are usable, we need to apply some gamma correction and convert them into the 0-255 range.
This looks a lot more complicated than it really is, so let’s work through it again and see what we get. We’ll convert a wavelength of – which is just in the green range – to RGB.
Firstly, we’ll calculate our X, Y, and Z values:
Next, we can use these to calculate our raw R, G, and B values:
Now we can apply our gamma correction and expand these to our 0-255 range.
This gives a color of #00F747, which looks like this:
If we then do this for the entire range of visible light, then the result is:
The white bars indicate the bounds in our original table, indicating which discrete color each frequency maps onto.
We can immediately see the similarities and differences between this method and the earlier one.
5. Summary
Here we’ve seen how color is represented by computers as compared to how it works in nature. We’ve also seen a couple of methods that can be used to convert light frequency, and therefore light wavelength, into the RGB colors that computers understand. Why not try implementing this for yourself?