Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Optimization 这种在颜色组件上并行工作的颜色混合技巧是如何工作的?_Optimization_Language Agnostic_Bit Manipulation_Color Blending_Swar - Fatal编程技术网

Optimization 这种在颜色组件上并行工作的颜色混合技巧是如何工作的?

Optimization 这种在颜色组件上并行工作的颜色混合技巧是如何工作的?,optimization,language-agnostic,bit-manipulation,color-blending,swar,Optimization,Language Agnostic,Bit Manipulation,Color Blending,Swar,我看到这段Java代码在两种RGB888颜色之间实现了50%的完美混合,效率极高: publicstaticintblendrgb(inta,intb){ 返回(a+b-((a^b)&0x0000101))>>1; } 这显然相当于单独提取和平均通道。大概是这样的: public static int blendRGB(int a,int b){ int aR=a>>16; int bR=b>>16; int aG=(a>>8)&0xFF; int bG=(b>>8)&0xFF; int aB

我看到这段Java代码在两种RGB888颜色之间实现了50%的完美混合,效率极高:

publicstaticintblendrgb(inta,intb){
返回(a+b-((a^b)&0x0000101))>>1;
}
这显然相当于单独提取和平均通道。大概是这样的:

public static int blendRGB(int a,int b){
int aR=a>>16;
int bR=b>>16;
int aG=(a>>8)&0xFF;
int bG=(b>>8)&0xFF;
int aB=a&0xFF;
int bB=b&0xFF;
int cR=(aR+bR)>>1;
int cG=(aG+bG)>>1;
int cB=(aB+bB)>>1;
return(cR
(a^b)&0x00010101
是如果没有进位来自右侧,通道的最低有效位在
a+b
中的值

从总和中减去它可以保证移入下一个通道的最高有效位的位只是该通道的进位,不受该通道的污染。当然,这也意味着该通道不再受下一个通道进位的影响

另一种方法是,有效地改变输入,使所有通道的和都相等。进位很好地进入最低有效位(零,因为偶数),而不干扰任何东西。当然,它实际上做的是另一种方式,首先它只是对它们求和,然后才确保对所有通道求和是均匀的。但顺序并不重要

更具体地说,有4种情况(在应用下一个通道的进位之前):

  • 一个通道的lsb为0,并且没有来自下一个通道的进位
  • 一个通道的lsb为0,并且存在来自下一个通道的进位
  • 一个通道的lsb为1,并且没有来自下一个通道的进位
  • 一个通道的lsb为1,并且存在来自下一个通道的进位
  • 前两种情况很简单,移位将携带的位放回它所属的通道,它是0还是1都无关紧要

    案例3更有趣。如果lsb为1,这意味着移位会将该位移到下一个通道的最高有效位。这很糟糕。该位必须以某种方式取消设置-但你不能仅仅掩盖它,因为你可能在案例4中

    案例4是最有趣的。如果lsb为1,并且该位中有进位,它将滚动到0,进位被传播。这不能通过掩蔽撤消,但可以通过反转过程来撤消,即从lsb中减去1(这将使其返回到1,并撤消传播进位造成的任何损坏)

    如您所见,在案例3和案例4中,治疗方法都是从lsb中减去1,而在这些案例中,lsb真的希望为1(尽管由于下一个通道的进位,它可能不再是了),并且在案例1和案例2中,您不必做任何事情(换句话说,减去0)。这正好对应于减去“如果右边没有进位,lsb应该在
    a+b
    中”

    此外,蓝色通道只能分为情况1或3(没有下一个通道可以携带),移位将丢弃该位,而不是将其放入下一个通道(因为没有)。因此,您也可以写入(注意,掩码丢失了最低有效值1)

    不过,这并没有什么区别

    要使其适用于argb888,您可以切换到良好的旧“SWAR平均值”:


    这是定义加法的递归方法的一个变体:
    x+y=(x^y)+((x&y)我必须处理很多我从同事那里继承下来的旧代码……他们中的一些人喜欢类似于第一个代码块的代码,而另一些人则喜欢类似于第二个代码块的代码——我必须承认,当我发现这些较长的代码片段时,我非常感激,因为它们更易于阅读!所以无论何时编写代码(甚至正确地)被另一个读到了,请使用那些“更长”的代码!我理解你的第一行,但不理解它的其余部分。@Boann好的,我添加了一些解释,现在更好了吗?谢谢,我现在明白了。你说“下一个频道”时让我感到震惊的是"我原以为你指的是左边的那个,但你指的是右边的那个。现在我看到原始代码实际上有一个微妙的错误:最好的掩码不是
    0x00010101
    0x00001000
    ,而是
    0x01010100
    。有了这个更改,如果低阿尔法位不为零,红色通道就不再被破坏。它仍然不会恢复正常正确地将上8位置位,但至少它不介意它们是否被设置。@Boann为了公平起见,名称和描述暗示它期望的是RGB888,而不是argB888。混合两个argB888有点棘手,因为a通道的执行消失了,但这是可行的。@harold:我想使用
    long
    作为中间分辨率ARGB的ult是最快的方法,至少在64位JVM上是这样。但是,无论如何,平均两个ARGB值没有意义;您需要一个加权和或任何东西。
    public static int blendRGB(int a, int b) {
        return (a + b - ((a ^ b) & 0x00010100)) >> 1;
    }
    
    // channel-by-channel average, no alpha blending
    public static int blendARGB(int a, int b) {
        return (a & b) + (((a ^ b) & 0xFEFEFEFE) >>> 1);
    }