user3526
user3526

Reputation: 1462

Gaussian blur that handles alpha transparency

I have been trying to implement an algorithm in C# for a gaussian blur that takes care of transparency. I tried the following two implementations, and each seems to give me different type of results. But neither takes into account the alpha channel.

http://code.google.com/p/imagelibrary/downloads/detail?name=ImageLibrary-source-1_2_4.zip&can=2&q= http://www.smokycogs.com/blog/image-processing-in-c-sharp-smoothing-using-convolution/

My test image has a simple circle on a transparent background PNG.

Could somebody point me in the right direction to get the gaussian blur to work with images that have transparency ? The only link i could find was a box blur. http://www.codeproject.com/Articles/6162/Gausian-and-Alpha-Blurring

Upvotes: 2

Views: 4611

Answers (2)

Dan Byström
Dan Byström

Reputation: 9244

You must multiply each RGB value with the alpha value and afterwards divide the result with the maximum possible alpha.

Let's say you want to average just three pixels:

newBlue = (
  src[-1].Blue * src[-1].Alpha + 
  src[0].Blue * src[0].Alpha + 
  src[1].Blue * src[1].Alpha ) / (255*3);

As you can see: if all three pixels are solid (alpha=255) then this calculation won't cange anything compared to ignoring the alpha channel (which is indeed what we want).

Here is a 3x3 convolution without alpha:

            for (var i = nWidth - 2; i > 0; i--)
            {
                n = ((((pT[-sourcePixelSize]*m.TL) + (pT[0]*m.TM) + (pT[sourcePixelSize]*m.TR) +
                       (pM[-sourcePixelSize]*m.ML) + (pM[0]*m.MM) + (pM[sourcePixelSize]*m.MR) +
                       (pB[-sourcePixelSize]*m.BL) + (pB[0]*m.BM) + (pB[sourcePixelSize]*m.BR) + 5)/m.Factor) + m.Offset);
                *pD = (byte) (n <= 0 ? 0 : n >= 255 ? 255 : n);
                pT += sourcePixelSize;
                pM += sourcePixelSize;
                pB += sourcePixelSize;
                pD += 4;
            }

Here is the eqvivalent with alpha:

            for (var i = nWidth - 2; i > 0; i--)
            {
                alphaSum = (pT[-4 + ao] + pT[ao] + pT[4 + ao] +
                            pM[-4 + ao] + pM[ao] + pM[4 + ao] +
                            pB[-4 + ao] + pB[ao] + pB[4 + ao] + 5)/9;
                n = alphaSum != 0
                        ? ((((pT[-4]*pT[-4 + ao]*m.TL) + (pT[0]*pT[ao]*m.TM) + (pT[4]*pT[4 + ao]*m.TR) +
                             (pM[-4]*pM[-4 + ao]*m.ML) + (pM[0]*pM[ao]*m.MM) + (pM[4]*pM[4 + ao]*m.MR) +
                             (pB[-4]*pB[-4 + ao]*m.BL) + (pB[0]*pB[ao]*m.BM) + (pB[4]*pB[4 + ao]*m.BR) + 5)/
                            (m.Factor*alphaSum)) + m.Offset)
                        : 0;
                *pD = (byte) (n <= 0 ? 0 : n >= 255 ? 255 : n);
                pT += 4;
                pM += 4;
                pB += 4;
                pD += 4;
             }

Upvotes: 2

comingstorm
comingstorm

Reputation: 26097

If you are using premultiplied alpha transparency, you can blur the alpha channel just like the RGB channels.

If your alpha is not premultiplied, you can get weird fringing artifacts. To avoid that, you can try converting your image to premultiplied, filtering it, then converting it back. There are pitfalls in this process, but the result will likely be better than naively smoothing a unmultiplied alpha image.

Upvotes: 4

Related Questions