While writing my program for visual cryptography, I noticed that each pixel in a picture could gets it’s own value of an alpha transparency. While I couldn’t find a way to make it useful, I recently returned to the project with the idea of seeing what it can do.
Each pixel in a png image is composed of four numbers – alpha channel transparency, red value, green value, and blue value. I will used the notation (A,R,G,B) for a pixel value. These values range from 0 to 255, but I’m going to use the convention of zero to one in my equations to represent percentage values. Also, I’m starting with gray value pictures to simplify the math, so the target picture will have values of (1,C,C,C). An alpha of 1 is opaque. If C=1 the pixel is white, C=0 is black, and intermediate values are shade of gray.
The basic equation for computer color addition is
$$T=B(1-\alpha )+F\alpha $$where T is the target gray value, B is the background value, and F is the foreground color. And alpha is alpha.
So, what can we do. If we make all pixels black and set the alpha channel to 1-T, i.e. (1-T,0,0,0) the picture will disappear over a black background and will be the original over a white background. If we make all pixels white and set the alpha channel to the target color, (T,1,1,1), we get an image that needs a black background to look like the original. Let’s do this with a Dawn Wells picture.
Here we have a black pixel Dawn and a white pixel Dawn on a various color background. Drag the images (magenta frames) around to see the pictures.
OK, what about a gray background? If the target pixel color is greater than than the background we make a white pixel and make it darker -> $F = (\frac{{T – B}}{{1 – B}},1,1,1)$. And if the color is darker, we make a black pixel -> $F = (1 – \frac{{T}}{{B}},0,0,0)$. All these pictures are on their proper background. Move them around to see the differences.
Hey, let’s make a random black and white pixel background. If the background pixel is black, we make a white foreground pixel with the proper alpha, if the pixel is white, we make a black foreground pixel. Using (1-T,0,0,0) and (T,1,1,1). Move the images to the correct corners to get the image. Download the picture files for the next window if you want to check for yourself.
Well if we can do that, we can use the equations for a gray background and make a background of random gray pixels and make a foreground of black and white pixels. Download the pictures for the next block if you don’t trust me.
What about a solid color background? If the background is red, (1,1,0,0) and the target color is gray, (1,T,T,T), we’ll define the foreground color as (alpha,R,B,G). This gives three equations.
$T = (1 – \alpha ) + R\alpha$ $T = G\alpha$ $T = B\alpha $The equations for G and B are identical, so those values are the same. Since $B = \frac{T}{\alpha }$ we can pick a random alpha between T and 1, and solve for R, G, and B. The solutions for a green or a blue background are trivial because instead of (1,1,0,0) we use (1,0,1,0) or (1,0,0,1) and the equations are essentially the same, just with the values in different places.
Move the Dawns around to get the original picture.
We can easily make pictures for a cyan (0,1,1), magenta (1,0,1), or yellow (1,1,0) backgrounds just by using the same output variables in different positions.
So one last puzzle. We can make a random color background using all the previous colors and making a foreground. By varying the variables, I found weighting the black background component helped obfuscate the picture better. Download the pictures.
Now we can’t just use any background color because there will be pixels with no solutions. For example, for a background of (1, 0.5, 0, 0) – a dark red – target gray colors above one half can not have foreground colors and alphas both between zero and one. There are trivial solutions, like the foreground is a solid color, or the foreground is totally transparent.
We can separate a picture into a random background color and a random foreground color, but this will require LOT of math. I’ll go into that in part 2.
Note: When programming use the highest precision variables as possible. Sometimes my calculations wouldn’t work with floats, but worked fine with doubles. Sometimes it’s useful to ‘trim’ the target pixels – i.e. set all colors greater than 250 to 250 and all grays below 5 to 5. Or else you have to make sure your program deals with zeros and ones.