HSV颜色空间是一个圆椎形的空间,如果用x,y,z坐标来计算两个颜色的距离,我认为是不正确的。
因此,写了这么一段代码(C++),计算圆椎内两个点与中轴形成的轴对称扇面的对角线,用这个长度作为HSV空间内两个颜色之间的距离。
struct SpHSV{
float h;
float s;
float v;
SpHSV()
{
h = s = v = 0.0f;
}
SpHSV(float _h, float _s, float _v)
{
h = _h; s = _s; v = _v;
}
inline float distance(const SpHSV& other) const
{
float arc = abs(h - other.h);
arc = (arc > 0.5f ? 1.0f - arc : arc) * 2.0f * 3.1415926f;
float r1 = s * (v);
float r2 = other.s * (other.v);
float height = sqrt((r1 - r2) * (r1 - r2) + (v - other.v) * (v - other.v));
return sqrt( r1 * arc * r2 * arc + height * height);
}
};
另外还有 HSL 的版本
struct SpHSL{
float h;
float s;
float l;
SpHSL()
{
h = s = l = 0.0f;
}
SpHSL(float _h, float _s, float _l)
{
h = _h; s = _s; l = _l;
}
inline float distance( const SpHSL& other) const
{
float arc = abs(h - other.h);
arc = (arc > 0.5f ? 1.0f - arc : arc) * 2.0f * 3.1415926f;
float r1 = (s * (1.0f - abs(0.5f - l) * 2.0f));
float r2 = (other.s * (1.0f - abs(0.5f - other.l) * 2.0f));
float height = sqrt((r1 - r2) * (r1 - r2) + (l - other.l) * (l - other.l));
return sqrt(r1 * arc * r2 * arc + height * height);
}
};
RGB 的版本
struct SpRGB{
float r;
float g;
float b;
SpRGB()
{
r = g = b = 0.0f;
}
SpRGB(float _r, float _g, float _b)
{
r = _r; g = _g; b = _b;
}
SpRGB(int32_t _r, int32_t _g, int32_t _b)
{
r = _r / 255.0f; g = _g / 255.0f; b = _b / 255.0f;
}
inline bool isEqual(float a, float b) const
{
return abs(a - b) < 0.00392157f;
}
inline bool operator == (const SpRGB& other)
{
return (isEqual(r, other.r) && isEqual(g, other.g) && isEqual(b, other.b));
}
inline float distance( const SpRGB& other) const
{
float x = r - other.r, y = g - other.g, z = b - other.b;
return sqrt(x*x + y*y + z*z);
}
//验证颜色转换计算结果:http://colorizer.org/
SpHSV toHSV() const
{
//返回的 vec3 中,均为归一化的值,包括色相 s。
float maxValue = std::max(r, std::max(g, b));
float minValue = std::min(r, std::min(g, b));
float v = maxValue - minValue;
SpHSV hsv(0.0f, 0.0f, maxValue);
if ( v > 0.0f )
{
hsv.s = v / maxValue;
if (isEqual(maxValue, r))
hsv.h = ((g - b) / v + (g < b ? 6.0f : 0.0f)) / 6.0f;
else if (isEqual(maxValue, g))
hsv.h = ((b - r) / v + 2.0f) / 6.0f;
else
hsv.h = ((r - g) / v + 4.0f) / 6.0f;
}
return hsv;
}
SpHSL toHSL() const
{
float maxValue = std::max(r, std::max(g, b));
float minValue = std::min(r, std::min(g, b));
float v = maxValue - minValue;
SpHSL hsl(0.0f, 0.0f, (maxValue + minValue) * 0.5f);
if (v > 0.0f )
{
//计算色深,等价于 s = l < 0.5 ? v/(2.0*l) : v/(2.0-2.0*l);
hsl.s = v / ( 1.0f - abs( 2.0f * hsl.l - 1.0f));
if (isEqual(maxValue, r))
hsl.h = ((g - b) / v + (g < b ? 6.0f : 0.0f)) / 6.0f;
else if (isEqual(maxValue, g))
hsl.h = ((b - r) / v + 2.0f) / 6.0f;
else
hsl.h = ((r - g) / v + 4.0f) / 6.0f;
}
return hsl;
}
};
转载请注明:《计算HSV颜色空间中,两个颜色的距离》