Extracting alpha

Sometimes you will want to take a VisIt image that contains transparency and composite that image over another image. To be done correctly, you need an alpha channel for the VisIt image. The alpha channel will ensure that geometry and patterns from the background image will show through the transparent portions of the VisIt image.

Unfortunately, VisIt does not currently write out alpha channel information. All is not lost, since you can reconstruct the image by saving your image once with a black background and once with a white background. If you difference the images, you can derive the alpha channel.

Script to automate alpha extraction

This script uses PIL to create an output image that has an alpha channel.


alpha.py whiteImage blackImage outputImage
#! /bin/sh
exec python $0 ${1+"$@"}

from PIL import Image, ImageChops

import sys

if len(sys.argv) != 4:
    print >>sys.stderr, "Usage: %s whiteImage blackImage outputImage"%sys.argv[0]
whiteFile = sys.argv[1]
blackFile = sys.argv[2]
outFile = sys.argv[3]

W = Image.open(whiteFile)
Wdata = W.getdata()
B = Image.open(blackFile)
Bdata = B.getdata()
alpha = ImageChops.subtract(W, B)
alpha = alpha.convert("L")
alphaData = alpha.getdata()
out = Image.new("RGBA", W.size)
outData = list(out.getdata())
size = W.size
count = 0
for y in range(size[1]):
    for x in range(size[0]):
        Bp = B.getpixel((x,y))
        a = alpha.getpixel((x,y))
        r = Bp[0]/255.
        g = Bp[1]/255.
        b = Bp[2]/255.
        a = a / 255.
        a = 1 - a
        if a > 0.0:
            r = r / a
            g = g / a
            b = b / a
        r = int(r*256)
        g = int(g*256)
        b = int(b*256)
        a = int(a*256)
        outData[count] = (r, g, b, a)
        count += 1

Mathematical explanation

Let W = white image, B = black image, A = alpha, C = color without alpha.
You know W and B, you're trying to retrieve A.
W = A*C + (1-A)*1.0
B = A*C + (1-A)*0.0

Subtract the images:
W - B = (A*C - A*C) + (1-A)*(1.0 - 0.0)
W - B = (0.0) + (1-A)*(1.0)
W - B = 1 - A
A = 1 - (W-B)

And you can reconstruct the original color by dividing the black image by alpha:
B = A*C + (1-A)*0.0
B = A*C
C = B/A

Note that the resultant image contains three channels, but should be a grayscale image within the numerical quantization limits. Also, in the color reconstruction, watch out for zero alpha (though note that a zero alpha should result in a zero output value, so you're only trying to avoid dividing 0/0, and in this case, you have no data to suggest the original color).

Example images

AlphaEx White.png AlphaEx Black.png AlphaEx Alpha.png

Note: the last PNG image is not the real output image from the script since many Web browsers wont properly render the transparancy. Instead, the output image has been manually composited with a checkerboard pattern using its alpha channel and a regular RGB image has been saved here to the wiki.