我有一个Java中的缓冲图像,并且我想记录每个像素与另一个像素相似程度基于颜色值。因此,'相似'颜色的像素将具有更高的相似性值。例如,红色和粉色将具有相似性值1000,但红色和蓝色将具有类似300或更低的数值。
如何实现这个功能?当我从Buffered Image像素中获取RGB时,它返回一个负整数,我不确定如何使用它来实现这一点。
首先,你是如何获取整数值的?
一旦获取到RGB值,你可以尝试使用以下公式:
((r2 - r1)2 + (g2 - g1)2 + (b2 - b1)2)1/2
这将给出两个点在三维空间中的距离,每个点由(r1, g1, b1)和(r2, g2, b2)指定。
或者有更复杂的方法,使用颜色的HSV值。
HSL是一个不好的选择。L*a*b是一个颜色空间,旨在表示颜色实际上是如何被感知的,并且基于数百个涉及真正有眼睛的人观察不同颜色并说“我可以区分那两个颜色,但不是这两个”的实验数据。
L*a*b空间中的距离表示根据这些实验导出的预测实际感知距离。
一旦你转换为L*a*b,你只需要在3D空间中测量线性距离。
Sqrt((X0 - X1)*(X0 - X1) + (Y0 - Y1)*(Y0 - Y1) + (Z0 - Z1)*(Z0 - Z1))
花费2 Cos、2 Sin和一个平方根。
或者,如果您愿意,您实际上可以更容易地计算距离,只需意识到当被压缩为2D空间时,您只需要从原点得到两个向量,并应用余弦定理来找到XY空间中的距离:
C² = A² + B² + 2*A*B*Cos(Theta)
A等于第一个值的S*V,B等于第二个值的S*V,cosine是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);
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;
关于这个问题,有一篇有趣的论文:
一种新的感知均匀颜色空间及其相关的基于内容的图像和视频检索的颜色相似度测量方法 作者:M. Sarifuddin 和 Rokia Missaoui
您可以在谷歌或者特别是[谷歌学术][1]上轻松找到它。
总结一下,一些颜色空间(例如RGB、HSV、Lab)和距离测量方法(如几何平均值和欧几里得距离)比其他方法更好地表示了人类对颜色相似性的感知。该论文介绍了一种新的颜色空间,它比其他颜色空间更好,但它也提供了常见现有颜色空间和距离测量方法的良好比较。从定性上来看,使用常见的颜色空间进行感知距离测量的最佳方法是:HSV颜色空间和圆柱形距离测量。
*至少根据参考论文中的第15张图表。
圆柱形距离测量公式(使用Latex符号)如下:
D_{cyl} = \sqrt{\Delta V^{2}+S_1^{2}+S_2^{2}-2S_1S_2cos(\Delta H)}
这是一个类似于#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之外,还有其他可供选择的颜色空间,可能更适合您的问题。