如何在手动“叠加”混合操作中处理 alpha?

Posted

技术标签:

【中文标题】如何在手动“叠加”混合操作中处理 alpha?【英文标题】:How to handle alpha in a manual "Overlay" blend operation? 【发布时间】:2011-01-14 08:13:16 【问题描述】:

我正在使用一些手动(逐像素)图像处理,并且我正在重新创建标准的“叠加”混合。我在这里查看“Photoshop 数学”宏:

http://www.nathanm.com/photoshop-blending-math/ (See also here 更易读的 Overlay 版本)

两个源图像都采用相当标准的 RGBA(每个 8 位)格式,目标图像也是如此。当两个图像都完全不透明(alpha 为 1.0)时,结果会按预期正确混合:

但是,如果我的“混合”图层(顶部图像)具有透明度,那么对于 如何正确地将 alpha 因素纳入混合方程,我会感到有些困惑。我希望它能够工作,这样混合层中的透明像素对结果没有影响,混合层中的不透明像素正常进行覆盖混合,而半透明混合层像素对结果有一些缩放效果。

有人可以向我解释一下混合方程式或这样做背后的概念吗?

加分如果您能帮我做到这一点,以使生成的图像具有正确的预乘 alpha(我认为这只对两个图层中不透明的像素起作用。)

谢谢!

// factor in blendLayerA, (1-blendLayerA) somehow?
resultR = ChannelBlend_Overlay(baseLayerR, blendLayerR); 
resultG = ChannelBlend_Overlay(baseLayerG, blendLayerG);
resultB = ChannelBlend_Overlay(baseLayerB, blendLayerB);
resultA = 1.0; // also, what should this be??

【问题讨论】:

【参考方案1】:

混合基色和混合色后,使用混合色的 alpha 混合原始基色和混合产生的颜色:

vec4 baseColor = ...;
vec4 blendColor = ...;
vec4 blendedColor = blend(baseColor, blendColor);
vec4 fragmentColor = (1.0 - blendColor.a) * baseColor + blendColor.a * blendedColor;

我用它来“叠加”混合不透明的基色和具有大量(半)透明像素的混合纹理。

【讨论】:

【参考方案2】:

只是猜测,但我会尝试

resultA = 1 - (1-baseAlpha) * (1-blendAlpha)

【讨论】:

好的,这是什么原理?谢谢。 @quixoto 好吧,我想将两者相乘以使它们都在等式中,而不会在组合透明层时过早达到不透明度(添加它们时会发生这种情况)。但是简单地相乘会使它接近于零,其中一个接近于零。因此,我将整个事情颠倒过来,测试值(如 0、0.5、1)“感觉还可以”【参考方案3】:

我一直在试验这个问题,直到我发现最好的方法是让基础层和混合层都使用直接 alpha,然后只用基础 alpha 预乘结果。

【讨论】:

【参考方案4】:

这很好用,使用这里的公式:https://dev.w3.org/SVG/modules/compositing/master/。我的函数有点古怪,因为它接受一个 0-1 的 DoubleColor 和一个 0-maxValDouble() 的 T* 像素颜色(这是使用的整数类型的最大 val,作为双精度)。

template<typename T> static inline void blendColorOverlay(T* rgba, DoubleColor overColor) 
    if (overColor.a == 0)
        return;
    
    double Da = rgba[3]/maxValDouble<T>();
    double Sa = overColor[3];
    double Dca, Sca;
    
    double outAlpha = (Sa + Da - Sa*Da);
    
    for (int k = 0; k < 3; k++) 
        Dca = (rgba[k]/maxValDouble<T>())*Da;
        Sca = overColor[k]*Sa;
        if (2*Dca <= Da)
            rgba[k] = (2*Sca*Dca + Sca*(1.0 - Da) + Dca*(1.0 - Sa))*maxValDouble<T>()/outAlpha;
        else
            rgba[k] = (Sca*(1.0 + Da) + Dca*(1.0 + Sa) - 2.0*Dca*Sca - Da*Sa)*maxValDouble<T>()/outAlpha;
        
        
    rgba[3] = outAlpha*maxValDouble<T>();
    

【讨论】:

以上是关于如何在手动“叠加”混合操作中处理 alpha?的主要内容,如果未能解决你的问题,请参考以下文章

如何在视频之上叠加不同的 Alpha 通道动画?

如何在 SDL 中进行硬件加速 Alpha 混合?

使用 alpha 混合组件合成纹理

UIImage 混合模式问题

android:如何像 Photoshop 一样创建叠加混合?

如何将两个 m4a 音频文件“混合/叠加”在一起