代码之家  ›  专栏  ›  技术社区  ›  Mike Florian Doyen

给定一个RGB值,找到数据库中最接近的匹配项的最佳方法是什么?

  •  21
  • Mike Florian Doyen  · 技术社区  · 15 年前

    我有一个RGB值,如果它在数据库的颜色表中不存在,我需要找到最接近的颜色。我正在考虑比较所有的值,找出差异(红色、绿色和蓝色),然后取平均值。最小的平均偏差应该是最接近的颜色。在我看来应该有更好的方法。有什么想法吗?

    8 回复  |  直到 6 年前
        1
  •  62
  •   Quantic    8 年前

    将颜色视为三维空间中的矢量,然后可以使用三维毕达哥拉斯轻松计算差异:

    d = sqrt((r2-r1)^2 + (g2-g1)^2 + (b2-b1)^2)
    

    但是,请注意,由于颜色受到不太完美的眼睛的解释,您可能需要调整颜色以避免它们具有相同的重要性。

    例如,使用 a typical weighted approach :

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

    由于眼睛对绿色最敏感,对蓝色最不敏感,因此只有蓝色组分不同的两种颜色必须具有较大的数值差异,才能被视为与绿色组分相同的数值差异“更不同”。

    还有各种方法来优化这个计算。例如,因为你对 d 值,可以忽略平方根:

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

    请注意,在许多基于C语法的编程语言(如C)中, ^ 并不意味着“提高到的力量”,而是“二进制异或”。

    所以如果这是C,你会用 Math.Pow 计算那个部分,或者展开并做乘法。

    补充 :从上一页判断 Color difference on Wikipedia 有各种各样的标准试图处理感知差异。例如,一个名为CIE94的应用程序使用了另一个公式, L*C*h 颜色模型看起来是值得研究的,但它取决于你想要它有多精确。

        2
  •  3
  •   David Oneill    15 年前

    以下内容完全符合您的描述:

    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)更接近。不过,我敢打赌第二个会更近一点,因为它也是灰色的。

    有几个想法浮现在脑海中:你可以试着在平均差异之前将其平方。或者你可以做一些复杂的事情,找到不同值之间比率最接近的颜色。找到最接近的比率可以让你最接近正确的色调,但不能解释饱和度(如果我记住了正确的术语…)

        3
  •  3
  •   Will    15 年前

    这个 Euclidean distance difference = sqrt(sqr(red1 - red2) + sqr(green1 - green2) + sqr(blue1 - blue2)) standard way 确定两种颜色的相似性。

    然而,如果你在一个简单的列表中有你的颜色,那么要找到最近的颜色,就需要用列表中的每种颜色计算出与新颜色的距离。这是一个O(N)操作。

    这个 sqrt() 是一个昂贵的操作,如果你只是比较两个距离,那么你可以简单地忽略 Sqt() .

    如果你有一个非常大的调色板,那么将颜色组织成 kd tree (或其中之一) alternatives )以减少需要计算的屏幕数量。

        4
  •  2
  •   Donnie    15 年前

    让数据库为您做:

    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 是要搜索的颜色的r、g、b值(SQL Server参数语法,因为没有指定数据库)。请注意,由于 order by 其中包含函数调用。

    注意,额外的平方根调用实际上不是必需的,因为它是一个单调函数。这可能不是很重要,但仍然重要。

        5
  •  1
  •   Tim Robinson    15 年前

    从看 the Wikipedia page on Color difference 我们的想法是将RGB颜色视为三维中的点。两种颜色之间的差异与两点之间的距离相同:

    difference = sqrt((red1 - red2)^2 + (green1 - green2)^2 + (blue1 - blue2)^2)
    
        6
  •  1
  •   Andomar    15 年前

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

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

    这样可以最小化3D颜色空间中的距离。

    因为根严格地递增,所以可以搜索平方的最大值。在SQL中如何表达这一点取决于您使用的是哪个RDBMS。

        7
  •  0
  •   nfechner    15 年前

    这样计算平均值和距离:

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

    这应该能让您更好地了解最接近的值。

        8
  •  0
  •   ʕ ᵔᴥᵔ ʔ    6 年前

    每次将颜色样本与整个颜色列表进行比较可能不是最佳选择。这可以通过将颜色列表中的颜色放入搜索树来优化。如果您正在比较其红色、绿色和蓝色(RGB)值上的颜色样本,您将把颜色列表中的颜色放入三维搜索树中。搜索树可以创建一次并保存到(json、xml)文件或数据库中。如果速度很重要,这可能是值得的,例如有许多点需要比较。