最快、最简单的平均ARGB颜色整数的方法是什么?

4

我有五个颜色以无符号整数的形式存储,格式为#AARRGGBB,我需要计算这五个颜色的平均值。显然,我不能简单地将每个整数除以五并相加,目前我想到的唯一方法是对它们进行位掩码操作,分别处理每个通道,然后再将它们合并。是否有更聪明或更简洁的方法来计算这五个颜色的平均值?


“纯红色和纯绿色的‘平均值’是暗黄色,对吧?” - AakashM
当然是。他正在计算ARGB的平均值,而不是HSV的。 - Dave Gamble
4个回答

3

在你(OP)提出的解决方案和Patrick的解决方案之间,有一个看起来相当不错的折中方案:

Color colors[5]={ 0xAARRGGBB,...};

unsigned long sum1=0,sum2=0;
for (int i=0;i<5;i++)
{
  sum1+= colors[i]    &0x00FF00FF; // 0x00RR00BB
  sum2+=(colors[i]>>8)&0x00FF00FF; // 0x00AA00GG
}
unsigned long output=0;
output|=(((sum1&0xFFFF)/5)&0xFF);
output|=(((sum2&0xFFFF)/5)&0xFF)<<8;
sum1>>=16;sum2>>=16; // and now the top halves
output|=(((sum1&0xFFFF)/5)&0xFF)<<16;
output|=(((sum2&0xFFFF)/5)&0xFF)<<24;

我认为你不能真正地将sum1/sum2除以5,因为来自上半部分的位会溢出... 如果一个近似值是有效的,你可以尝试乘以像0.1875(0.125+0.0625)这样的值(这意味着:乘以3并向下移动4个位置。这可以通过位掩码和小心处理来完成。)问题是,0.2有一个很差的二进制表示,所以乘以它是很麻烦的。像往常一样,精度或速度。由你选择。

2

如果您使用至少支持SSE的x86机器,且仅需要近似值,则可以使用汇编指令PAVGB(打包平均字节)来计算平均值。请参见http://www.tommesani.com/SSEPrimer.html以了解更多信息。

由于您有5个值,因此需要在调用PAVGB时进行创意,因为PAVGB一次只能处理两个值。


1

我找到了一个聪明的解决方案,但遗憾的是它只适用于颜色数量为2的幂次方。我将在两种颜色的情况下展示它:

mask = 01010101

pom = ~(a^b & mask) # ^ means xor here, ~ negation

a = a & pom
b = b & pom

avg = (a+b) >> 1

这种方法的诀窍在于——当你计算平均值时,总和的LSB(在两个数字的情况下)没有意义,因为它将在除法中被舍弃(当然,我们在这里讨论整数)。在您的问题中,部分和的LSB与相邻颜色的和的进位位同时出现。假设每个颜色和的LSB都是0,则可以安全地添加这两个整数——加法不会互相干扰。位移将每个颜色除以二。

这种方法也可以用于4种颜色,但是您必须实现找出由每种颜色的最后两位组成的数字之和的进位标志。也可以省略此部分,并将每种颜色的最后两位变为零——忽略此部分的最大错误是每个分量为1。


0
编辑 我将保留这个尝试,但请注意它是不正确的,不能正常工作。
你可以采用一种“聪明”的方法,即在组件之间插入零,解析为无符号长整型,求出数字的平均值,转换回十六进制字符串,删除零,最后解析为无符号整型。
例如,将 #AARRGGBB 转换为 #AA00RR00GG00BB。
这种方法涉及到解析和字符串操作,因此肯定比你提出的方法慢。
如果你仔细考虑自己的解决方案,它实际上可能看起来很聪明。

我非常确定那样行不通。考虑四个黑色(#0..0)和一个红色(#00010000)。相加并除以五,红色(1/5)的余数将流入绿色和蓝色字段。 - Alice Purcell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接