计算 HSV 中颜色之间的距离 space

Calculate distance between colors in HSV space

我打算在 HSV space 中找到两种颜色之间的距离度量。

假设每个颜色元素有 3 个分量:色调、饱和度和明度。色相介于 0 到 360 之间,饱和度介于 0 到 1 之间,明度介于 0 到 255 之间。

hue也有一个循环属性,例如hue的359比hue的10更接近0的hue值。

谁能提供一个好的指标来计算 HSV space 中 2 个颜色元素之间的距离?

首先是一个简短的警告:计算颜色的距离没有意义(在大多数情况下)。如果不考虑 Colorimetry, things like the CIECAM02 Color Space 50 年的研究结果或距离测量的感知线性,这种距离测量的结果将是违反直觉的。根据您的距离度量 "similar" 的颜色将对观看者显示 "very different",而具有较大 "distance" 的其他颜色将无法被观看者区分。然而...


真题好像主要针对"Hue"部分,也就是0到360之间的一个值。而实际上0和360的值是一样的——都是代表"red",如图所示:

现在,计算这两个值的差值归结为计算圆周为 360 的圆上两点的距离。您已经知道这些值严格在 [0,360) 范围内。如果您不知道,则必须使用 Floating-Point Modulo Operation 将它们纳入此范围。

然后,您可以计算这些色调值 h0h1 之间的距离,如

hueDistance = min(abs(h1-h0), 360-abs(h1-h0));

想象一下,将这两个点都画在一个圆上,然后选择它们所描述的较小的 "piece of the cake" - 即它们之间的距离按顺时针或逆时针顺序排列。


EDIT Extended for the comment:

  • "Hue" 个元素在 [0,360] 范围内。使用上面的公式,您可以计算两种色调之间的距离。此距离在 [0,180] 范围内。将距离除以 180.0 将得到 [0,1]

  • 中的值
  • "Saturation" 个元素在 [0,1] 范围内。两个饱和度之间的(绝对)差异也将在 [0,1].

  • 范围内
  • "Value" 个元素在 [0,255] 范围内。因此,两个值之间的绝对差也将在 [0,255] 范围内。将此差异除以 255.0 将得到 [0,1].

  • 中的值

假设您有两个 HSV 元组。称他们为 (h0,s0,v0)(h1,s1,v1)。然后你可以计算距离如下:

dh = min(abs(h1-h0), 360-abs(h1-h0)) / 180.0
ds = abs(s1-s0)
dv = abs(v1-v0) / 255.0

这些值中的每一个都在 [0,1] 范围内。您可以计算此元组的长度:

distance = sqrt(dh*dh+ds*ds+dv*dv)

对于 HSV space,此距离将是 metric

给定 hsv 值,归一化到 [0, 2pi]、[0, 1]、[0, 1] 范围内,此公式会将颜色投影到 HSV 锥体中,并给出平方(笛卡尔坐标) 在该圆锥中的距离:

   ( sin(h1)*s1*v1 - sin(h2)*s2*v2 )^2
 + ( cos(h1)*s1*v1 - cos(h2)*s2*v2 )^2
 + ( v1 - v2 )^2

如果您只想检查色相,Marco 的回答就可以了。然而,为了更准确地考虑色相、饱和度和明度的比较,肖恩的回答是正确的。 你不能简单地平等地检查色调、饱和度和明度的距离,因为色调是一个圆,而不是一个法向量。它不像 RGB 红绿蓝是矢量

PS:我知道我不会为此 post 提供任何新的解决方案,但 Sean 的回答确实救了我,除了投票之外我想承认它,因为它不是这里的最佳答案.

让我们开始:

c0 = HSV( h0, s0, v0 )
c1 = HSV( h1, s1, v1 )

这里还有两个解决方案:

  1. (Helix Length)求欧氏曲线的长度space:

    x = ( s0+t*(s1-s0) ) * cos( h0+t*( h1-h0 ) )
    y = ( s0+t*(s1-s0) ) * sin( h0+t*( h1-h0 ) )
    z = ( v0+t*(v1-v0) )

t 从 0 到 1。

注意:h1-h0 不仅仅是减法,它是模数减法。 这个可以通过旋转优化然后使用:h0=0, and h1 = min(abs(h1-h0), 360-abs(h1-h0))

  1. (RGB 上的螺旋长度)与上述相同,但将以上曲线转换为 RGB 而不是欧氏 space,然后计算弧长。 再次通过HSV颜色坐标进行凸组合,HSV线上的每个点都转换为RGB。
    使用欧氏范数计算 RGB space 中该线的长度。

    helix_rgb( t ) = RGB( HSV( h0+t*( h1-h0 ), s0+t*(s1-s0), v0+t*(v1-v0) ) )

t 从 0 到 1。

注意:h1-h0 不仅仅是减法,它是(大于)模数减法,例如

D(HSV(300,50,50),HSV(10,50,50)) = D(HSV(300,50,50),HSV( 0,50,50)) + D(HSV( 0,50,50), HSV(10,50,50))

指标比较:

RGB(0,1,0) 为参考点,计算图像右下角颜色的距离。
彩色图像由规则 HSL([0-360], 100, [1-100] ).

生成

EMEuclid with Modulo 的缩写,正如 Marco13 提议的那样,Sean Gerrish 的尺度。 HSI、HSL、HSV上的解比较,RGB和CIE76(LAB)也有距离。

EM 与 Helix len、RGB2RGB、CIE76 等其他解决方案进行比较,似乎 EM 以非常低的成本提供了可接受的结果。

https://github.com/dmilos/color.git中实现了EM任意缩放。
示例:

typedef ::color::hsv<double> color_t; // or HSI, HSL
color_t A = ::color::constant::orange_t{};  \
color_t B = ::color::constant::lime_t{};  \
auto distance = ::color::operation::distance<::color::constant::distance::hue_euclid_entity>( A, B, 3.1415926/* pi is default */ );