2011-03-17 73 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