计算HSV颜色空间中,两个颜色的距离

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颜色空间中,两个颜色的距离

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注