如何在图像卷积过程中使用预乘以解决alpha出血问题? [英] How to use pre-multiplied during image convolution to solve alpha bleed problem?

查看:282
本文介绍了如何在图像卷积过程中使用预乘以解决alpha出血问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将一个框模糊应用于透明图像,并且我在边缘处得到一个暗晕。



Jerry Huxtable

  • 预乘alpha


  • 解决方案

    tkerwin有已经提供了正确答案,但它似乎需要进一步解释。



    你在问题​​中显示的数学是绝对正确的,直到最后。在那里你错过了一步 - 结果仍然是预乘的alpha模式,并且必须unmultiplied回到PixelFormat32bppARGB格式。乘法的反面是除数,因此:

      finalRed = finalRed * 255 / finalAlpha; 
    finalGreen = finalGreen * 255 / finalAlpha;
    finalBlue = finalBlue * 255 / finalAlpha;

    你已经表达了一个担心,这个鸿沟可能会产生一个远远超出范围的结果,但是这不会发生。如果跟踪数学,您会注意到红色,绿色和蓝色值不能大于alpha值,因为预乘法步骤。如果你使用的是比简单的盒子模糊更复杂的过滤器,那么它可能是可能的,但即使你没有使用alpha也是如此!正确的反应是钳制结果,将负数转为0,将任何大于255的数字转换为255。


    i'm trying to apply a box blur to an transparent image, and i'm getting a "dark halo" around the edges.

    Jerry Huxtable has a short mention of the problem, and a very good demonstration showing the problem happen:

    But i, for the life of me, cannot understand how "pre-multiplied alpha" can fix the problem. Now for a very simple example. i have a 3x3 image, containing one red and one green pixel:

    In reality the remaining pixels are transparent:

    Now we will apply a 3x3 Box Blur to the image. For simplicities sake, we'll only calculate the new value of the center pixel. The way a box blur works is that since we have a 9 position square (3x3, called the kernel) we take 1/9th of each pixels in the kernel, and add it up:

    So

    finalRed =   1/9 * red1 + 1/9 * red2 + 1/9 * red3+ ... + 1/9 * red9
    finalGreen = 1/9*green1 + 1/9*green2 + 1/9*green3+ ... + 1/9*green9
    finalBlue =  1/9* blue1 + 1/9* blue2 + 1/9* blue3+ ... + 1/9* blue9
    finalAlpha = 1/9*alpha1 + 1/9*alpha2 + 1/9*alpha3+ ... + 1/9*alpha9
    

    In this very simplified example, the calculations become very simple:

    finalRed =   1/9 * 255
    finalGreen = 1/9 * 255
    finalBlue =  0
    finalAlpha = 1/9*255 + 1/9*255
    

    This gives me a final color value of:

    finalRed =   28
    finalGreen = 28
    finalBlue =  0
    finalAlpha = 56 (22.2%)
    

    This color is too dark. When i perform a 3px Box blur on the same 3x3 pixel image in Photoshop, i get what i expect:

    Which is clearer when displayed over white:


    In reality i'm performing a box blur on a bitmap containing transparent text, and the text gains the tell-tale dark around the fringes:

    i'm starting with a GDI+ Bitmap that is in PixelFormat32bppARGB format


    How do i use "pre-multiplied alpha" when applying 3x3 convolution kernel?

    Any answer will have to include new forumla, since:

    final = 1/9*(pixel1+pixel2+pixel3...+pixel9)
    

    Is getting me the wrong answer.


    Edit: A simpler example is:

    i'll perform this math with color and alpha values in the range of 0..1:

    i'm going to apply the box blur convolution filter to the middle pixel:

    ARGB'
          = 1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0) + 
            1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0) + 
            1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0);
    
          = (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0) +
            (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0) +
            (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0)
    
          = (0, 0.33, 0, 0.33)
    

    Which gives a fairly transparent dark green.

    Which is not what i expect to see. And by comparison Photoshop's Box Blur is:

    If i assume (0, 0.33, 0, 0.33) is pre-multiplied alpha, and un-multiply it, i get:

    (0, 1, 0, 0.33)
    

    Which looks right for my all-opaque example; but i don't know what to do when i begin to involve partially transparent pixels.

    See also

    解决方案

    tkerwin has already provided the correct answer, but it seems to need further explanation.

    The math you've shown in your question is absolutely correct, right up until the end. It is there that you're missing a step - the results are still in a pre-multiplied alpha mode, and must be "unmultiplied" back to the PixelFormat32bppARGB format. The opposite of a multiply is a divide, thus:

    finalRed = finalRed * 255 / finalAlpha;
    finalGreen = finalGreen * 255 / finalAlpha;
    finalBlue = finalBlue * 255 / finalAlpha;
    

    You've expressed a concern that the divide might create a result that is wildly out of range, but that won't happen. If you trace the math, you'll notice that the red, green, and blue values can't be greater than the alpha value, because of the pre-multiplication step. If you were using a more complicated filter than a simple box blur it might be a possibility, but that would be the case even if you weren't using alpha! The correct response is to clamp the result, turning negative numbers into 0 and anything greater than 255 into 255.

    这篇关于如何在图像卷积过程中使用预乘以解决alpha出血问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆