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

时间:2022-02-10 19:22:43

I have a rgb value and if it doesn't exist in the color table in my database I need to find the closest color. I was thinking of comparing all values and finding the difference(in red,green,and blue) then take the average. The lowest average deviation should be the closest color. There seems to me like there should be a better way. Any ideas?

我有一个rgb值,如果它不存在于数据库中的颜色表中,我需要找到最近的颜色。我想比较所有的值,然后找出差异(红色、绿色和蓝色),然后取平均值。最低的平均偏差应该是最接近的颜色。我觉得应该有更好的办法。什么好主意吗?

7 个解决方案

#1


56  

Consider a color as a vector in 3-dimensional space, you can then easily compute the difference by using 3d pythagoras:

把颜色看成是三维空间中的向量,你就可以用3d毕达哥拉斯来简单地计算出它们的差别:

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

However, note that due to colors being subject to interpretation by not-so-perfect eyes, you might want to adjust the colors to avoid them having the same importance.

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

For instance, using a typical weighted approach:

例如,使用典型的加权方法:

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

Since eyes are most sensitive to green, and least sensitive to blue, two colors that differ only in the blue component must thus have a larger numeric difference to be considered "more different" than one that is the same numeric difference in the green component.

由于眼睛对绿色最敏感,对蓝色最不敏感,因此只有蓝色部分不同的两种颜色在数值上的差异必须大于绿色部分相同数值上的差异。

There's also various ways to optimize this calculation. For instance, since you're not really interested in the actual d value, you can dispense with the square root:

也有各种方法来优化这个计算。例如,由于你对实际的d值并不感兴趣,你可以不用平方根:

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

Note here that in many C-syntax-based programming languages (like C#), ^ does not mean "raise to the power of", but rather "binary exclusive or".

注意,在许多C-syntax-based编程语言(如c#),^并不意味着“筹集的力量”,而是“二元异或”。

So if this was C#, you would use Math.Pow to calculate that part, or just expand and do the multiplication.

如果这是c#,你可以用数学。用Pow来计算这个部分,或者只是展开和做乘法运算。

Added: Judging by the page on Color difference on Wikipedia, there's various standards that try to handle perceptual differences. For instance, the one called CIE94 uses a different formula, in the L*C*h color model that looks like it's worth looking into, but it depends on how accurate you want it to be.

补充:从*上关于颜色差异的页面来看,有各种各样的标准试图处理感知上的差异。例如,CIE94使用了一个不同的公式,在L*C*h颜色模型中,看起来很值得研究,但这取决于你希望它有多精确。

#2


3  

The following does exactly what you describe:

下面就是你所描述的:

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;

However, you might get better results with something that was non-linear. In the "take the averages" approach, if you goal color is (25, 25, 25) the color (45, 25, 25) would be closer than (35, 35, 35). However, I bet the second would actually look closer, since it would also be gray.

然而,你可能会得到更好的结果用一些非线性的东西。在“取平均值”的方法中,如果你的目标颜色是(25,25,25,25,25,25),那么颜色(455,25,25,25,25)会比(355,35,35,35)更接近。不过,我敢打赌,第二张照片会看起来更近一些,因为它也是灰色的。

A few ideas come to mind: you could try squaring the differences before you average them. Or you could do something complicated with finding the color with the closest ratio between the different values. Finding the closest ratios would get you closest to the right hue, but won't account for saturation (if I'm remembering the terms right...)

我想到了几个主意:你可以先把这些差异平方,然后再平均。或者你可以做一些复杂的事情找到颜色在不同的值之间的最接近的比率。找到最接近的比例可以让你接近正确的色调,但不能解释饱和度(如果我记得正确的术语…)

#3


3  

The Euclidean distance difference = sqrt(sqr(red1 - red2) + sqr(green1 - green2) + sqr(blue1 - blue2)) is the standard way to determine the similarity of two colours.

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

However, if you have your colours in a simple list, then to find the nearest colour requires computing the distance from the new colour with every colour in the list. This is an O(n) operation.

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

The sqrt() is an expensive operation, and if you're just comparing two distances then you can simply omit the sqrt().

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

If you have a very large palette of colours, it is potentially quicker to organise the colours into a kd tree (or one of the alternatives) so as to reduce the number of diffreences that require computing.

如果你有一个非常大的颜色调色板,将颜色组织成一个kd树(或其中的一种)可能会更快,从而减少需要计算的差异数量。

#4


2  

Let the database do it for you:

让数据库为您做:

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))

Where @r, @g, and @b are the r,g,b values of the color that you're searching for (SQL Server parameter syntax, since you didn't specify a database). Note that this is still going to have to do a table scan since the order by has a function call in it.

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

Note that the extra square root call isn't actually required since it's a monotonic function. Not that it would probably matter very much, but still.

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

#5


1  

From looking at the Wikipedia page on Color difference, the idea is to treat RGB colours as points in three dimensions. The difference between two colours is the same as the distance between two points:

通过查看*关于颜色差异的页面,我们的想法是将RGB颜色视为三维空间中的点。两种颜色之间的差异与两点之间的距离相同:

difference = sqrt((red1 - red2)^2 + (green1 - green2)^2 + (blue1 - blue2)^2)

#6


1  

One step better than average is nearest square root:

一个比平均值更好的步骤是最近的平方根:

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

This minimizes the distance in 3D color space.

这使得三维彩色空间的距离最小化。

Since a root is strictly increasing, you can search for the maximum of the square instead. How you express this in SQL would depend on which RDBMS you're using.

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

#7


0  

Calculate both the average and the distance like this:

像这样计算平均和距离:

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

This should give you a good idea of the closest value.

这应该能让你很好地知道最接近的值。

#1


56  

Consider a color as a vector in 3-dimensional space, you can then easily compute the difference by using 3d pythagoras:

把颜色看成是三维空间中的向量,你就可以用3d毕达哥拉斯来简单地计算出它们的差别:

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

However, note that due to colors being subject to interpretation by not-so-perfect eyes, you might want to adjust the colors to avoid them having the same importance.

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

For instance, using a typical weighted approach:

例如,使用典型的加权方法:

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

Since eyes are most sensitive to green, and least sensitive to blue, two colors that differ only in the blue component must thus have a larger numeric difference to be considered "more different" than one that is the same numeric difference in the green component.

由于眼睛对绿色最敏感,对蓝色最不敏感,因此只有蓝色部分不同的两种颜色在数值上的差异必须大于绿色部分相同数值上的差异。

There's also various ways to optimize this calculation. For instance, since you're not really interested in the actual d value, you can dispense with the square root:

也有各种方法来优化这个计算。例如,由于你对实际的d值并不感兴趣,你可以不用平方根:

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

Note here that in many C-syntax-based programming languages (like C#), ^ does not mean "raise to the power of", but rather "binary exclusive or".

注意,在许多C-syntax-based编程语言(如c#),^并不意味着“筹集的力量”,而是“二元异或”。

So if this was C#, you would use Math.Pow to calculate that part, or just expand and do the multiplication.

如果这是c#,你可以用数学。用Pow来计算这个部分,或者只是展开和做乘法运算。

Added: Judging by the page on Color difference on Wikipedia, there's various standards that try to handle perceptual differences. For instance, the one called CIE94 uses a different formula, in the L*C*h color model that looks like it's worth looking into, but it depends on how accurate you want it to be.

补充:从*上关于颜色差异的页面来看,有各种各样的标准试图处理感知上的差异。例如,CIE94使用了一个不同的公式,在L*C*h颜色模型中,看起来很值得研究,但这取决于你希望它有多精确。

#2


3  

The following does exactly what you describe:

下面就是你所描述的:

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;

However, you might get better results with something that was non-linear. In the "take the averages" approach, if you goal color is (25, 25, 25) the color (45, 25, 25) would be closer than (35, 35, 35). However, I bet the second would actually look closer, since it would also be gray.

然而,你可能会得到更好的结果用一些非线性的东西。在“取平均值”的方法中,如果你的目标颜色是(25,25,25,25,25,25),那么颜色(455,25,25,25,25)会比(355,35,35,35)更接近。不过,我敢打赌,第二张照片会看起来更近一些,因为它也是灰色的。

A few ideas come to mind: you could try squaring the differences before you average them. Or you could do something complicated with finding the color with the closest ratio between the different values. Finding the closest ratios would get you closest to the right hue, but won't account for saturation (if I'm remembering the terms right...)

我想到了几个主意:你可以先把这些差异平方,然后再平均。或者你可以做一些复杂的事情找到颜色在不同的值之间的最接近的比率。找到最接近的比例可以让你接近正确的色调,但不能解释饱和度(如果我记得正确的术语…)

#3


3  

The Euclidean distance difference = sqrt(sqr(red1 - red2) + sqr(green1 - green2) + sqr(blue1 - blue2)) is the standard way to determine the similarity of two colours.

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

However, if you have your colours in a simple list, then to find the nearest colour requires computing the distance from the new colour with every colour in the list. This is an O(n) operation.

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

The sqrt() is an expensive operation, and if you're just comparing two distances then you can simply omit the sqrt().

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

If you have a very large palette of colours, it is potentially quicker to organise the colours into a kd tree (or one of the alternatives) so as to reduce the number of diffreences that require computing.

如果你有一个非常大的颜色调色板,将颜色组织成一个kd树(或其中的一种)可能会更快,从而减少需要计算的差异数量。

#4


2  

Let the database do it for you:

让数据库为您做:

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))

Where @r, @g, and @b are the r,g,b values of the color that you're searching for (SQL Server parameter syntax, since you didn't specify a database). Note that this is still going to have to do a table scan since the order by has a function call in it.

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

Note that the extra square root call isn't actually required since it's a monotonic function. Not that it would probably matter very much, but still.

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

#5


1  

From looking at the Wikipedia page on Color difference, the idea is to treat RGB colours as points in three dimensions. The difference between two colours is the same as the distance between two points:

通过查看*关于颜色差异的页面,我们的想法是将RGB颜色视为三维空间中的点。两种颜色之间的差异与两点之间的距离相同:

difference = sqrt((red1 - red2)^2 + (green1 - green2)^2 + (blue1 - blue2)^2)

#6


1  

One step better than average is nearest square root:

一个比平均值更好的步骤是最近的平方根:

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

This minimizes the distance in 3D color space.

这使得三维彩色空间的距离最小化。

Since a root is strictly increasing, you can search for the maximum of the square instead. How you express this in SQL would depend on which RDBMS you're using.

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

#7


0  

Calculate both the average and the distance like this:

像这样计算平均和距离:

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

This should give you a good idea of the closest value.

这应该能让你很好地知道最接近的值。