给定一个RGB值,最好的方法是如何在数据库中找到最接近的匹配项?

36

我有一个RGB值,如果它在我的数据库的颜色表中不存在,那么我需要找到最接近的颜色。我想比较所有值,并计算差值(红色,绿色和蓝色),然后取平均值。最低平均偏差应该是最接近的颜色。但我觉得可能有更好的方法,有什么建议吗?


你存储颜色的表的结构是怎样的? - Ryan
4
虽然每一个答案都建议在RGB空间中使用欧几里得距离,但是不要这么做!HSV比RGB更适合模拟感知距离,因此您应该首先将颜色空间转换为HSV。 - Nick Johnson
CIELAB是描述颜色感知的标准方式。 - bodo
8个回答

98

把颜色看作三维空间中的向量,你可以使用3D勾股定理轻松计算它们之间的差异:

d = sqrt((r2-r1)^2 + (g2-g1)^2 + (b2-b1)^2)
然而,需要注意的是,由于颜色受到不那么完美的眼睛解释的影响,您可能需要调整颜色以避免它们具有相同的重要性。例如,使用典型的加权方法: 链接
d = sqrt(((r2-r1)*0.3)^2 + ((g2-g1)*0.59)^2 + ((b2-b1)*0.11)^2)

由于眼睛对绿色最为敏感,对蓝色最不敏感,因此,两种仅在蓝色分量上有差异的颜色必须具有更大的数值差异才能被认为是“更不同”,而与绿色分量相同的数值差异则相对较小。

此外,还有各种方法可以优化这个计算。例如,由于实际上并不关心值本身,因此可以省去平方根:

d =   ((r2-r1)*0.30)^2
    + ((g2-g1)*0.59)^2
    + ((b2-b1)*0.11)^2

需要注意的是,在许多基于C语法的编程语言(如C#)中,^并不意味着“乘方”,而是“二进制异或”。

所以如果这是C#,你应该使用 Math.Pow 来计算那部分,或者展开并进行乘法运算。

附加信息:根据维基百科上关于颜色差异的页面,有各种标准来处理视觉差异。例如,名为CIE94的标准使用不同的公式,在看起来值得研究的L*C*h色彩模型中,但这取决于你想要多精确。


1
+1。这对我来说看起来很接近,除了眼睛对亮度比颜色更敏感外,所以一个最佳差异应该同时考虑到颜色向量之间的夹角、长度以及从顶端到顶端的距离。 - RickNZ
1
当然。"最接近的颜色"不仅仅是数学差异,更多的是理论。 - Lasse V. Karlsen
不错的答案...是的,颜色可能不仅仅是数学上的差异...因此需要进行可测量的调整。 - John Nicholas
加权是一种短暂的解决方案;感知色模型更适合这个问题,正如您在编辑中所提到的那样。 - Nick Johnson

5

欧几里得距离差异 = sqrt(sqr(red1 - red2) + sqr(green1 - green2) + sqr(blue1 - blue2))是确定两种颜色相似性的标准方法

然而,如果您将颜色存储在简单列表中,则查找最近的颜色需要计算新颜色与列表中每个颜色之间的距离。这是一个O(n)操作。

sqrt()是一项昂贵的操作,如果您只比较两个距离,则可以简单地省略sqrt()

如果您拥有非常大的调色板,则将颜色组织成kd树(或其他选择之一)可能更快,以减少需要计算的差异数量。


4
以下代码完全符合您的要求:
select (abs(my_R - t.r) + abs(my_G - t.g) + abs(my_B - t.b)) / 3 as difference, t.*
from RGBtable t
order by difference desc;

然而,使用非线性方法可能会得到更好的结果。在“取平均值”的方法中,如果您的目标颜色是(25,25,25),那么颜色(45,25,25)比(35,35,35)更接近。但是,我敢打赌第二种颜色看起来更接近,因为它也是灰色。
有一些想法:您可以尝试在对差异求平均之前将其平方。或者,您可以使用复杂的方法找到不同值之间最接近的颜色。找到最接近的比率会使您更接近正确的色调,但不会考虑饱和度(如果我记得这些术语正确的话...)。

2

让数据库为您完成:

select top 1
  c.r,
  c.b,
  c.g
from
  color c
order by
  (square(c.r - @r) + square(c.g - @g) + square(c.b - @b))

这里的@r@g@b是您要搜索的颜色的RGB值(SQL Server参数语法,因为您没有指定数据库)。请注意,由于order by中有一个函数调用,仍然需要进行表扫描。

请注意,额外的平方根调用实际上并不是必需的,因为它是单调函数。虽然可能不会有太大影响,但仍需注意。


数据库并不是魔棒。这样做需要的工作量与自己做一样多,只不过是把工作转嫁给了数据库而已。 - Nick Johnson
2
既然数据已经在数据库中,那么对我来说更有意义的是只获取你需要的行,而不是获取所有行来自己计算距离。 - Donnie

1
从查看颜色差异的维基百科页面来看,其思想是将RGB颜色视为三维空间中的点。两种颜色之间的差异就相当于两个点之间的距离:
difference = sqrt((red1 - red2)^2 + (green1 - green2)^2 + (blue1 - blue2)^2)

1

比平均水平更好的一步是最接近的平方根:

((delta red)^2 + (delta green)^2 + (delta blue)^2)^0.5

这将最小化3D颜色空间中的距离。

由于根是严格递增的,因此您可以搜索平方的最大值。如何在SQL中表达这一点取决于您使用的关系数据库管理系统(RDBMS)。


1
比较整个颜色列表和每个颜色样本可能不是最优的选择。可以通过将颜色列表中的颜色放入搜索树中来进行优化。如果您正在比较颜色样本的红、绿、蓝(RGB)值,则应将颜色列表中的颜色放入三维搜索树中。搜索树可以创建一次,并保存到(json,xml)文件或数据库中。如果速度很重要,例如需要比较许多点,则这可能是值得的。
使用[k-d树],其中R、G和B值为0-256作为X、Y和Z坐标1。或者使用另一种类型的最近邻搜索

0

像这样计算平均值和距离:

(r + g + b) / 3 = average
(r - average) + (g - average) + (b - average) = distance

这应该能让你对最接近的值有一个很好的了解。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接