c - 有效地预乘图像 Alpha

标签 c image-processing optimization graphics cairo

将 32 位图像加载到缓冲区中,然后将颜色值与相应的 Alpha 值相乘以用于混合。

以下方法有效,但我想知道是否有更有效的方法来做到这一点,即使它只能产生足够好的近似值?

图像数据是这种类型的指针:

typedef struct rgba_pixel
{
    uint8_t r;
    uint8_t g;
    uint8_t b;
    uint8_t a;
} rgba_pixel;

rgba_pixel * image_data;

for ( i = 0; i < length; i++ )
{
    if ( image_data[i].a == 0 )
        image_data[i].r = image_data[i].g = image_data[i].b = 0;
    else if ( image_data[i].a < 255 )
    {
        alpha_factor = image_data[i].a / 255.0;
        image_data[i].r = image_data[i].r * alpha_factor;
        image_data[i].g = image_data[i].g * alpha_factor;
        image_data[i].b = image_data[i].b * alpha_factor;
    }
}

最佳答案

假设您的 argb 组件是 unsigned char code>,您可以通过将浮点乘法转换为整数乘法并使用 shr​​ 8(除以 256)而不是除以 255 来提高性能:

for ( i = 0; i < length; i++ )
{
    if ( image_data[i].a == 0 )
        image_data[i].r = image_data[i].g = image_data[i].b = 0;
    else if ( image_data[i].a < 255 ) 
    {
        image_data[i].r = (unsigned short)image_data[i].r * image_data[i].a >> 8;
        image_data[i].g = (unsigned short)image_data[i].g * image_data[i].a >> 8;
        image_data[i].b = (unsigned short)image_data[i].b * image_data[i].a >> 8;
    }
}

这会将 1 fp 除法和 3 fp 乘法转换为 3 个整数乘法和 3 个位移位。

另一个可以完成的改进是对像素数据使用 union 结构:

typedef union rgba_pixel
{
    struct {
        uint8_t r;
        uint8_t g;
        uint8_t b;
        uint8_t a;
    };

    uint32_t u32;
} rgba_pixel;

然后一次将零分配给 r、g 和 b:

//image_data[i].r = image_data[i].g = image_data[i].b = 0; 
image_data[i].u32 = 0; //use this instead

根据https://godbolt.org/对于 x86-64 gcc 7.2,后者在 -O3 处生成的指令较少。当然,这在实践中可能会更快,也可能不会更快。

要考虑的另一件事是部分循环展开,即每次循环迭代处理多个(例如 4)像素。如果您保证行的宽度是 4 的倍数,那么即使没有额外的检查,您也可以这样做。

关于c - 有效地预乘图像 Alpha,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46804751/

相关文章:

python - 在3.4.2.0(Python 3)以上的cv2版本上使用SIFT算法

string - 数字和可被 6 整除的子序列

python - Redis内存优化

c - f 打开文件并跳过字符

c - OpenCL 在 GPU 上同时解决两个不同大小的问题

c - Z3 与 Craig 插值 (iz3)

opencv - (opencv) imread 与 CV_LOAD_IMAGE_GRAYSCALE 产生 4 channel 垫

MATLAB - 合并子矩阵

java - 为什么 Hibernate 有时会忽略 FetchMode.JOIN?

c 中从格式化流 I/O 更改为直接 I/O