以编程方式查找相似的颜色
我在java中有一个缓冲的图像,我想根据颜色值记录每个像素与另一个像素的相似程度。 所以具有“相似”颜色的像素将具有更高的相似度值。 例如,红色和粉红色的相似度值为1000,但红色和蓝色的相似值为300或更小。
我怎样才能做到这一点。 当我从缓冲的Image像素中获取RGB时,它返回一个负整数,我不知道如何用它来实现它。
首先,你如何得到整数值?
获得RGB值后,您可以尝试
((r2-r1) 2 +(g2-g1) 2 +(b2-b1) 2 ) 1/2
这将为您提供距离两个点的3D空间距离,每个点由(r1,g1,b1)和(r2,g2,b2)指定。
或者使用颜色的HSV值有更复杂的方法。
我建议你从这里开始阅读
色差公式,如果你想这样做。 它解释了用于计算色差的ΔE*ab
, ΔE*94
, ΔE*00
和ΔE*CMC
公式。
HSL是一个糟糕的举动。 L * a * b是一个色彩空间,旨在表示色彩实际上是如何被实现的,并且是基于数百个实验的数据,这些实验涉及真实眼睛看不同颜色的人,并说“我可以分辨出这两者之间的区别。但不是那两个“。
L * a * b空间中的距离表示根据这些实验得出的预测的实际距离。
一旦转换为L * a * b,您只需要测量3D空间中的线性距离。
如果您打算使用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
然后将因子考虑在内,将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);
请注意,因为cosigns定律给我们C²,我们只需将其插入Z中即可。它的成本为1 Cos和1 Sqrt。 HSV非常有用,你只需要知道它描述的是什么类型的色彩空间。 你不能只是将它们打成一个欧几里德函数,并从中得到一些连贯的东西。
最简单的方法是将两种颜色转换为HSV值并找出H值的差异。 最小的变化意味着颜色相似。 您可以自定义阈值。
你可能在每个像素上调用getRGB(),它返回的颜色为4 8位字节,高字节alpha,下一个字节为红色,下一个字节为绿色,下一个字节为蓝色。 您需要将频道分开。 即使这样,RGB空间中的颜色相似性也不是很大 – 使用HSL或HSV空间可能会获得更好的结果。 请参阅此处获取转换代码。
换一种说法:
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;
我发现HSL值更容易理解。 HSL Color解释了它们的工作原理并提供了转换程序。 与其他答案一样,您需要确定与您类似的方法。
有一篇关于这个问题的有趣论文:
用于基于内容的图像和video检索 的 相关颜色相似性测量的新的感知均匀颜色空间 由M. Sarifuddin和Rokia Missaoui提供
您可以使用Google或特别是[Google学术搜索]轻松找到这一点。[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,这可能更适合您的问题。
颜色感知不是线性的, 因为人眼对某些颜色比其他颜色更敏感。
所以抖动 正确回答
我试了一下。 HSL / HSV值绝对没用。 例如:
-
L = 0的所有颜色都是“黑色”(RGB 000000),尽管它们的HSL差异可能暗示高色距。
-
S = 0的所有颜色都是“灰色”的阴影,尽管它们的HSL差异可能暗示高颜色距离。
-
H(色调)范围以“红色”的阴影开始和结束,因此H = 0且H = [max](360°或100%或240,取决于应用)都是红色的并且彼此相对相似,但欧几里德HSL距离接近最大值。
所以我的建议是使用Euclidean RGB距离(r2-r1)²+(g2-g1)²+(b2-b1)²无根。 (主观)阈值1000然后适用于类似的颜色。 差异> 1000的颜色可以通过人眼很好地区分。 另外,对组件进行不同的加权可能会很有帮助(参见前文)。
- 将eclipse IDE指向使用JAVA_HOME中指定的JRE / JDK以外的其他JRE / JDK
- 为什么我在编译时在java程序中遇到“无法找到符号”错误?
- 使用iText Java的pdf中的日文/中文文本
- Log4J Swing Appender
- 如何让多个Threads绘制到AWT组件上?
- 在oracle.jdbc.driver.T4CConnection上找到的锁定对象
- Java Hibernate json无限递归与自引用类
- 通过Producer类将RequestScoped CDI Bean注入ApplicationScoped CDI Bean
- 我想在鼠标hover在JMenuItem上时执行一些操作。 我应该使用什么样的听众?