计算24位颜色之间的差异而不分成单独的RGB字节?

时间:2015-10-16 19:48:48

标签: algorithm math colors

计算颜色之间距离的正常方法可能就是:

//             R G B
var color1 = 0xFF0000;
var color2 = 0x00FF00;
// Calculate points      R                    G                  B
var color1_p = [(color1&0xFF0000)>>16, (color1&0xFF00)>>8, color1&0xFF];
var color2_p = [(color2&0xFF0000)>>16, (color2&0xFF00)>>8, color2&0xFF];

var distance = Math.sqrt((color1_p[0]-color2_p[0])*(color1_p[0]-color2_p[0]) + 
                         (color1_p[1]-color2_p[1])*(color1_p[1]-color2_p[1]) +
                         (color1_p[2]-color2_p[2])*(color1_p[2]-color2_p[2])) 

这只是正常的毕达哥拉斯距离。但我必须创建一个数组或以其他方式保存RGB值。我想用C ++解决这个问题我想:

uint32_t color = 0xFF0000;
uint8_t* color_p = (uint8_t*)&color; // [G, B, R, alpha, segmentation fault ...]

You can try it here.永远不要使用int执行此操作,在某些奇怪的平台上,它的范围可以是16到64位。

现在我的问题是,如果有一些智能数学可以直接对0xFF0000(红色,16711680十进制)和0xFFCC00(橙色, 16763904 dec)计算距离或其他类型的差异。我正在寻找线性差异。通过线性差异,我的意思是如果A和B之间的距离相同,那么差异也必须相同,但我并不在乎它究竟是什么数字。

2 个答案:

答案 0 :(得分:2)

没有避免计算的三维性质。使用3字节整数值的计算不会考虑维度的独立性。你可以安全地使用整数值来检查是否相等,这确实比单独比较3个字节更有效(如果你有很多相同的RGB值)。
您可以通过多种方式优化计算,但将颜色分成单独的R,G和B值将始终是其中的一部分。像这样的东西是你能做到这一点最有效的:



function rgbDistanceSquared(x, y) {
    if (x == y) return 0;    // if you expect a lot of identical RGB values
    var r = ((x & 0xFF0000) - (y & 0xFF0000)) >> 16;
    var g = ((x & 0x00FF00) - (y & 0x00FF00)) >> 8;
    var b =  (x & 0x0000FF) - (y & 0x0000FF);
    return r * r + g * g + b * b;
}

document.write(rgbDistanceSquared(0xFF0000, 0xFFCC00) + "<BR>");
document.write(rgbDistanceSquared(0x00CCFF, 0x0000FF) + "<BR>");
document.write(rgbDistanceSquared(0x00CCFF, 0xFFCC00) + "<BR>");
&#13;
&#13;
&#13;

上面的代码返回距离的平方,以避免计算平方根。 当检查相等或比较距离时,这没有区别,因为:
A&lt; B→A 2 &lt;乙 2
A = B→A 2 = B 2
A&gt; B→A 2 &gt; B 2

答案 1 :(得分:1)

正如@harold所说,还有其他距离指标。最简单的是Manhattan distance或出租车指标。这基本上计算绝对值的总和。如果你指向的是(r1,g1,b1)和(r2,g2,b2),那么找到| r1-r2 | + | g1-g2 | + | b1-b2 |。它被称为曼哈顿距离,因为它可以测量两点之间的距离,如果你只能沿着矩形网格的边缘移动,就像曼哈顿的道路模式一样。

设c1 = 0xrrggbb为(r1,g1,b1)的单字节表示,类似于c2。 如果我们知道r2&gt; = r1,g2&gt; = g1,b2&gt; = b1,我们就可以找到x=c2-c1y=((x & 0xFF0000)>>16)+((x & 0x00FF00)>>8)+(x & 0x0000FF)。如果这些点可以是任何顺序,那么我们必须担心每个字节溢出。

黑客喜悦有一种寻找绝对价值的好方法。如果有一个带符号的32位整数x,那么我们可以计算y = x >> 32; z=(x+y)^x。给出绝对值。我们可以做类似

的事情
int32_t r = ((c1 & 0xFF0000) - (c2 & 0xFF0000)) >> 16;
int32_t rsign = r >> 32; // fill with sign bit
int32_t result = (r+rsign)^r;
int32_t g = ((c1 & 0x00FF00) - (c2 & 0x00FF00)) >> 8;
int32_t gsign = g >> 32; // fill with sign bit
result += (g+gsign)^g;
int32_t b = ((c1 & 0x0000FF) - (c2 & 0x0000FF));
int32_t bsign = b >> 32; // fill with sign bit
result += (b+bsign)^b;

我认为这需要23次操作。它并没有真正提供优于@ m69的答案,并且在现代硬件上整数乘法很快。