views:

44

answers:

1

I am trying to update a source image with the contents of multiple destination images. From what I can tell using premultiplied alpha is the way to go with this, but I think I am doing something wrong (function below). the image I am starting with is initialized with all ARGB values set to 0. When I run the function once the resulting image looks great, but when I start compositing on any others all the pixels that have alpha information get really messed up. Does anyone know if I am doing something glaringly wrong or if there is something extra I need to do to modify the color values?

void CompositeImage(unsigned char *src, unsigned char *dest, int srcW, int srcH){
int w = srcW;
int h = srcH;

int px0;
int px1;
int px2;
int px3;

int inverseAlpha;

int r;
int g;
int b;
int a;

int y;
int x;

for (y = 0; y < h; y++) {
    for (x= 0; x< w*4; x+=4) {
        // pixel number
        px0 = (y*w*4) + x;
        px1 = (y*w*4) + (x+1);
        px2 = (y*w*4) + (x+2);
        px3 = (y*w*4) + (x+3);

        inverseAlpha = 1 - src[px3];

        // create new values
        r = src[px0]  + inverseAlpha * dest[px0];
        g = src[px1]  + inverseAlpha * dest[px1];
        b = src[px2]  + inverseAlpha * dest[px2];
        a = src[px3]  + inverseAlpha * dest[px3];

        // update destination image
        dest[px0] = r;
        dest[px1] = g;
        dest[px2] = b;
        dest[px3] = a;
    }
}

}

+1  A: 

I'm not clear on what data you are working with. Do your source images already have the alpha values pre-multiplied as they are stored? If not, then pre-multiplied alpha does not apply here and you would need to do normal alpha blending.

Anyway, the big problem in your code is that you're not keeping track of the value ranges that you're dealing with.

inverseAlpha = 1 - src[px3];

This needs to be changed to:

inverseAlpha = 255 - src[px3];

You have all integral value types here, so the normal incoming 0..255 value range will result in an inverseAlpha range of -254..1, which will give you some truly wacky results.

After changing the 1 to 255, you also need to divide your results for each channel by 255 to scale them back down to the appropriate range. The alternative is to do the intermediate calculations using floats instead of integers and divide the initial channel values by 255.0 (instead of these other changes) to get values in the 0..1 range.

If your source data really does already have pre-multiplied alpha, then your result lines should look like this.

r = src[px0]  + inverseAlpha * dest[px0] / 255;

If your source data does not have pre-multiplied alpha, then it should be:

r = src[px0] * src[px3] / 255  + inverseAlpha * dest[px0] / 255;

There's nothing special about blending the alpha channel. Use the same calculation as for r, g, and b.

Alan
That works perfectly. I had tried both of these things individually prior, but didn't think to plug them in together. Makes sense now.
pixelrevision