RGB Colors
Summary: We examine some basic operations for
working with RGB colors.
Introduction
In a related
reading, you learned about raster graphics and ways to set and
get colors at various locations in a raster image. However, in your
work, you were limited to either the colors already in the image or
the colors that someone has named for you.
One of the great advantages of computational image making is that
it is possible to describe colors that do not have a name. In fact,
it is often better to use a more precise definition than is possible
with a name. After all, we may not agree on what precisely something
like springgreen
or burlywood
means. (One color scheme that we've found has both Seattle
salmon
and Oregon salmon
. Would
you know how those two colors relate?)
In fact, it may not only be more accurate to represent colors
non-textually, it may also be more efficient,
since we will often need to look up color names in a table somewhere.
Representing Colors
The most popular scheme for representing colors for display on the
computer screen is RGB. In this scheme, we build each color by combining
varying amounts of the three primary colors, red, green, and blue.
(What, you think that red, yellow, and blue are the primary colors?
It turns out that primary works differently when you're transmitting
light, as on the computer screen, than when you're reflecting light,
as when you color with crayons on paper.)
So, for example, purple is created by combining a lot of red, a lot of
blue, and essentially no green. You get different purple-like colors by
using different amounts of red and blue, and even different ratios of
red and blue.
When we describe the amount of red, green, and blue, we traditionally
use integers between 0 and 255 to describe each component color.
Why do we start with 0? Because we might not want any contribution
from that color. Why do we stop with 255? Because 255 is one
less than 28 (256), and it turns out that
numbers between 0 and 255 are therefore easy to represent on computers.
(For those who learned binary in high school or elsewhere, if you have
exactly eight binary digits, and you only care to represent positive
numbers, you can represent exactly the integers from 0 to 255.)
If there are 256 possible values for each component, then there are
16,777,216 different colors that we can represent in standard RGB. Can
the eye distinguish all of them? Not necessarily. Nonetheless, it
is useful to know that this variety is available, and many eyes can make
very fine distinctions between nearby colors.
Relevant Procedures
Let us now turn to the primary procedures we will use to work with
RGB colors.
We build a new color with the (rgb-new
red-component
green-component
blue-component) procedure. Here
are a few colors.
(rgb-new 255 0 0)
(rgb-new 127 0 127) (rgb-new 191 0 191) (rgb-new 255 0 255) (rgb-new 127 0 191) (rgb-new 191 0 127)
For example, we might set the center of a 9x5 image to a purple-like
color with the following.
> (image-set-pixel! canvas 4 2 (rgb-new 128 0 128))
Internally, each RGB color is represented as a single integer.
The particular
algorithm to convert the three components to an integer and back again
are not complex, but are not necessary to your understanding. However,
when using RGB colors, you may find that you see some strange numbers.
With some exceptions that you will learn, it's very difficult to look at
these numbers and know what colors they represent.
> (define sample-color (color-name->rgb "palevioletred"))
> sample-color
14381203
sample-color
If we have color created by rgb-new or extracted with
image-get-pixel (or computed in one of the ways you'll
learn over the next few weeks), we can extract the red, green, and blue
components with (rgb-red color),
(rgb-green color), and
(rgb-blue color). For example,
we can remove the green component of the upper-right pixel of a 9x5
sample image with
> (define color (image-get-pixel sample-image 8 4))
> (image-set-pixel! sample-image 8 4 (rgb-new (rgb-red color) 0 (rgb-blue color))
These procedures can also be useful for telling us a bit about the named
colors. For example, let's figure out the components of the color
that the GIMP calls named palevioletred
.
> (define sample-color (color-name->rgb "palevioletred"))
> sample-color
> (rgb-red sample-color)
219
> (rgb-green sample-color)
112
> (rgb-blue sample-color)
147
At times, we simply want to find out the three components of the
color so that we can think about the meaning of those components.
(That is, we will not compute with the values, but simply look at them.)
While we could use each of rgb-red, rgb-green,
and rgb-blue, as in the sample code above, that requires
a bit more effort than seems necessary. Hence, MediaScript also provides
procedures called (rgb->rgb-list
color) and
(rgb->string
color) that let us view the three
components together.
(color-name->rgb "palevioletred")
(color-name->rgb "cornflowerblue")
> (define sample-color (color-name->rgb "palevioletred"))
>; (rgb->rgb-list sample-color)
(219 112 147)
>; (rgb->rgb-list (color-name->rgb "cornflowerblue"))
(100 149 237)
>; (rgb->string sample-color)
"219/112/147"
>; (rgb->string (color-name->rgb "cornflowerblue"))
"100/149/237"
[Design Detour] Computing with Color: Complementary Colors
In creating works, many artists and visual designers consider the
applications of complementary colors. A pair of
colors is complementary if the sum of the two colors is a kind of grey
(including black or white). What does it mean to sum two colors?
Well, it turns out that complementarity is really defined only for
a different representation of colors (hue, saturation, and value,
or HSV). Nonetheless, we can come close to simulating it in RGB,
so we will call complementary colors defined using their RGB values
pseudo-complementary colors.
In RGB, we can add the colors by adding the corresponding components
(capping the sum at 255) or by averaging the corresponding components.
We'll use the former technique, because it can be a bit easier to
analyze capping.
For example, the pseudo-complement of green (0/255/0) is magenta (255/0/255)
because when we add them together, we get 255/255/255, which is white.
(rgb-new 0 255 0) (rgb-new 255 0 255)
Depending on what you accept as the definition of grey
,
colors can have many pseudo-complements. For example, consider
the color 128/0/0, which is similar to maroon. One logical
pseudo-complement to that color is 127/255/255 (a color for which there
is no name, but which MediaScript thinks is similar to aquamarine),
since when we add the two colors together, we get 255/255/255, which
is still white. However, one might also consider 0/128/128 (a color
with which MediaScript calls teal) as a pseudo-complement, since when
we add the two together, we get 128/128/128, a nice medium grey.
(rgb-new 128 0 0) (rgb-new 127 255 255)
(rgb-new 128 0 0) (rgb-new 0 128 128)
(rgb-new 128 128 128)
In general, when we say pseudo-complementary color
, we mean the
one which, when we add the RGB components to those of the first color,
we get white. When we ask for multiple pseudo-complements for the same
color, we'll mean those that, when added, give us a color in which all
three components are the same (that is, a version of grey).