开发者

Converting RGB to HSB Colors

I am trying to convert a HSB Color to RGB. The way I am doing that is

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);

I find that when I have FF0000, it will be converted to H = 0, S = 255, L = 127 which converts to RGB FF0E0E. I think Luminosity should be 120? Or am I getting the whole HSB thing wrong? When I look at the color picker in Photoshop, Hue is 0-360 degrees, Saturation, Luminosity is 0-100%. I开发者_如何学Go am having HSB values ranging from 0 - 255, am I doing it wrong?


Maybe you already look into this wikipedia article, but to make it clear.

There is a difference between HSL and HSB (aka HSV).

So you can't take the (B)rightness from the color class and use it like a (L)uminosity.

To get back from the Color class provided values GetHue(), GetSaturation() and GetBrightness() to a normal color you should give this extension method a chance.

/// <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);
    }
}

Update

So just to make things clear. My code above and the three methods within the Color class mentioned above are using the HSB (aka HSV) color model, but Photoshop uses the HSL color model.

In your comment you wrote that the parameters Hue = 0, Saturation = 1 and Brightness = 1 give you with the code above a red color and white in Photoshop. When you take a closer look at the differences of these modes this makes absolutely sense:

The HSL cylinder

Converting RGB to HSB Colors


(source: wikimedia.org)

  • In both models the hue acts as the same by using color Red as start and end point (zero and 360 degree).
    • By just looking at the hue you've got a red color.
  • The saturation defines how opaque the color is or how much the portion of a whitescale is.
    • So by setting it to one you say you want a full shiny red color.
  • The lighting now defines how much is the black and white part within your color. By setting it to zero you got black, one means white and 0.5 means perfect weighting.
    • So by setting it to one you say you want it as bright as possible which result in a white color.

The HSB cylinder

Converting RGB to HSB Colors


(source: wikimedia.org)

  • In both models the hue acts as the same by using color Red as start and end point (zero and 360 degree).
    • By just looking at the hue you've got a red color.
  • The saturation defines how opaque the color is or how much the portion of a whitescale is.
    • So by setting it to one you say you want a full shiny red color.
  • The brightness (or value) now defines how much is the black part within the color (not the white part).
    • So by setting it to one you say you want it full colored leading to a full shiny red color.

As you can see, Photoshop and the .Net framework (including my extension function) are using different coloring models. So you should check if you find somewhere an implementation of the other coloring model, a transformation or something else that gives you the results you need.


This works...modified from Java source code. The other answer is still HSL, This really is HSB to RGB (actually it's HSB/HSV to System.Windows.Media.Color as my return type)

    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));
    }


Since the other answers don't seem to work for me (and I didn't have the patience to see what's going on), I'm sharing my code for HSV->RGB conversion. It's based on the section "Alternate HSV conversion" on Wikipedia and is quite compact.

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));
}


You can use ColorHelper library for this:

using ColorHelper;

RGB rgb = new RGB(20, 20, 20);
HSV hsv = ColorConverter.RgbToHsv(rgb);

Links:

  • Github
  • Nuget
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜