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

发布于 2024-10-11 16:15:54 字数 955 浏览 8 评论 0原文

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

http://www.nathanm.com /photoshop-混合-数学/另请参阅此处以获取更易读的叠加版本)

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

但是如果我的“混合”层(顶部图像)具有透明度,我会有点困惑如何正确地将 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??

I'm playing with some manual (walk-the-pixels) image processing, and I'm recreating the standard "overlay" blend. I'm looking at the "Photoshop math" macros here:

http://www.nathanm.com/photoshop-blending-math/
(See also here for more readable version of Overlay)

Both source images are in fairly standard RGBA (8 bits each) format, as is the destination. When both images are fully opaque (alpha is 1.0), the result is blended correctly as expected:

But if my "blend" layer (the top image) has transparency in it, I'm a little flummoxed as to how to factor that alpha into the blending equation correctly. I expect it to work such that transparent pixels in the blend layer have no effect on the result, opaque pixels in the blend layer do the overlay blend as normal, and semitransparent blend layer pixels have some scaled effect on the result.

Can someone explain to me the blend equations or the concept behind doing this?

Bonus points if you can help me do it such that the resulting image has correctly premultiplied alpha (which only comes into play for pixels that are not opaque in both layers, I think.)

Thanks!

// 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??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

行至春深 2024-10-18 16:15:54

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

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

我用它来“叠加”混合不透明基色和混合纹理,其中有很多(半)透明像素。

After blending the base color and the blend color, mix the original base color and the color resulting from the blending using the alpha of the blend color:

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

I use this for "overlay" blending an opaque base color and a blend texture which has a lot of (semi) transparent pixels.

记忆で 2024-10-18 16:15:54

只是猜测,但我会尝试

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

Just a guess, but I would try

resultA = 1 - (1-baseAlpha) * (1-blendAlpha)
Spring初心 2024-10-18 16:15:54

使用这里的公式,效果很好: 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>();
    }

This works great, using formula from here: https://dev.w3.org/SVG/modules/compositing/master/. My function is a bit funky because it takes in a DoubleColor which is 0-1, and a T* pixel color which is 0-maxValDouble() (which is the max val of the integer type being used, as a double).

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>();
    }
亣腦蒛氧 2024-10-18 16:15:54

我正在精确地尝试这个问题,直到我发现最好的方法是让基础层和混合层都具有直接 Alpha,然后仅将结果与基础 Alpha 进行预乘。

I was experimenting with this issue exactly, until I found out that the best is to have the base and the blend layer both with straight alpha, then premultiply only the result with the base alpha.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文