4

我有五种颜色#AARRGGBB以无符号整数的格式存储,我需要取所有五种颜色的平均值。显然,我不能简单地将每个 int 除以 5 并添加它们,到目前为止我想到的唯一方法是对它们进行位掩码,分别执行每个通道,然后再次将它们 OR 在一起。有没有一种聪明或简洁的方法来平均所有五个?

4

4 回答 4

3

您(OP)提出的解决方案和帕特里克的解决方案之间的一半看起来很整洁:

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 有一个糟糕的二进制表示,所以乘以它是一个屁股。

一如既往,准确性或速度。你的选择。

于 2009-07-22T13:42:56.577 回答
2

当使用至少具有 SSE 的 x86 机器时,如果您只需要近似,您可以使用汇编指令 PAVGB(打包平均字节),它平均字节。有关说明,请参见http://www.tommesani.com/SSEPrimer.html

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

于 2009-07-22T13:43:21.553 回答
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。

于 2009-07-23T11:58:31.620 回答
0

编辑我会把这个尝试留给后代,但请注意它是不正确的并且不会起作用。

您可以这样做的一种“聪明”方法是在组件之间插入零,解析为无符号长整数,平均数字,转换回十六进制字符串,删除零,最后解析为无符号整数。

即将#AARRGGBB 转换为#AA00RR00GG00BB

此方法涉及解析和字符串操作,因此无疑会比您提出的方法慢。

如果您要仔细考虑自己的解决方案,它本身实际上可能看起来很聪明。

于 2009-07-22T13:32:14.517 回答