将RGB转换为HSB颜色

时间:2010-11-05 13:43:31

标签: c# colors

我正在尝试将HSB颜色转换为RGB。我这样做的方式是

System.Windows.Media.Color winColor = value;
System.Drawing.Color drawColor = System.Drawing.Color.FromArgb(winColor.R, winColor.G, winColor.B);
Hue = (byte)(drawColor.GetHue()*255);
Saturation = (byte)(drawColor.GetSaturation()*255);
Luminosity = (byte)(drawColor.GetBrightness()*255);

我发现当我FF0000时,它会转换为H = 0, S = 255, L = 127,转换为RGB FF0E0E。我觉得Luminosity应该是120?或者我是否让整个HSB错误?当我在Photoshop中查看颜色选择器时,Hue为0-360度,饱和度,亮度为0-100%。我的HSB值介于0到255之间,我做错了吗?

3 个答案:

答案 0 :(得分:11)

也许你已经调查了这个wikipedia article,但要说清楚。

HSL和HSB(又名HSV)之间存在差异。

所以你不能从颜色等级中取出(B)正确性并将其用作(L)不成熟之处。

要从Color类提供的值GetHue()GetSaturation()GetBrightness()恢复为正常颜色,您应该为此扩展方法提供机会。

/// <summary>
/// Creates a Color from alpha, hue, saturation and brightness.
/// </summary>
/// <param name="alpha">The alpha channel value.</param>
/// <param name="hue">The hue value.</param>
/// <param name="saturation">The saturation value.</param>
/// <param name="brightness">The brightness value.</param>
/// <returns>A Color with the given values.</returns>
public static Color FromAhsb(int alpha, float hue, float saturation, float brightness)
{
    if (0 > alpha
        || 255 < alpha)
    {
        throw new ArgumentOutOfRangeException(
            "alpha",
            alpha,
            "Value must be within a range of 0 - 255.");
    }

    if (0f > hue
        || 360f < hue)
    {
        throw new ArgumentOutOfRangeException(
            "hue",
            hue,
            "Value must be within a range of 0 - 360.");
    }

    if (0f > saturation
        || 1f < saturation)
    {
        throw new ArgumentOutOfRangeException(
            "saturation",
            saturation,
            "Value must be within a range of 0 - 1.");
    }

    if (0f > brightness
        || 1f < brightness)
    {
        throw new ArgumentOutOfRangeException(
            "brightness",
            brightness,
            "Value must be within a range of 0 - 1.");
    }

    if (0 == saturation)
    {
        return Color.FromArgb(
                            alpha,
                            Convert.ToInt32(brightness * 255),
                            Convert.ToInt32(brightness * 255),
                            Convert.ToInt32(brightness * 255));
    }

    float fMax, fMid, fMin;
    int iSextant, iMax, iMid, iMin;

    if (0.5 < brightness)
    {
        fMax = brightness - (brightness * saturation) + saturation;
        fMin = brightness + (brightness * saturation) - saturation;
    }
    else
    {
        fMax = brightness + (brightness * saturation);
        fMin = brightness - (brightness * saturation);
    }

    iSextant = (int)Math.Floor(hue / 60f);
    if (300f <= hue)
    {
        hue -= 360f;
    }

    hue /= 60f;
    hue -= 2f * (float)Math.Floor(((iSextant + 1f) % 6f) / 2f);
    if (0 == iSextant % 2)
    {
        fMid = (hue * (fMax - fMin)) + fMin;
    }
    else
    {
        fMid = fMin - (hue * (fMax - fMin));
    }

    iMax = Convert.ToInt32(fMax * 255);
    iMid = Convert.ToInt32(fMid * 255);
    iMin = Convert.ToInt32(fMin * 255);

    switch (iSextant)
    {
        case 1:
            return Color.FromArgb(alpha, iMid, iMax, iMin);
        case 2:
            return Color.FromArgb(alpha, iMin, iMax, iMid);
        case 3:
            return Color.FromArgb(alpha, iMin, iMid, iMax);
        case 4:
            return Color.FromArgb(alpha, iMid, iMin, iMax);
        case 5:
            return Color.FromArgb(alpha, iMax, iMin, iMid);
        default:
            return Color.FromArgb(alpha, iMax, iMid, iMin);
    }
}

更新

所以只是为了说清楚。我上面的代码和上面提到的Color类中的三个方法都使用HSB(aka HSV)颜色模型,但Photoshop使用HSL颜色模型。

在您的评论中,您写道参数Hue = 0Saturation = 1Brightness = 1会在Photoshop中为您提供红色和白色以上的代码。当你仔细研究这些模式的差异时,这绝对有意义:

HSL柱面

HSL cylinder

  • 在两种模型中,色调的作用相同,使用红色作为起点和终点(零点和360度)。
    • 只要看一下你的红色就会变成红色。
  • 饱和度定义了不透明颜色的方式或白色部分的大小。
    • 因此,通过将其设置为1,您说您想要一个完全闪亮的红色。
  • 灯光现在定义了您的颜色中黑色和白色部分的多少。通过将其设置为零,您将获得黑色,一个意味着白色,0.5意味着完美的权重。
    • 因此,通过将其设置为1,您可以说它希望它尽可能明亮,从而产生白色。

HSB柱面

HSB cylinder

  • 在两种模型中,色调的作用相同,使用红色作为起点和终点(零点和360度)。
    • 只要看一下你的红色就会变成红色。
  • 饱和度定义了不透明颜色的方式或白色部分的大小。
    • 因此,通过将其设置为1,您说您想要一个完全闪亮的红色。
  • 亮度(或值)现在定义颜色中的黑色部分(不是白色部分)的多少。
    • 因此,通过将其设置为1,您可以说它需要全彩色,从而产生完全闪亮的红色。

正如您所看到的,Photoshop和.Net框架(包括我的扩展功能)正在使用不同的着色模型。因此,您应该检查是否找到了其他着色模型的实现,转换或其他能够为您提供所需结果的实现。

答案 1 :(得分:3)

这可以...从Java源代码修改。另一个答案仍然是HSL,这实际上是HSB到RGB(实际上它是HSB / HSV到System.Windows.Media.Color作为我的返回类型)

    public static Color HSBtoRGB(float hue, float saturation, float brightness)
    {
        int r = 0, g = 0, b = 0;
        if (saturation == 0)
        {
            r = g = b = (int)(brightness * 255.0f + 0.5f);
        }
        else
        {
            float h = (hue - (float)Math.Floor(hue)) * 6.0f;
            float f = h - (float)Math.Floor(h);
            float p = brightness * (1.0f - saturation);
            float q = brightness * (1.0f - saturation * f);
            float t = brightness * (1.0f - (saturation * (1.0f - f)));
            switch ((int)h)
            {
                case 0:
                    r = (int)(brightness * 255.0f + 0.5f);
                    g = (int)(t * 255.0f + 0.5f);
                    b = (int)(p * 255.0f + 0.5f);
                    break;
                case 1:
                    r = (int)(q * 255.0f + 0.5f);
                    g = (int)(brightness * 255.0f + 0.5f);
                    b = (int)(p * 255.0f + 0.5f);
                    break;
                case 2:
                    r = (int)(p * 255.0f + 0.5f);
                    g = (int)(brightness * 255.0f + 0.5f);
                    b = (int)(t * 255.0f + 0.5f);
                    break;
                case 3:
                    r = (int)(p * 255.0f + 0.5f);
                    g = (int)(q * 255.0f + 0.5f);
                    b = (int)(brightness * 255.0f + 0.5f);
                    break;
                case 4:
                    r = (int)(t * 255.0f + 0.5f);
                    g = (int)(p * 255.0f + 0.5f);
                    b = (int)(brightness * 255.0f + 0.5f);
                    break;
                case 5:
                    r = (int)(brightness * 255.0f + 0.5f);
                    g = (int)(p * 255.0f + 0.5f);
                    b = (int)(q * 255.0f + 0.5f);
                    break;
            }
        }
        return Color.FromArgb(Convert.ToByte(255), Convert.ToByte(r), Convert.ToByte(g), Convert.ToByte(b));
    }

答案 2 :(得分:0)

由于其他答案似乎对我不起作用(并且我没有耐心来看看发生了什么事情),我将共享我的HSV-> RGB转换代码。它基于Wikipedia上的“备用HSV转换”部分,并且非常紧凑。

public static Color FromAhsv(byte alpha, float hue, float saturation, float value)
{
    if (hue < 0f || hue > 360f)
        throw new ArgumentOutOfRangeException(nameof(hue), hue, "Hue must be in the range [0,360]");
    if (saturation < 0f || saturation > 1f)
        throw new ArgumentOutOfRangeException(nameof(saturation), saturation, "Saturation must be in the range [0,1]");
    if (value < 0f || value > 1f)
        throw new ArgumentOutOfRangeException(nameof(value), value, "Value must be in the range [0,1]");

    int Component(int n)
    {
        var k = (n + hue / 60f) % 6;
        var c = value - value * saturation * Math.Max(Math.Min(Math.Min(k, 4 - k), 1), 0);
        var b = (int)Math.Round(c * 255);
        return b < 0 ? 0 : b > 255 ? 255 : b;
    }

    return Color.FromArgb(alpha, Component(5), Component(3), Component(1));
}