'Calculate distance between colors in HSV space
I intend to find a distance metric between two colours in HSV space.
Suppose that each colour element has 3 components: hue, saturation, and value. Hue is ranged between 0 to 360, saturation is ranged between 0 to 1, and value is ranged between 0 to 255.
Also hue has a circular property, for example, 359 in hue is closer to 0 in hue value than 10 in hue.
Can anyone provide a good metric to calculate the distance between 2 colour element in HSV space here?
Solution 1:[1]
Given hsv values, normalized to be in the ranges [0, 2pi), [0, 1], [0, 1], this formula will project the colors into the HSV cone and give you the squared (cartesian) distance in that cone:
( sin(h1)*s1*v1 - sin(h2)*s2*v2 )^2
+ ( cos(h1)*s1*v1 - cos(h2)*s2*v2 )^2
+ ( v1 - v2 )^2
Solution 2:[2]
In case you are looking for checking just the hue, Marco's answer will do it. However, for a more accurate comparison considering hue, saturation and value, Sean's answer is the right one. You can't simply check the distance from hue, saturation and value equally, because hue is a circle, not a normal vector. It's not like RGB where red, green and blue are vectors
PS: I know I am not giving any new solutions with this post, but Sean's answer really saved me and I wanted to acknowledge it besides upvoting since it is not the top answer here.
Solution 3:[3]
Lets start with:
c0 = HSV( h0, s0, v0 )
c1 = HSV( h1, s1, v1 )
Here are two more solutions:
(Helix Length)Find the length of curve in euclidean 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 goes from 0 to 1.
Note: h1-h0 is not just subtraction it is modulus subtraction. This can be optimized by rotation and then use: h0=0, and h1 = min(abs(h1-h0), 360-abs(h1-h0))
(Helix Length over RGB)Same as above but convert above curve in to RGB instead to euclidean space then calculate arc length. And again convex combination by coordinate of HSV colors, each point on HSV-line convert to RGB.
Calculate the length of that line in RGB space with euclidean norm.helix_rgb( t ) = RGB( HSV( h0+t*( h1-h0 ), s0+t*(s1-s0), v0+t*(v1-v0) ) )
t goes from 0 to 1.
Note: h1-h0 is not just subtraction it is (more than) modulus subtraction e.g.
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))
Comparison of metrics:
RGB(0,1,0) is referent point and calculate distance to color in right-down corner image.
Color image is generated by rule HSL([0-360], 100, [1-100] ).
EM is short from Euclid with Modulo as Marco13 propose with Sean Gerrish's scale. Comparison of solutions over HSI, HSL and HSV, there are also distance in RGB and CIE76(LAB).
Comparing EM to other solutions like Helix len, RGB2RGB, CIE76 appears that EM give acceptable result at very low cost.
In https://github.com/dmilos/color.git it is implemented EM with arbitrary scaling.
Example:
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 */ );
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Pang |
| Solution 2 | mvoelcker |
| Solution 3 | DejanM |

