像素叠加透明度

时间:2017-08-18 08:05:52

标签: c++ image-processing overlay

我在B8G8R8A8(32)格式中有2个像素。 两个像素(顶部和底部)都具有透明度(Alpha通道<255)

在底部像素上覆盖顶部像素的方式(公式)是什么? (不使用第三方)。

我试图做这样的事情

struct FColor
{
public:
    // Variables.
#if PLATFORM_LITTLE_ENDIAN
    #ifdef _MSC_VER
        // Win32 x86
        union { struct{ uint8 B,G,R,A; }; uint32 AlignmentDummy; };
    #else
        // Linux x86, etc
        uint8 B GCC_ALIGN(4);
        uint8 G,R,A;
    #endif
#else // PLATFORM_LITTLE_ENDIAN
    union { struct{ uint8 A,R,G,B; }; uint32 AlignmentDummy; };
#endif
//...
};

FORCEINLINE FColor AlphaBlendColors(FColor pixel1, FColor pixel2)
{
    FColor blendedColor;
    //Calculate new Alpha:
    uint8 newAlpha = 0;
    newAlpha = pixel1.A + pixel2.A * (255 - pixel1.A);

    //get FColor as uint32
    uint32 colora = pixel1.DWColor();
    uint32 colorb = pixel2.DWColor();

    uint32 rb1 = ((0x100 - newAlpha) * (colora & 0xFF00FF)) >> 8;
    uint32 rb2 = (newAlpha * (colorb & 0xFF00FF)) >> 8;
    uint32 g1 = ((0x100 - newAlpha) * (colora & 0x00FF00)) >> 8;
    uint32 g2 = (newAlpha * (colorb & 0x00FF00)) >> 8;
    blendedColor = FColor(((rb1 | rb2) & 0xFF00FF) + ((g1 | g2) & 0x00FF00));


    blendedColor.A = newAlpha;
    return blendedColor;
}

但结果远不是我想要的: - )

我找了一些Alpha混合公式(我从来不知道如何计算叠加的新alpha) - &gt;也许我的方向错了?

编辑:

newAlpha更改为newAlpha = FMath::Min(pixel1.A + pixel2.A, 255); 实际上给出了一个更好的结果,但是这样计算它是对的吗?我在这里错过了什么吗?

基于接受的答案的工作示例)

   FORCEINLINE FColor AlphaBlendColors(FColor BottomPixel, FColor TopPixel)
{
    FColor blendedColor;
    //Calculate new Alpha:
    float normA1 = 0.003921568627451f * (TopPixel.A);
    float normA2 = 0.003921568627451f * (BottomPixel.A);

    uint8 newAlpha = (uint8)((normA1 + normA2 * (1.0f - normA1)) * 255.0f);

    if (newAlpha == 0)
    {
        return FColor(0,0,0,0);
    }

    //Going By Straight Alpha formula
    float dstCoef = normA2 * (1.0f - normA1);
    float multiplier = 255.0f / float(newAlpha);

    blendedColor.R = (uint8)((TopPixel.R * normA1 + BottomPixel.R * dstCoef) * multiplier);
    blendedColor.G = (uint8)((TopPixel.G * normA1 + BottomPixel.G * dstCoef) * multiplier);
    blendedColor.B = (uint8)((TopPixel.B * normA1 + BottomPixel.B * dstCoef) * multiplier);

    blendedColor.A = newAlpha;

    return blendedColor;
}

1 个答案:

答案 0 :(得分:1)

首先假设下面的第三个像素恰好是不透明的。

对于更多符号,我将假设alpha值在[0,1]中。

给定:三个像素,第一个像素在顶部,颜色c_1,c_2,c_3,alpha值a_1,a_2,a_3 = 1

然后得到的alpha值显然为1,颜色为

(a_1)*c_1 + (1-a_1)(*a_2)*c_2 + (1-a_1)*(1-a_2)*c_3

现在,我们想要找到一些值c_k,a_k,以便上面的公式等于

(a_k)*c_k + (1-a_k)*c_3

我们可以分两步解决这个问题:

(1-a_k) = (1-a_1)*(1-a_2)
->
a_k = 1-(1-a_1)*(1-a_2)

(a_k)*c_k = (a_1)*c_1 + (1-a_1)(*a_2)*c_2
->
c_k = [(a_1)*c_1 + (1-a_1)(*a_2)*c_2] / a_k

使用这些公式(对于您的Alpha值具有不同的范围),您将获得所需的颜色。

(别忘了抓住a_k = 0)

编辑:第三个像素的说明:

当你以任何方式使用你的两个像素时,这会导致它被用来显示某些东西,它们会被放在一些其他不透明的现有颜色上。例如,这可能是背景颜色,但也可能是某种颜色,这是在某些背景颜色上应用更多透明像素的结果。

我现在要做的是将两种颜色结合起来,找到一种颜色就像那两种颜色一样。也就是说,将它放在一些不透明的颜色之上应该与将原始的两种颜色放在它上面相同。这就是我对新颜色的要求,导致我使用的配方。

这个公式不过是在第三个颜色上连续应用两种颜色的结果。