【问题标题】:Gaussian blur that handles alpha transparency处理 Alpha 透明度的高斯模糊
【发布时间】:2012-05-02 06:22:35
【问题描述】:

我一直在尝试在 C# 中实现一种算法,用于处理透明度的高斯模糊。我尝试了以下两种实现,每一种似乎都给了我不同类型的结果。但两者都没有考虑到 alpha 通道。

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/

我的测试图像在透明背景 PNG 上有一个简单的圆圈。

有人能指出我正确的方向,让高斯模糊处理具有透明度的图像吗? 我能找到的唯一链接是框模糊。 http://www.codeproject.com/Articles/6162/Gausian-and-Alpha-Blurring

【问题讨论】:

    标签: c# image-processing graphics filter gaussian


    【解决方案1】:

    如果您使用 premultiplied alpha 透明度,您可以像 RGB 通道一样模糊 Alpha 通道。

    如果您的 alpha 没有预乘,您可能会得到奇怪的边缘伪影。为避免这种情况,您可以尝试将图像转换为预乘图像,对其进行过滤,然后再将其转换回来。这个过程有一些陷阱,但结果可能比天真地平滑未相乘的 alpha 图像要好。

    【讨论】:

    • 我仍在试图弄清楚这将如何适应。我正在寻找的测试图像和效果与 codeproject box blur 链接中的完全相似。对于图像由完全透明像素或完全不透明像素组成的这种情况,预乘似乎没有效果。我不确定我在这里缺少什么......
    • 不能保证一定有问题——这取决于透明区域下的 RGB 颜色。如果和区域外的颜色一样,应该没问题。但是,如果有人用不同的图像代替,而事实并非如此,他们可能会对结果感到惊讶和恼火......
    【解决方案2】:

    您必须将每个 RGB 值乘以 alpha 值,然后将结果除以可能的最大 alpha。

    假设您只想平均三个像素:

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

    如您所见:如果所有三个像素都是实心的(alpha=255),那么与忽略 alpha 通道(这确实是我们想要的)相比,此计算不会产生任何影响。

    这是一个 3x3 卷积没有 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;
                }
    

    这是 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;
                 }
    

    【讨论】:

    • 请原谅,但我无法遵循代码 sn-p 中使用的变量。你能帮忙解释一下吗?常量 4 是用来增加 4 个字节的吗?
    • ARGB 的一个像素为 4 个字节。 “ao”变量是“alpha offset”,在处理每个 R/G/B 通道时具有不同的值(每个像素进行三遍)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-30
    • 2019-04-23
    • 2010-09-30
    • 2013-12-16
    • 2020-02-01
    • 2016-11-18
    • 1970-01-01
    相关资源
    最近更新 更多