由于alpha值,将一张图像融合到另一张图像上会产生错误的图像

时间:2018-08-02 06:21:17

标签: c++ image-processing

因此,我遇到了将两个图像混合在一起以解决透明度问题。我在这里使用freetype来生成字形。我有一个相当大的代码库,所以我挑选了混合过程中涉及的大部分代码。

这是我正在使用的代码:

void TopDown(FT_Bitmap *bitmap, ... )
{
        .....
        .....

        for (int srcY=0; srcY < bitmap->rows; srcY++, destLine += textureWidth, srcLine += bitmap->pitch)
        {
            unsigned char *currSrc = srcLine;
            unsigned int *currDest = destLine;
            for (int srcX=0; srcX < bitmap->width; srcX++, currSrc++)
            {
                unsigned char alpha = *currSrc * textA / 255;
                if (currDest >= dest && currDest < destMax)
                {
                    unsigned int destR = (textR * alpha + bgR * (255-alpha))/255;
                    unsigned int destG = (textG * alpha + bgG * (255-alpha))/255;
                    unsigned int destB = (textB * alpha + bgB * (255-alpha))/255;

                    unsigned int as = alpha;
                    *currDest = makeColor(destR, destG, destB, alpha);
                }
                currDest++;
            }
        }
}

1 个答案:

答案 0 :(得分:0)

让此行unsigned char alpha = *currSrc * textA / 255分成两行:

unsigned char alpha = *currSrc;
alpha = alpha * textA / 255;

这实际上是红色部分。您必须跳过3个字节才能获得alpha值:

unsigned char alpha = *currSrc + 3;
alpha = alpha * textA / 255;

您实际上并不需要。只需找到所有黑色像素并将其alpha值设置为零即可。确保文本颜色不是黑色。您可以使用0x00000001来设置文本颜色,这会将其与黑色背景区分开。

void TopDown(...)
{
    ...
    for(...)
    {
        ...
        for(...)
        {
            ...
            unsigned char r = *currSrc + 0;
            unsigned char g = *currSrc + 1;
            unsigned char b = *currSrc + 2;
            unsigned char alpha = 128; //or 255 or whatever
            if(currDest >= dest && currDest < destMax)
            {
                if(r || g || b)
                {
                    //non-black pixels get alpha value
                    *currDest = makeColor(r, g, b, alpha);
                }
                else
                {
                    //black pixels get zero alpha
                    *currDest = 0;
                }
            }
            currDest++;
        }
    }
}

现在,您只需要绘制背景位图即可。如果使用正确的绘画功能,则无需混合。背景将显示为透明。手动混合颜色:

unsigned char blend2(unsigned char m, unsigned char n, unsigned char alpha)
{
    float i = (float)n;
    float j = (float)m;
    float a = (float)alpha;

    j *= a / 255.0f; //you can skip this step

    int color = (int)((i + j)/2);
    return (unsigned char)color;
}

void blendBitmap(...)
{
    ...
    for (int line=0; line < copyHeight; line++)
    {
        T *destPtr = destBitmap->line(line+destRow) + 4*destCol;
        unsigned char *sourcePtr = sourceBitmap->line(line+srcRow) + 4*srcCol;
        if(destPtr && sourcePtr)
        {
            for (int col=0; col < copyWidth; col++, destPtr += 4, sourcePtr += 4)
            {
                unsigned char alpha = sourcePtr[3];
                destPtr[0] = blend2(destPtr[0], sourcePtr[0], alpha);
                destPtr[1] = blend2(destPtr[1], sourcePtr[1], alpha);
                destPtr[2] = blend2(destPtr[2], sourcePtr[2], alpha);
            }
        }
    }
}