我正在尝试将一个框模糊应用于透明图像,并且我在边缘处得到一个“暗晕”。
Jerry Huxtable has a short mention of the problem,以及展示问题的非常好的演示:
但是,对于我的生活,我无法理解“预乘α”如何解决问题。现在举一个非常简单的例子。我有一个3x3的图像,包含一个红色和一个绿色像素:
实际上剩下的像素是透明的:
现在我们将对图像应用3x3 Box Blur。为简单起见,我们只计算中心像素的新值。盒子模糊的工作方式是,因为我们有一个9个位置的正方形(3x3,称为内核),我们占用内核中每个像素的1/9,并将其加起来:
所以
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
在这个非常简单的例子中,计算变得非常简单:
finalRed = 1/9 * 255
finalGreen = 1/9 * 255
finalBlue = 0
finalAlpha = 1/9*255 + 1/9*255
这给我一个最终的颜色值:
finalRed = 28
finalGreen = 28
finalBlue = 0
finalAlpha = 56 (22.2%)
这种颜色太暗了。当我在Photoshop中对同一个3x3像素图像执行3px Box模糊时,我得到了我的期望:
白色显示时更清晰:
实际上我正在对包含透明文本的位图执行框模糊处理,并且文本会在条纹周围变暗:
我开始使用PixelFormat32bppARGB
格式
在应用3x3卷积内核时如何使用“预乘alpha”?
任何答案都必须包含新论坛,因为:
final = 1/9*(pixel1+pixel2+pixel3...+pixel9)
给我错误的答案。
编辑:更简单的例子是:
我将使用0..1:
范围内的颜色和alpha值执行此数学运算
我要将盒子模糊卷积滤镜应用到中间像素:
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)
这给出了相当透明的深绿色。
这不是我期望看到的。相比之下,Photoshop的Box Blur是:
如果我假设(0, 0.33, 0, 0.33)
预先乘以alpha,并且非乘以它,我得到:
(0, 1, 0, 0.33)
哪个看起来适合我的全不透明的例子;但是当我开始涉及部分透明像素时,我不知道该怎么做。
答案 0 :(得分:6)
tkerwin有already provided the correct answer,但似乎需要进一步解释。
你在问题中展示的数学是完全正确的,直到最后。在那里你错过了一个步骤 - 结果仍处于预乘的alpha模式,并且必须“unmultiplied”回到PixelFormat32bppARGB格式。乘法的相反是一个除法,因此:
finalRed = finalRed * 255 / finalAlpha;
finalGreen = finalGreen * 255 / finalAlpha;
finalBlue = finalBlue * 255 / finalAlpha;
你已经表达了一种担忧,即分歧可能会产生一个远远超出范围的结果,但这种情况不会发生。如果跟踪数学,您会注意到红色,绿色和蓝色值不能大于alpha值,因为预乘法步骤。如果你使用的是比简单的盒子模糊更复杂的过滤器,那么它可能是有可能的,但即使你没有使用alpha也是如此!正确的反应是钳制结果,将负数转换为0,将大于255的任何数字转换为255。
答案 1 :(得分:2)
根据您的链接中的建议,您在模糊之前预先乘法,并在模糊之后进行非预乘。在您的示例中,预乘实际上什么都不做,因为没有半透明像素。你做了模糊,然后你需要你做前期乘法(假设从0到1的标准化颜色值):
RGB' = RGB/A (if A is > 0)
A' = A
这将为您提供非预先模糊的最终图像。
答案 2 :(得分:0)
这两个答案在这里似乎都是错误的。
使用适当的混合模式,根据波特·达夫的说法,该模式是:
FG.RGB + (1.0 - FG.Alpha)*BG.RGB
不确定其余答案的来源,但哇。
alpha编码指示over操作。