【发布时间】:2010-12-16 01:54:43
【问题描述】:
我在 java 中有一个缓冲图像,我想根据颜色值记录每个像素与另一个像素的相似程度。因此具有“相似”颜色的像素将具有更高的相似度值。例如,红色和粉色的相似度值为 1000,但红色和蓝色的相似度值为 300 或更少。
我该怎么做。当我从缓冲的图像像素中获取 RGB 时,它返回一个负整数,我不确定如何用它来实现。
【问题讨论】:
我在 java 中有一个缓冲图像,我想根据颜色值记录每个像素与另一个像素的相似程度。因此具有“相似”颜色的像素将具有更高的相似度值。例如,红色和粉色的相似度值为 1000,但红色和蓝色的相似度值为 300 或更少。
我该怎么做。当我从缓冲的图像像素中获取 RGB 时,它返回一个负整数,我不确定如何用它来实现。
【问题讨论】:
首先,你是如何得到整数值的?
获得 RGB 值后,您可以尝试
((r2 - r1)2 + (g2 - g1)2 + (b2 - b1)2)1 /2
这将为您提供与两个点在 3D 空间中的距离,每个点由 (r1,g1,b1) 和 (r2,g2,b2) 指定。
或者有更复杂的方法使用颜色的 HSV 值。
【讨论】:
最简单的方法是将两种颜色都转换为 HSV 值并找出 H 值的差异。最小的变化意味着颜色相似。不过,您可以自行定义阈值。
【讨论】:
您可能在每个像素上调用 getRGB(),它以 4 个 8 位字节返回颜色,高字节 alpha,下一个字节为红色,下一个字节为绿色,下一个字节为蓝色。您需要分离出通道。即使这样,RGB 空间中的颜色相似性也不是那么好——使用 HSL 或 HSV 空间可能会得到更好的结果。转换代码见here。
换句话说:
int a = (argb >> 24) & 0xff;
int r = (argb >> 16) & 0xff;
int g = (argb >> 8) & 0xff;
int b = argb & 0xff;
我不知道java缓冲图像中具体的字节顺序,但我认为是对的。
【讨论】:
您可以按如下方式获取单独的字节:
int rgb = bufferedImage.getRGB(x, y); // Returns by default ARGB.
int alpha = (rgb >>> 24) & 0xFF;
int red = (rgb >>> 16) & 0xFF;
int green = (rgb >>> 8) & 0xFF;
int blue = (rgb >>> 0) & 0xFF;
【讨论】:
我建议你从这里开始阅读
Color difference formulas 如果您想正确执行此操作。它解释了用于计算色差的ΔE*ab、ΔE*94、ΔE*00 和ΔE*CMC 公式。
【讨论】:
我发现 HSL 值更容易理解。 HSL Color 解释了它们的工作原理并提供了转换例程。与其他答案一样,您需要确定类似对您意味着什么。
【讨论】:
HSL 是一个糟糕的举动。 L*a*b 是一个色彩空间,旨在表示颜色的实际感知方式,它基于数百个实验的数据,这些实验涉及用真眼观察不同颜色并说“我能分辨出这两种颜色的人。但不是那两个”。
L*a*b 空间中的距离表示根据这些实验得出的预测实际感知到的距离。
转换为 L*a*b 后,您只需在 3D 空间中测量线性距离。
【讨论】:
这是一个与#1634206类似的问题。
如果您正在寻找 RGB 空间中的距离,则欧几里得距离将起作用,假设您平等对待红色、绿色和蓝色值。
如果您想对它们进行不同的加权,就像在将颜色/RGB 转换为灰度时通常所做的那样,您需要按不同的量加权每个组件。例如,使用流行的从 RGB 转换为 30% 红色 + 59% 绿色 + 11% 蓝色的灰度:
d2 = (30*(r1-r2))**2 + (59*(g1-g2))**2 + (11*(b1-b2))**2;
d2的值越小,(r1,g1,b1)和(r2,g2,b2)的颜色越接近。
但除了 RGB 之外,还有其他颜色空间可供选择,这可能更适合您的问题。
【讨论】:
我试过了。 HSL/HSV 值绝对没有用。例如:
所有 L=0 的颜色都是“黑色”(RGB 000000),尽管它们的 HSL 差异可能意味着颜色距离较大。
所有 S=0 的颜色都是“灰色”阴影,尽管它们的 HSL 差异可能暗示色距较大。
H(色调)范围以“红色”阴影开始和结束,因此 H=0 和 H=[max](360° 或 100% 或 240,取决于应用程序)都是红色并且相互比较相似,但欧几里得HSL距离接近最大值。
所以我的建议是使用没有根的欧几里得 RGB 距离 (r2-r1)² + (g2-g1)² + (b2-b1)²。 1000 的(主观)阈值适用于相似的颜色。差异大于 1000 的颜色很容易被人眼分辨。此外,对组件进行不同的加权也会很有帮助(参见上一篇文章)。
【讨论】:
如果您要使用 HSV,您需要意识到 HSV 不是三维空间中的点,而是圆锥的角度、大小和距顶部的距离。要计算 HSV 值的距离,您需要通过变换确定 3d 空间中的点。
X = Cos(H)*S*V
Y = Sin(H)*S*V
Z = V
对于两个点,然后取它们之间的欧几里得距离:
Sqrt((X0 - X1)*(X0 - X1) + (Y0 - Y1)*(Y0 - Y1) + (Z0 - Z1)*(Z0 - Z1))
成本为 2 Cos、2 Sin 和平方根。
或者,如果您愿意,实际上可以更容易地计算距离,方法是意识到当展平到 2D 空间时,您只需从原点有两个向量,并应用 cosign 定律来找到 XY 空间中的距离:
C² = A² + B² + 2*A*B*Cos(Theta)
其中 A = S*V 的第一个值,B = S*V 的第二个和 cosign 是差值 theta 或 H0-H1
然后考虑 Z,将 2D 空间扩展到 3D 空间。
A = S0*V0
B = S1*V1
dTheta = H1-H0
dZ = V0-V1
distance = sqrt(dZ*dZ + A*A + B*B + 2*A*B*Cos(dTheta);
请注意,因为余符号定理给了我们 C²,所以我们只需将其与 Z 的变化一起插入其中。这需要 1 Cos 和 1 Sqrt。 HSV 非常有用,您只需要知道它所描述的色彩空间类型。您不能只是将它们打造成欧几里得函数并从中得到连贯的东西。
【讨论】:
关于这个问题有一篇有趣的论文:
用于基于内容的图像和视频检索的具有相关颜色相似度度量的新感知均匀颜色空间 M. Sarifuddin 和 Rokia Missaoui
您可以使用 Google 或特别是 [Google Scholar.][1] 轻松找到此内容。
总而言之,一些颜色空间(例如 RGB、HSV、Lab)和距离度量(例如几何平均值和欧几里得距离)比其他颜色空间更能代表人类对颜色相似性的感知。该论文讨论了一种新的色彩空间,它比其他的更好,但它也提供了对常见的现有色彩空间和距离度量的很好的比较。定性*,使用常用颜色空间测量感知距离的最佳方法似乎是:HSV 颜色空间和圆柱距离测量。
*至少,根据参考论文中的图 15。
圆柱距离度量是(在 Latex 表示法中):
D_{cyl} = \sqrt{\Delta V^{2}+S_1^{2}+S_2^{2}-2S_1S_2cos(\Delta H)}
【讨论】: