2011-03-17 104 views
3

我需要透明度使ARGB透明度,具有2個像素:如何使用按位運算符

pixel1: {A, R, G, B} - foreground pixel
pixel2: {A, R, G, B} - background pixel

A,R,G,B是字節值

每個顏色由字節表示的值

現在我計算透明度:

newR = pixel2_R * alpha/255 + pixel1_R * (255 - alpha)/255
newG = pixel2_G * alpha/255 + pixel1_G * (255 - alpha)/255
newB = pixel2_B * alpha/255 + pixel1_B * (255 - alpha)/255

,但實在是太慢了 我需要位運算符(AND,OR,XOR,否定,BIT MOVE)做

我想這樣做,在Windows Phone 7 XNA

- - 附帶的C#代碼---

public static uint GetPixelForOpacity(uint reduceOpacityLevel, uint pixelBackground, uint pixelForeground, uint pixelCanvasAlpha) 
    { 
     byte surfaceR = (byte)((pixelForeground & 0x00FF0000) >> 16); 
     byte surfaceG = (byte)((pixelForeground & 0x0000FF00) >> 8); 
     byte surfaceB = (byte)((pixelForeground & 0x000000FF)); 

     byte sourceR = (byte)((pixelBackground & 0x00FF0000) >> 16); 
     byte sourceG = (byte)((pixelBackground & 0x0000FF00) >> 8); 
     byte sourceB = (byte)((pixelBackground & 0x000000FF)); 

     uint newR = sourceR * pixelCanvasAlpha/256 + surfaceR * (255 - pixelCanvasAlpha)/256; 
     uint newG = sourceG * pixelCanvasAlpha/256 + surfaceG * (255 - pixelCanvasAlpha)/256; 
     uint newB = sourceB * pixelCanvasAlpha/256 + surfaceB * (255 - pixelCanvasAlpha)/256; 

     return (uint)255 << 24 | newR << 16 | newG << 8 | newB; 
    } 
+0

將分割形式255更改爲256改進了很多代碼。調試模式下8 FPS至14 FPS。 – 2011-03-17 09:24:22

回答

3

除非您基本上重新設計了與基本運算(8位移相加)的乘法運算,否則不能使用按位運算進行8位α混合。

您可以按照其他答案中提到的方法執行兩種方法:使用256而不是255,或使用查找表。兩者都有問題,但你可以緩解它們。這真的取決於你在做什麼架構:乘法,除法,移位,加法和內存加載的相對速度。在任何情況下:

查找表:一個普通的25​​6x256查找表是64KB。這會甩掉你的數據緩存並最終變得非常慢。我不會推薦它,除非你的CPU有一個非常慢的乘法器,但是有低延遲RAM。您可以通過丟棄一些阿爾法位來提高性能,例如A >> 3,從而導致32x256 = 8KB的查找,這更有可能適合緩存。

使用256而不是255:被256除的想法只是右移8位。這將略微偏離並趨於向下舍入,稍微變暗圖像,例如如果R = 255,則A = 255則(R * A + R)/ 256或者只是(R * A + R)/ 256或(R * A + A)/ 256 = 254.您可以使用作弊 )/ 256 = 255。或者,首先將A縮放到0..256,例如:A =(256 * A)/ 255。這只是一個昂貴的255分而不是6.然後,(R * A)/ 256 = 255。

+0

使用移位而不是劃分是一個壞主意。 '((無符號字符)a)>> 8'將不分爲'a'的值。除非你開始使用16位整數。 – CAFxX 2011-03-17 08:43:09

+0

另外,計算中無處不在整數溢出,例如R = 255,A = 255,R * A/256 = 0(因爲255 * 255 = 1 mod 256) – CAFxX 2011-03-17 08:48:48

+0

如果僅限於8位操作,則不能執行任何操作。使用(R * A + R + A)/ 256的方法適合於16位。將alpha縮放到256的方法也適用於16位。問題中的例子假定大於8位中間值,所以我認爲可以使用它。 – 2011-03-17 08:51:42

0

我不認爲它可以使用只有那些運算符以相同的精度完成。最好的辦法是,我認爲,使用LUT(只要LUT可以容納在CPU緩存,否則甚至可能會更慢)

// allocate the LUT (64KB) 
unsigned char lut[256*256] __cacheline_aligned; // __cacheline_aligned is a GCC-ism 

// macro to access the LUT 
#define LUT(pixel, alpha) (lut[(alpha)*256+(pixel)]) 

// precompute the LUT 
for (int alpha_value=0; alpha_value<256; alpha_value++) { 
    for (int pixel_value=0; pixel_value<256; pixel_value++) { 
    LUT(pixel_value, alpha_value) = (unsigned char)((double)(pixel_value) * (double)(alpha_value)/255.0)); 
    } 
} 

// in the loop 
unsigned char ialpha = 255-alpha; 
newR = LUT(pixel2_R, alpha) + LUT(pixel1_R, ialpha); 
newG = LUT(pixel2_G, alpha) + LUT(pixel1_G, ialpha); 
newB = LUT(pixel2_B, alpha) + LUT(pixel1_B, ialpha); 

否則你應該嘗試向量化你的代碼。但要做到這一點,您至少應該爲我們提供有關CPU架構和編譯器的更多信息。請記住,如果提供了正確的選項,編譯器可能會自動進行矢量化。

+0

你也可以分解255個分區(這是昂貴的) – Anycorn 2011-03-17 08:29:04

+0

@aaa這個分區只在創建LUT時完成,所以它幾乎沒有代價。實際上,它甚至可以在編譯時完成......(即,將LUT作爲靜態數組存儲) – CAFxX 2011-03-17 08:32:04

+0

由於緩存顛簸,64KB查找表很昂貴。這比我所知道的所有手機平臺上的L1緩存都要大。 – 2011-03-17 08:37:00