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 \lambda = C/f, where C is the speed of light, f is the frequency, and \lambda 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:

Baeldung Blue

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 round(255 * (value * factor) ^ {0.8}). This then gives us three values in the range of 0 - 255, ready for use as our color.

Let’s actually work through this. We’ll convert a wavelength of 400nm – which is in the violet range – to RGB.

Firstly, we’ll work out the raw red, green, and blue values:

  • Red = -(\lambda - 440) / (440 - 380) = -(400 - 440) / (440 - 380) = 40 / 60 = 0.\overline{666}
  • Green = 0.0
  • Blue = 1.0

Next, we need our fading factor. This is 0.3 + 0.7 * (\lambda - 380) / (420 - 380) = 0.3 + 0.7 * (400 - 380) / (420 - 380) = 0.3 + 0.7 * 20 / 40 = 0.65.

Now we can plug it all together to get our final values:

  • Red = round(255 * (0.\overline{666} * 0.65) ^ {0.8}) = 130 = 0x82.
  • Green = round(255 * (0.0 * 0.65) ^ {0.8}) = 0 = 0x00.
  • Blue = round(255 * (1.0 * 0.65) ^ {0.8}) = 181 = 0xB5.

So we have a color of #8200B5, which looks like this:

Violet

If we then do this for the entire range of visible light, then the result is:

simple spectrum

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:

Rendered by QuickLaTeX.com

Our Y value is then calculated as:

Rendered by QuickLaTeX.com

And finally, our Z value is then calculated as:

Rendered by QuickLaTeX.com

Once we have these, we can combine them to calculate our raw RGB values:

Rendered by QuickLaTeX.com

Finally, before these values are usable, we need to apply some gamma correction and convert them into the 0-255 range.

Rendered by QuickLaTeX.com

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 510nm – which is just in the green range – to RGB.

Firstly, we’ll calculate our X, Y, and Z values:

Rendered by QuickLaTeX.com

Next, we can use these to calculate our raw R, G, and B values:

Rendered by QuickLaTeX.com

Now we can apply our gamma correction and expand these to our 0-255 range.

Rendered by QuickLaTeX.com

This gives a color of #00F747, which looks like this:

Green

If we then do this for the entire range of visible light, then the result is:

cei spectrum

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?