Math 如何使用位运算符使ARGB透明

Math 如何使用位运算符使ARGB透明,math,colors,transparency,alphablending,Math,Colors,Transparency,Alphablending,我需要透明,有2个像素: pixel1:{A,R,G,B}-前景像素 像素2:{A,R,G,B}-背景像素 A、 R、G、B是字节值 每个颜色由字节值表示 现在我将透明度计算为: newR=pixel2\u R*alpha/255+pixel1\u R*(255-alpha)/255 newG=pixel2_G*alpha/255+pixel1_G*(255-alpha)/255 newB=pixel2_B*alpha/255+pixel1_B*(255-alpha)/255 但是它太慢了 我需

我需要透明,有2个像素:

pixel1:{A,R,G,B}-前景像素
像素2:{A,R,G,B}-背景像素

A、 R、G、B是字节值

每个颜色由字节值表示

现在我将透明度计算为:

newR=pixel2\u R*alpha/255+pixel1\u R*(255-alpha)/255
newG=pixel2_G*alpha/255+pixel1_G*(255-alpha)/255
newB=pixel2_B*alpha/255+pixel1_B*(255-alpha)/255

但是它太慢了 我需要使用位运算符(和,或,异或,求反,位移动

我想在WindowsPhone7XNA上做这件事

---附件C#代码---

公共静态uint GetPixelForOpacity(uint reduceOpacityLevel、uint pixelBackground、uint pixelForeground、uint pixelCanvasAlpha)
{
字节表面处理程序=(字节)((像素前景&0x00FF0000)>>16);
字节surfaceG=(字节)((像素前景&0x0000FF00)>>8);
字节surfaceB=(字节)((像素前景&0x000000FF));
字节源R=(字节)((像素背景&0x00FF0000)>>16);
字节源G=(字节)((像素背景&0x0000FF00)>>8);
字节源B=(字节)((像素背景&0x000000FF));
uint newR=sourceR*像素canvasalpha/256+表面处理*(255-像素canvasalpha)/256;
uint newG=sourceG*像素canvasalpha/256+surfaceG*(255-像素canvasalpha)/256;
uint newB=sourceB*像素canvasalpha/256+surfaceB*(255-像素canvasalpha)/256;

return(uint)255我不认为仅使用这些运算符就可以达到相同的精度。我认为,您最好的选择是使用LUT(只要LUT可以放入CPU缓存,否则可能会更慢)

//分配LUT(64KB)
无符号字符lut[256*256]\uuuuuu cacheline\u aligned;//\uuuuu cacheline\u aligned是一个GCC ism
//宏来访问LUT
#定义LUT(像素,α)(LUT[(α)*256+(像素)])
//预先计算LUT

对于(int alpha_value=0;alpha_value),不能仅使用逐位运算进行8位alpha混合,除非基本上用基本运算(8移位加法)重新发明乘法

您可以使用其他答案中提到的两种方法:使用256而不是255,或者使用查找表。这两种方法都有问题,但您可以缓解它们。这实际上取决于您使用的体系结构:乘法、除法、移位、加法和内存加载的相对速度。在任何情况下:

查找表:一个普通的256x256查找表是64KB。这会使您的数据缓存变得非常慢。除非您的CPU有一个非常慢的乘法器,但有低延迟RAM,否则我不建议这样做。您可以通过丢弃一些alpha位(例如a>>3)来提高性能,从而产生32x256=8KB的查找,这具有更好的性能在缓存中安装的机会


使用256而不是255:被256除的想法只是一个右移8。这将稍微偏离,并倾向于向下取整,使图像稍微变暗,例如,如果R=255,a=255,那么(R*a)/256=254。你可以稍微作弊一下,然后这样做:(R*a+R+a)/256或只是(R*a+R)/256或(R*a+a)/256=255。或者,先将a缩放到0..256,例如:a=(256*a)/255.这只是一个昂贵的除法255,而不是6。然后,(R*A)/256=255。

您还可以计算出255除法(这是昂贵的)@aaa除法仅在LUT创建期间进行,因此几乎不昂贵。实际上,甚至可以在编译时进行…(即将LUT存储为静态数组)64KB的查找表由于缓存抖动而昂贵。这比我所知道的所有移动电话平台中的一级缓存都要大。@John实际上,这取决于alpha在整个循环中是否是常量。如果是常量,则只需要512字节的缓存。嗯,问题是每像素alpha显示一次,但公式只使用了“alpha”两次,这意味着cates不是。你是对的-如果它是常数alpha,那么最坏情况下,你缓存256字节的未命中,这算不了什么。用移位代替除法是个坏主意。
((无符号字符)a)>>8
将是0,而与
a
的值无关。除非您开始使用16位整数。此外,计算中到处都有整数溢出,例如R=255,a=255,R*a/256=0(因为255*255=1 mod 256)。如果您仅限于8位运算,则无法执行任何操作。使用(R*a+R+a)的方法/256适合16位。将alpha扩展到256的方法也适合16位。问题中的示例假设大于8位的中间值,因此我认为使用它是可以的。我同意John的观点。大多数处理器/编译器使用16/32位结果,即使源操作数为8位,因此建议非常好。在x86 pro中cessor,如果您在汇编中编写此代码,您甚至可以完全免费获得256除法,因为结果只是挂在AH寄存器中-您甚至不必对其进行位移位!将除法形式255更改为256大大改进了代码。在调试模式下,8 FPS到14 FPS的除法速度。
    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;
    }
// 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);