home
on exploration, introspection and creation

Playing with Color (part I)

I’m fascinated by color. When I was younger I dreamt of discovering a color that nobody has ever seen before. And since most computer languages give you easy ways to manipulate graphics, I played with color on a computer.

One day I saw an interesting effect on some certificate I got. When you photocopied it in black and white, a word appeared in the photocopy that wasn’t visible in the original that said “COPY”. In fact, this effect took advantage of the photocopier’s inability to faithfully replicate the document (in this case the word COPY was visible in the original but it was difficult to see because it consisted of a bunch of tiny dots), but I wondered whether it would be possible to hide messages in documents even if the copier were to produce faithful facsimiles.

Specifically, I asked myself, can I come up with a message that is visible on a color version of an image but that disappears on the grayscale version? It turns out that it’s possible, and not that difficult. I’ll explain how, while trying to limit distracting you with color theory to the minimum.

On a computer screen, each color is a mixture of three primary colors, red, green and blue (printers use a slightly different scheme but for all intents and purposes we can limit ourselves to talking about the RGB space). It turns out that pure red does not appear as “bright” to the eye as pure green. In fact, the intensity of a color (how “bright” it appears to the eye regardless of its hue) has been found to be a weighed average of the three primary components:

intensity = 0.299*red + 0.587*green + 0.114*blue

This intensity is precisely what you see when you convert an image to grayscale (note that you may find different formulas depending on what devices you’re dealing with — different devices have different sensitivity to various primary colors). For example, consider the following image and its grayscale version:

Not all colors were created equally bright

Not all colors were created equally bright

(Of course your favorite graphics editing software simply applies the above transformation; to find the precise relation from first principles you can take a picture of the image below with an old-fashioned analog camera on a black-and-white film and find rectangles that match in intensity).

Use this to derive the intensity formula

Use this to derive the intensity formula

A simple idea for hiding messages is therefore to produce an image of pixels whose intensity is all the same, but whose hue is different (so that we can see the message in color). For example, we can give every pixel of the message the color of (1, 0.3, 0.4) and every pixel of the background the color of (0.3, 0.7, 0.176). The intensity of the former is 0.52, as is the intensity of the latter. Since the intensities are close to each other, when we desaturate the image, the message will blend with the background.

This works well if we know the relationship for a given device exactly. Some printers (if we wish to print the image out) use a slightly different relationship (or perhaps they round the weights). In such a case the two intensities will not be exactly the same and the eye is surprisingly good at telling the difference between two close colors if they cover large areas! We can improve this algorithm by adding some randomness (this is just a suggestion that works pretty well, you can find much better algorithms!):

Consider an input image that contains the message (white text on black background). Each pixel has an intensity of 0 (if the pixel belongs to the background) or 1 (if the pixel belongs to the text), and probably somewhere in between if the text is antialiased.

The secret message we'll try to hide

The secret message we'll try to hide

First, transform the image by adding some random noise and reducing the variance between white and black:

targetIntensity = (rand() + sourceIntensity + 1)*0.33

Adding some randomness

Adding some randomness

Once we have the target intensity, we’ll randomly adjust the intensity formula and find an output color such that the intensity formula cancels targetIntensity out:


alpha = 0.587 + (rand(25)-12)*0.001
beta = 0.299 + (rand(25)-12)*0.001
gamma = 1.0 - alpha - beta

ratio = (alpha-gamma)/beta
r = 0.44 + targetIntensity/3.0
g = 0.62 - targetIntensity*ratio/3.0
b = 0.9 - targetIntensity/3.0

Convince yourself that the intensity is a constant, independent of targetIntensity. But since targetIntensity varies, the color version of the image will consist of distinctly different pixels.

As a nice touch we can alternate between two different formulas for added noise:

The resulting message that disappears when rendered in grayscale!

The resulting message that disappears when rendered in grayscale!

Print the above image out in black and white and see the message disappear!

Of course, it would be great if we could write a program that takes a message and displays an image like the one above. Ruby with RMagick makes it very easy:

Enter some short text here:

and then click this link

Source:
disappearing-helper.rb

Good reading:
Colour Space Conversions

One Response to “Playing with Color (part I)”

  1. [...] you know, I’m fascinated with color, especially when there’s math or technology involved. [...]

Leave a Reply