有效地预乘图像alpha

时间:2017-10-18 07:21:43

标签: 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;
    }
}

1 个答案:

答案 0 :(得分:3)

鉴于您的argb组件为unsigned char,您可以通过将浮点乘法转换为整数乘法来提高性能使用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 struct作为像素数据:

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的倍数,那么即使没有额外的检查,您也可以这样做。