Better to use LAB color space, which has been designed for color comparisons (hence its wide use in computer vision). In LAB space, the euclidean distance corresponds closely to the perceptual color difference.
Here is the conversion to/from LAB and sRGB:
/// Convert the gamma from sRGB to linear RGB space.
template < typename T >
T gamma_sRGB_RGB( T x )
{
return (x <= T(0.0404482362771076)) ? (x / T(12.92)) : math::pow( (x + T(0.055))/T(1.055), T(2.4) );
}
/// Convert the gamma from linear RGB to sRGB space.
template < typename T >
T gamma_RGB_sRGB( T x )
{
return (x <= T(0.0031306684425005883)) ? (x * T(12.92)) : (T(1.055)*math::pow( x, T(1)/T(2.4) ) - T(0.055));
}
template < typename T >
T LAB_f( T x )
{
return (x > T(8.85645167903563082e-3)) ? math::pow( x, T(1)/T(3) ) : (T(841)/T(108))*x + T(4)/T(29);
}
template < typename T >
T LAB_f_inverse( T x )
{
return (x > T(0.206896551724137931)) ? (x*x*x) : (T(108)/T(841))*(x - T(4)/T(29));
}
/// Convert from the sRGB color space to the linear RGB color space.
template < typename T >
void convert_sRGB_RGB( const T srgb[3], T rgb[3] )
{
rgb[0] = gamma_sRGB_RGB(srgb[0]);
rgb[1] = gamma_sRGB_RGB(srgb[1]);
rgb[2] = gamma_sRGB_RGB(srgb[2]);
}
/// Convert from the linear RGB color space to the sRGB color space.
template < typename T >
void convert_RGB_sRGB( const T rgb[3], T srgb[3] )
{
srgb[0] = gamma_RGB_sRGB(rgb[0]);
srgb[1] = gamma_RGB_sRGB(rgb[1]);
srgb[2] = gamma_RGB_sRGB(rgb[2]);
}
/// Convert from the linear RGB color space to the XYZ color space.
template < typename T >
void convert_RGB_XYZ( const T rgb[3], T xyz[3] )
{
xyz[0] = T(0.4123955889674142161)*rgb[0] + T(0.3575834307637148171)*rgb[1] + T(0.1804926473817015735)*rgb[2];
xyz[1] = T(0.2125862307855955516)*rgb[0] + T(0.7151703037034108499)*rgb[1] + T(0.07220049864333622685)*rgb[2];
xyz[2] = T(0.01929721549174694484)*rgb[0] + T(0.1191838645808485318)*rgb[1] + T(0.9504971251315797660)*rgb[2];
}
/// Convert from the XYZ color space to the linear RGB color space.
template < typename T >
void convert_XYZ_RGB( const T xyz[3], T rgb[3] )
{
rgb[0] = T(3.2406)*xyz[0] + T(-1.5372)*xyz[1] + T(-0.4986)*xyz[2];
rgb[1] = T(-0.9689)*xyz[0] + T(1.8758)*xyz[1] + T(0.0415)*xyz[2];
rgb[2] = T(0.0557)*xyz[0] + T(-0.2040)*xyz[1] + T(1.0570)*xyz[2];
// Ensure positive numbers.
const T minRGB = math::min( rgb[0], math::min( rgb[1], rgb[2] ) );
if ( minRGB < T(0) )
{
rgb[0] -= minRGB;
rgb[1] -= minRGB;
rgb[2] -= minRGB;
}
}
/// Convert from the XYZ color space to the CIE LAB color space.
template < typename T >
void convert_XYZ_LAB( const T xyz[3], T lab[3], const VectorND<T,3>& whitePoint = WHITE_POINT_D65 )
{
// Divide by XYZ color of the D65 white point and apply the LAB f function.
T temp0 = LAB_f(xyz[0] / whitePoint[0]);
T temp1 = LAB_f(xyz[1] / whitePoint[1]);
T temp2 = LAB_f(xyz[2] / whitePoint[2]);
lab[0] = T(116)*temp1 - T(16);
lab[1] = T(500)*(temp0 - temp1);
lab[2] = T(200)*(temp1 - temp2);
}
/// Convert from the CIE LAB color space to the XYZ color space.
template < typename T >
void convert_LAB_XYZ( const T lab[3], T xyz[3], const VectorND<T,3>& whitePoint = WHITE_POINT_D65 )
{
T y = (lab[0] + T(16))/T(116);
T x = y + lab[1]/T(500);
T z = y - lab[2]/T(200);
xyz[0] = LAB_f_inverse(x)*whitePoint[0];
xyz[1] = LAB_f_inverse(y)*whitePoint[1];
xyz[2] = LAB_f_inverse(z)*whitePoint[2];
}
/// Convert from the linear RGB color space to the CIE LAB color space.
template < typename T >
void convert_RGB_LAB( const T rgb[3], T lab[3], const VectorND<T,3>& whitePoint = WHITE_POINT_D65 )
{
T xyz[3];
convert_RGB_XYZ( rgb, xyz );
convert_XYZ_LAB( xyz, lab, whitePoint );
}
/// Convert from the CIE LAB color space to the linear RGB color space.
template < typename T >
void convert_LAB_RGB( const T lab[3], T rgb[3], const VectorND<T,3>& whitePoint = WHITE_POINT_D65 )
{
T xyz[3];
convert_LAB_XYZ( lab, xyz, whitePoint );
convert_XYZ_RGB( xyz, rgb );
}
/// Convert from the sRGB color space to the CIE LAB color space.
template < typename T >
void convert_sRGB_LAB( const T srgb[3], T lab[3], const VectorND<T,3>& whitePoint = WHITE_POINT_D65 )
{
T rgb[3];
convert_sRGB_RGB( srgb, rgb );
convert_RGB_LAB( rgb, lab, whitePoint );
}
/// Convert from the CIE LAB color space to the sRGB color space.
template < typename T >
void convert_LAB_sRGB( const T lab[3], T srgb[3], const VectorND<T,3>& whitePoint = WHITE_POINT_D65 )
{
T xyz[3];
T rgb[3];
convert_LAB_XYZ( lab, xyz, whitePoint );
convert_XYZ_RGB( xyz, rgb );
convert_RGB_sRGB( rgb, srgb );
}