为何IPP Alpha混合在透明背景下返回错误结果?
IPP库Alpha混合结果异常问题
我用Intel IPP库替换项目中的自定义Alpha混合函数,速度提升了15-20%,但发现结果图像存在错误——当把图像混合到全透明背景时,输出颜色不符合预期。为此我写了一个测试示例来复现问题:
测试代码
inline void alphaBlend(unsigned char * baseColor, unsigned char * targetColor) { // 原始算法(R、G、B为0-255的浮点数,A为0-1的浮点数) // // float newAlpha = (1 - targetColor.A) * baseColor.A + targetColor.A; // baseColor.R = ((1 - targetColor.A) * baseColor.A * baseColor.R + targetColor.A * targetColor.R) / newAlpha; // baseColor.G = ((1 - targetColor.A) * baseColor.A * baseColor.G + targetColor.A * targetColor.G) / newAlpha; // baseColor.B = ((1 - targetColor.A) * baseColor.A * baseColor.B + targetColor.A * targetColor.B) / newAlpha; // // 以下代码是将上述算法转换为0-255范围的无符号整数RGBA格式 // 将A替换为(A/255),并优化公式以减少除法操作,确保运算在无符号整数范围内 // 使用移位操作替代除以/乘以255(不完全等价,但误差可接受) unsigned int bA = baseColor[3]; unsigned int bR = baseColor[2]; unsigned int bG = baseColor[1]; unsigned int bB = baseColor[0]; unsigned int tA = targetColor[3]; unsigned int tR = targetColor[2]; unsigned int tG = targetColor[1]; unsigned int tB = targetColor[0]; unsigned int a = (((bA + tA) << 8) - tA * bA) >> 8; if (a > 0) { unsigned int divisor = a << 8; unsigned int baseAR = bA * bR; baseColor[2] = (((tA * tR + baseAR) << 8) - (baseAR * tA)) / divisor; unsigned int baseAG = bA * bG; baseColor[1] = (((tA * tG + baseAG) << 8) - (baseAG * tA)) / divisor; unsigned int baseAB = bA * bB; baseColor[0] = (((tA * tB + baseAB) << 8) - (baseAB * tA)) / divisor; baseColor[3] = a; } else { baseColor[2] = 0; baseColor[1] = 0; baseColor[0] = 0; baseColor[3] = 0; } } void displayBackground(unsigned char* background) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { printf("%d ", background[i * 4 + j]); } printf("\r\n"); } } int main(int argc, char * argv[]) { unsigned char* background = new unsigned char[4 * 4]; unsigned char* image = new unsigned char[4 * 4]; image[0 * 4 + 0] = 0; image[0 * 4 + 1] = 0; image[0 * 4 + 2] = 255; image[0 * 4 + 3] = 255; image[1 * 4 + 0] = 0; image[1 * 4 + 1] = 0; image[1 * 4 + 2] = 255; image[1 * 4 + 3] = 192; image[2 * 4 + 0] = 0; image[2 * 4 + 1] = 0; image[2 * 4 + 2] = 255; image[2 * 4 + 3] = 128; image[3 * 4 + 0] = 0; image[3 * 4 + 1] = 0; image[3 * 4 + 2] = 255; image[3 * 4 + 3] = 32; // IPP测试 memset(background, 0, 4 * 4); IppiSize size; size.width = 2; size.height = 2; ippiAlphaComp_8u_AC4IR(image, 8, background, 8, size, ippAlphaOver); printf("IPP:\n"); displayBackground(background); // 手动实现测试 memset(background, 0, 4 * 4); for (int i = 0; i < 4; i++) alphaBlend(background + i * 4, image + i * 4); printf("Manual:\n"); displayBackground(background); delete[] background; delete[] image; getchar(); }
测试场景说明
测试中,我将包含四个不同Alpha值的红色像素(Windows位图BGRA格式)混合到全透明背景(RGBA均为0)中。
测试结果
IPP输出结果:
IPP: 0 0 255 255 0 0 192 192 0 0 128 128 0 0 32 32
手动实现(基于标准Alpha合成公式)的输出结果:
Manual: 0 0 255 255 0 0 255 192 0 0 255 128 0 0 255 32
公式差异对比
IPP使用的Alpha混合公式:
颜色分量: αA * A + (1 - αA) * αB * B
Alpha通道: αA + (1 - αA) * αB
而我采用的标准Alpha合成公式:
Alpha通道: αA + αB * (1 - αA)
颜色分量: (A * αA + B * αB * (1 - αA)) / αO
注:其中αO是混合后的Alpha值,即αO = αA + αB*(1-αA)
疑问
为什么IPP的颜色分量公式缺少除以αO的步骤?如何用IPP正确实现符合标准的半透明图像Alpha混合?
内容的提问来源于stack exchange,提问作者Spook
相关产品推荐
相关产品推荐

