C#RGB到HSL单向转换算法

时间:2014-09-16 22:35:54

标签: c# colors models rgb hsl

以下是我的RGB到HSL单向颜色转换方法,用C#编写。它紧密地基于开源程序代码“Meazure”(我正在为我的项目使用的工具,因此我需要将我的HSL颜色格式化为与Meazure中相同的颜色)。

    public String rgbToHsl(int r, int g, int b)
    {
        double h, s, l;
        double rDecimal = r / 255;
        double gDecimal = g / 255;
        double bDecimal = b / 255;
        double cMin = Math.Min(r, Math.Min(g, b));
        double cMax = Math.Max(r, Math.Max(g, b));
        double delta = cMax - cMin;

        l = (cMax + cMin) / 2;

        if (cMax == cMin)
        {
            s = 0;
            h = 0;  // It's really undefined
        }
        else
        {
            if (l < .5)
            {
                s = delta / (cMax + cMin);
            }
            else
            {
                s = delta / (2 - cMax - cMin);
            }

            if (r == cMax)
            {
                h = (g - b) / delta;
            }
            else if (g == cMax)
            {
                h = 2 + (b - r) / delta;
            }
            else
            {
                h = 4 + (r - g) / delta;
            }

            h /= 6;

            if (h < 0)
            {
                h += 1;
            }
        }

        return h.ToString().PadLeft(3, '0') + s.ToString().PadLeft(3, '0') + l.ToString().PadLeft(3, '0');
    }

以下是我用作参考的开源C ++ Meazure代码。

void MeaColors::RGBtoHSL(COLORREF rgb, HSL& hsl)
{
    double h, s, l;
    double r = GetRValue(rgb) / 255.0;
    double g = GetGValue(rgb) / 255.0;
    double b = GetBValue(rgb) / 255.0;
    double cmax = Max(r, Max(g, b));
    double cmin = Min(r, Min(g, b));

    l = (cmax + cmin) / 2.0;
    if (MEA_DBL_EQL(cmax, cmin)) {
        s = 0.0;
        h = 0.0; // it's really undefined
    } else {
        if (l < 0.5) {
            s = (cmax - cmin) / (cmax + cmin);
        } else {
           s = (cmax - cmin) / (2.0 - cmax - cmin);
        }
        double delta = cmax - cmin;

        if (MEA_DBL_EQL(r, cmax)) {
            h = (g - b) / delta;
        } else if (MEA_DBL_EQL(g, cmax)) {
            h = 2.0 + (b - r) / delta;
        } else {
            h = 4.0 + (r - g) / delta;
        }
        h /= 6.0;

        if (h < 0.0) {
            h += 1.0;
        }
    }

    hsl.hue = h;
    hsl.lightness = l;
    hsl.saturation = s;
}

问题是我的方法没有输出预期的值。它可以编译和运行,而不会崩溃。然而,对于输入RGB值214,219,233,我的方法产生HSL值.6,228,70,而通过使用Meazure测量HSL格式的相同像素而获得的期望值是149,72,210。我注意到这个网站上有一些类似的问题,但没有一个有功能性的解决方案,至少在这里需要的格式。

这是我调用my方法的代码。它恰好通过构建一个以输入像素为中心的5x5框来转换来自单个输入的25个RGB值(仅提及它以避免混淆)。

            Bitmap screenShot = takeScreenShot();
            const int squareSideSize = 5;
            Color[] firstPixelSquare = new Color[(int)Math.Pow(squareSideSize, 2)];
            hslColor[] hslFirstPixelSquare = new hslColor[(int)Math.Pow(squareSideSize, 2)];

            for (int hOffset = -2, i = 0; hOffset <= 2; hOffset++, i += squareSideSize)
            {
                for (int vOffset = -2, j = i; vOffset <= 2; vOffset++, j++)
                {
                    firstPixelSquare[j] = screenShot.GetPixel((int)numericUpDownX1.Value + hOffset, (int)numericUpDownY1.Value + vOffset);
                    hslFirstPixelSquare[j].h = Convert.ToDouble(rgbToHsl(firstPixelSquare[j].R, firstPixelSquare[j].G, firstPixelSquare[j].B).Substring(0, 3));
                    hslFirstPixelSquare[j].s = Convert.ToDouble(rgbToHsl(firstPixelSquare[j].R, firstPixelSquare[j].G, firstPixelSquare[j].B).Substring(3, 3));
                    hslFirstPixelSquare[j].l = Convert.ToDouble(rgbToHsl(firstPixelSquare[j].R, firstPixelSquare[j].G, firstPixelSquare[j].B).Substring(6, 3));
                }
            }

1 个答案:

答案 0 :(得分:1)

原始算法存在两个问题:

此处声明的变量从未使用过:

    double rDecimal = r / 255;
    double gDecimal = g / 255;
    double bDecimal = b / 255;

在任何地方切换r的{​​{1}},或者只是重命名输入以继续使用rDecimal变量:

r, g, b

第二个问题也在这一部分。输入为public String RgbToHsl(int rInput, int gInput, int bInput) { double h, s, l; double r = rInput / 255; double g = gInput / 255; double b = bInput / 255; s,您除以255(也是int)。这导致整数除法,每次将产生0。你需要除以255.0来强制进行双重划分:

int

完成后,您需要将结果从[0,1]间隔转换为从工具中获得的结果。我能够最接近的是将结果乘以239然后舍入。可能从更多输入/输出示例中找到真实模式/精确值...

public String RgbToHsl(int rInput, int gInput, int bInput)
{
    double h, s, l;
    double r = rInput / 255.0;
    double g = gInput / 255.0;
    double b = bInput / 255.0;