如何计算两个32位颜色打包成一个整数的平均值?

3

我正在尝试将两种颜色平均。

我的原始(糟糕的)实现如下:

//color is a union
int ColorAverage(int c1, int c2) {
    color C1(c1);
    color C2(c2);
    return color(
        (unsigned char)(0.5f * C1.a + 0.5f * C2.a),
        (unsigned char)(0.5f * C1.r + 0.5f * C2.r),
        (unsigned char)(0.5f * C1.g + 0.5f * C2.g),
        (unsigned char)(0.5f * C1.b + 0.5f * C2.b)
    ).c;
}

目前我的解决方案如下(表现相当不错):

int ColorAverage(int c1, int c2) {
    unsigned char* b1 = reinterpret_cast<unsigned char*>(&c1);
    unsigned char* b2 = reinterpret_cast<unsigned char*>(&c2);
    int value;
    unsigned char* bv = reinterpret_cast<unsigned char*>(&value);
    bv[0] = (b1[0] + b2[0]) / 2;
    bv[1] = (b1[1] + b2[1]) / 2;
    bv[2] = (b1[2] + b2[2]) / 2;
    bv[3] = (b1[3] + b2[3]) / 2;
    return(value);
}

然而,它仍然相当缓慢(约为我的帧时间的3%)。
我找到了一个24位的解决方案,但它不适用于32位(alpha会丢失)。
#define AVERAGE(a, b)   ( ((((a) ^ (b)) & 0xfffefefeL) >> 1) + ((a) & (b)) )

http://www.compuphase.com/graphic/scale3.htm#HSIEH1

2个回答

5

尝试将您的掩码扩展到32位,就像这样:

#define AVERAGE(a, b)   ( ((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b)) )

编辑:我进行了快速检查,它似乎适用于我的测试案例。顺便说一句,公式不错!


4
目标是对整数的四个字节应用以下运算:
``` (a + b) / 2 = ((a ^ b) >> 1) + (a & b) ```
如果只是一个字节,右移一位会丢弃最右边的位。但在这种情况下,前三个字节的最右边的位不会被丢弃——它们被移动到相邻的字节中。需要牢记的原则是需要屏蔽每个字节的最后一位,以免在移位过程中“污染”相邻的字节。例如,假设 a ^ b 如下:
``` a XOR b = 1011 1101 1110 1001 ```
没有使用掩码的右移 1 位,结果如下:
``` (a XOR b) >> 1 = 0101 1110 1111 0100 ```
这是错误的。掩码将每个字节的最后一位清零,避免这种情况的发生:
``` (a XOR b) AND 0xfefefefe = 1010 1100 1110 1000 ```
然后可以安全地右移该值:
``` ((a XOR b) AND 0xfefefefe) = 0101 0110 0111 0100 ```
因此:
#define AVERAGE(a, b)   ( ((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b)) )

需要注意的一点是,C语言的运算符没有将算术右移与逻辑右移区分开。因此,您需要确保要移位的整数是无符号的,以防止实现特定的有符号整数位移操作。 编辑:我认为@dasblinkenlight可能已经比我回答得更好了。只要避免移动带符号整数,就应该没问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接