计算 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 将它们纳入此范围。
然后,您可以计算这些色调值 h0
和 h1
之间的距离,如
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 )
这里还有两个解决方案:
(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))
(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] ).
生成
EM 是 Euclid 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 */ );
我打算在 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 将它们纳入此范围。
然后,您可以计算这些色调值 h0
和 h1
之间的距离,如
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 )
这里还有两个解决方案:
(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))
(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] ).
EM 是 Euclid 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 */ );