If you are an artist, photographer, graphic designer, or web developer, having a firm understanding of colors is a necessity. Key to being able to study and discuss colors is a formal framework for quantizing their properties. Abstract mathematical models called color models do just this, allowing people to discuss the qualities of a color in a consistent manner. These models usually assign tuples of numbers to a color, often either ordered triplets or quartets, where each value represents a property of the color. This post will introduce one the most popular models: the RGB color model.
Color Models and Color Spaces
Even though they do provide precise representations of colors, color models, are still abstract. To cross from theoretical to practical, a color model would also need to take into account the conditions under which the color is viewed. For example the primary color red will appear different when viewed in direct sunlight versus a cloudy day. Or consider devices with displays like cell phones, tablets, computer monitors, or TVs. Either because of technical limitations or by design choice, there is variation in how colors appear between devices. Apple’s idea of absolute red on the iPhone will likely vary slightly from Samsung’s interpretation on a Galaxy phone. For a technical limitation, think about how even when your phone is supposed to be displaying a black screen, the color usually is a few shades lighter. Color models provide a way to describe color in a precise way but not relative to any specific absolute reference. When the viewing conditions and other variable properties that affect the presentation of a color are taken into consideration, colors can be talked about in a more absolute way. A color model combined with a viewing profile is known as a color space.
RGB Color Model
One of the most prolific and, in my opinion, easiest to understand color models is the RGB color model. Inspired by the way human’s perceive colors, the RGB color model is an additive model , in which a color is represented by a triplet of values where each value stands for the intensity of the primary colors red, green, and blue respectively.
To understand why RGB is an additive model, its original practical application: image display in TVs and computer monitors. To form a specific color, three beams of light, blue, green, and red are superimposed. Each color beam, or component, has an intensity between 0 and 100%. The wave lengths of each beam’s light spectra add to one another to form the spectra of the final color.
When the intensity of all three components is 0%, the color is black. When all three are at 100% intensity the color is white as the above figure illustrates. Any time all three components are equal, the resulting color will be gray, the darkness of which will fall somewhere between black and white depending on the intensity value.
In addition to the three primary colors of the model, the graphic above illustrates three other noteworthy colors: the secondary colors, colors formed when two of the three components are at 100% intensity and the third component is absent entirely. The three secondary colors in the RGB model are yellow, made by combining red and green, magenta, made by combining blue and red, and cyan, the combination of blue and green.
Each secondary color is the complement of a primary color, specifically the primary color that is absent from itself. For yellow, magenta, and cyan the corresponding primary colors are blue, green, and red, respectively.
When the three components do not have the same value, the color will have a hue that falls closer to either red, green, or blue depending on which component has the largest value.
Since the component values represent intensity levels of their respective colors falling between none and full, an obvious choice for encoding is to use the percentages themselves.
|Red||(100%, 0%, 0%)|
|Green||(0%, 100%, 0%)|
|Blue||(0%, 0%, 100%)|
|Yellow||(100%, 100%, 0%)|
|Gray||(50%, 50%, 50%)|
|Tan||(82%, 71%, 55%)|
Floating Point Numbers
Percentages are nice as they explicitly identify what the component values represent: a percent intensity level for the respective color, but string percentages aren’t easy for computers to do math with. The obvious solution is to divide by 100 and use the corresponding floating pointing number between 0 and 1 instead.
|Red||(1.0, 0.0, 0.0)|
|Green||(0.0, 1.0, 0.0)|
|Blue||(0.0, 0.0, 1.0)|
|Yellow||(1.0, 1.0, 0.0)|
|Gray||(0.50, 0.50, 0.50)|
|Tan||(0.82, 0.71, 0.55)|
8 Bit Unsigned Integers
One aesthetic problem with using floating point numbers is that by their nature, floating point numbers are unable to represent every decimal number exactly. For example it is not possible to exactly represent the number 0.1. Where you might be expecting to see 0.1 you might find something like 0.1000000000000000055511151231257827021181 instead. In reality this is not an issue. The difference is completely negligible and will have no effect on calculations. Many systems will even hide this oddness from users by only showing the first few significant digits which on the surface will appear equal to 0.1.
Because at their heart, everything is an integer to a computer, using integers to represent RGB values only make sense. The most common choice is to use an unsigned, 8 bit integer value whose range is 0 to 255.
|Red||(255, 0, 0)|
|Green||(0, 255, 0)|
|Blue||(0, 0, 255)|
|Yellow||(255, 255, 0)|
|Gray||(128, 128, 128)|
|Tan||(210, 180, 140)|
Unlike decimal numbers, or base 10, that has ten symbols to represent numbers (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0), hexadecimal, or base 16, has sixteen symbols (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F). So when counting in hexadecimal, 10 does not follow 9. A does. And B in hexadecimal is the same as 11 in decimal. It is only after E (decimal 15) do we add a second decimal place and go to 10. So 10 in hexadecimal is the same as 16 in decimal.
This seems really confusing, and you might wonder why hexadecimal would be worth the effort. It turns out the hexadecimal is a great match for binary systems. A 4 bit binary number can represent the decimal numbers 0 through 15 – the same as single hexadecimal digit. That means the 8 bit integers we previously used for components can be represented a pair of hexadecimal digits. So the decimal numbers 0 to 255 are the same as 00 to FF in hexadecimal.
It gets better. Because of the correspondence between pairs of hexadecimal digits and 8 bit binary numbers, we can combine all three RGB components into one 6 digit hexadecimal number. So now instead of having to store 3 separate numbers to represent an RGB value, it only needs to store one.
The values are combined with the rightmost two digits being the R value, the middle two digits are the G value, and the leftmost two digits being the B value, ie., RRGGBB.
To distinguish hexadecimal numbers from decimal numbers, hexadecimal numbers are often preceded by a special prefix. In computer programming, this prefix is often ‘0x’, but on the web and in most software packages, the standard prefix is ‘#’.
That ends this introduction to the RGB color model. In my next post on the subject I will be discussing geometric representations of the RGB color model. Look for it soon.