2011-12-09 53 views
3

我想平均兩種顏色。你會如何平均兩個32位顏色打包成一個整數?

我原來的(恐怖)實施如下:

//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位(阿爾法丟失):

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

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

回答

5

試試你的面具擴展到32位,這樣的:

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

編輯:我做了一個快速檢查,它似乎適用於我的測試用例。順便說一句好的公式!

4

目標是採取以下動作:

(A + B)/ 2 =((A^B)>> 1)+(一個& B)

而將其應用於整數的所有四個字節。如果這只是一個字節,那麼右移一位將丟棄最右邊的位。但是,在這種情況下,前3個字節的最右側位不會被丟棄 - 它會被移入相鄰的字節。記住的想法是,你需要掩碼每個字節的最後一位,以便它不會在移位期間「污染」相鄰字節。例如,假設一個^ B是這樣的:

一個XOR B = 1011 1101 1110 1001

1個比特的右移,沒有掩模,看起來像這樣:

(一個XOR b)>> 1 = 0101 1110 1111 0100

哪個是錯誤的。面具零的出每個字節的最後一位,因此不會發生這種情況:

(一XOR b)通過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並沒有區分算術右移和邏輯右移與其運算符。你需要確保你正在移動的整數是無符號的,至prevent implementation-specific signed-integer shift voodoo

編輯:我認爲@dasblinkenlight可能擊敗了我這個答案。只要小心轉移有符號整數,你應該很好。

相關問題