Is there a built-in C#/.NET System API for HSV to RGB?

36,061

Solution 1

I don't think there's a method doing this in the .NET framework.
Check out Converting HSV to RGB colour using C#

This is the implementation code,

void HsvToRgb(double h, double S, double V, out int r, out int g, out int b)
{    
  double H = h;
  while (H < 0) { H += 360; };
  while (H >= 360) { H -= 360; };
  double R, G, B;
  if (V <= 0)
    { R = G = B = 0; }
  else if (S <= 0)
  {
    R = G = B = V;
  }
  else
  {
    double hf = H / 60.0;
    int i = (int)Math.Floor(hf);
    double f = hf - i;
    double pv = V * (1 - S);
    double qv = V * (1 - S * f);
    double tv = V * (1 - S * (1 - f));
    switch (i)
    {

      // Red is the dominant color

      case 0:
        R = V;
        G = tv;
        B = pv;
        break;

      // Green is the dominant color

      case 1:
        R = qv;
        G = V;
        B = pv;
        break;
      case 2:
        R = pv;
        G = V;
        B = tv;
        break;

      // Blue is the dominant color

      case 3:
        R = pv;
        G = qv;
        B = V;
        break;
      case 4:
        R = tv;
        G = pv;
        B = V;
        break;

      // Red is the dominant color

      case 5:
        R = V;
        G = pv;
        B = qv;
        break;

      // Just in case we overshoot on our math by a little, we put these here. Since its a switch it won't slow us down at all to put these here.

      case 6:
        R = V;
        G = tv;
        B = pv;
        break;
      case -1:
        R = V;
        G = pv;
        B = qv;
        break;

      // The color is not defined, we should throw an error.

      default:
        //LFATAL("i Value error in Pixel conversion, Value is %d", i);
        R = G = B = V; // Just pretend its black/white
        break;
    }
  }
  r = Clamp((int)(R * 255.0));
  g = Clamp((int)(G * 255.0));
  b = Clamp((int)(B * 255.0));
}

/// <summary>
/// Clamp a value to 0-255
/// </summary>
int Clamp(int i)
{
  if (i < 0) return 0;
  if (i > 255) return 255;
  return i;
}

Solution 2

There isn't a built-in method for doing this, but the calculations aren't terribly complex.
Also note that Color's GetHue(), GetSaturation() and GetBrightness() return HSL values, not HSV.

The following C# code converts between RGB and HSV using the algorithms described on Wikipedia.
I already posted this answer here, but I'll copy the code here for quick reference.

The ranges are 0 - 360 for hue, and 0 - 1 for saturation or value.

public static void ColorToHSV(Color color, out double hue, out double saturation, out double value)
{
    int max = Math.Max(color.R, Math.Max(color.G, color.B));
    int min = Math.Min(color.R, Math.Min(color.G, color.B));

    hue = color.GetHue();
    saturation = (max == 0) ? 0 : 1d - (1d * min / max);
    value = max / 255d;
}

public static Color ColorFromHSV(double hue, double saturation, double value)
{
    int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
    double f = hue / 60 - Math.Floor(hue / 60);

    value = value * 255;
    int v = Convert.ToInt32(value);
    int p = Convert.ToInt32(value * (1 - saturation));
    int q = Convert.ToInt32(value * (1 - f * saturation));
    int t = Convert.ToInt32(value * (1 - (1 - f) * saturation));

    if (hi == 0)
        return Color.FromArgb(255, v, t, p);
    else if (hi == 1)
        return Color.FromArgb(255, q, v, p);
    else if (hi == 2)
        return Color.FromArgb(255, p, v, t);
    else if (hi == 3)
        return Color.FromArgb(255, p, q, v);
    else if (hi == 4)
        return Color.FromArgb(255, t, p, v);
    else
        return Color.FromArgb(255, v, p, q);
}

Solution 3

It's not built in, but there's there's an open-source C# library called ColorMine which makes converting between color spaces pretty easy.

Rgb to Hsv:

var rgb = new Rgb {R = 123, G = 11, B = 7};
var hsv = rgb.To<Hsv>();

Hsv to Rgb:

var hsv = new Hsv { H = 360, S = .5, L = .17 }
var rgb = hsv.to<Rgb>();

Solution 4

For this you can use ColorHelper library:

RGB rgb = ColorConverter.HsvToRgb(new HSV(100, 100, 100));
Share:
36,061
caseyamcl
Author by

caseyamcl

I'm a Java and .Net programmer.

Updated on February 06, 2022

Comments

  • caseyamcl
    caseyamcl over 2 years

    Is there an API built into the .NET framework for converting HSV to RGB? I didn't see a method in System.Drawing.Color for this, but it seems surprising that there wouldn't be one in the platform.

  • MusiGenesis
    MusiGenesis over 14 years
    Thanks for that method. Weird that Color has .GetHue(), .GetSaturation() and .GetBrightness(), but no inverse method like .fromHSB().
  • caseyamcl
    caseyamcl over 14 years
    Indeed... its a very strange omission, imo.
  • Admin
    Admin almost 10 years
    Why not return a Color object instead of using out for three separate values?
  • Patrik Svensson
    Patrik Svensson almost 10 years
    The code is posted from the provided link and is not mine.
  • O. R. Mapper
    O. R. Mapper about 9 years
    @FizzledOut: Maybe because like this, the code can directly be used for SWF Color, WPF Color, Gdk# Color, and others.
  • Chris Moschini
    Chris Moschini almost 9 years
    If you start with for example, System.Drawing.Color.FromArgb(255, 0, 0), use .GetHue() etc to emit that to HSV, then use this code to roundtrip back to a Color, you get rgb 127, 0, 0. .GetBrightness() returns 0.5, and this code interprets that to mean the dominant color is 255*.5 = 127. At least from my perspective that means this code does not work properly.
  • Isaac Bolinger
    Isaac Bolinger over 8 years
    Your ColorFromHSV might have something wrong with it, I was trying to rotate the hue 180 degrees using your code for an opposite color and it's not working too well. The accepted code gives a different color which seems correct to me.
  • Isaac Bolinger
    Isaac Bolinger over 8 years
    I'm using your ColorToHSV function, however. It seems to work well.
  • Isaac Bolinger
    Isaac Bolinger over 8 years
    I'm using a combination of the above code, and ColorToHSV given below. Works great.
  • xmedeko
    xmedeko over 6 years
    @IsaacBolinger does not work well with negative hue, workd well for hue >= 0, but better to use hue between <0, 360) in your code.
  • Manfred
    Manfred almost 6 years
    The ColorMine repository seems to have disappeared (404 on github as of 05 Aug 2018). Also, there doesn't seem to be a successor repository owned by Joe. However, I found ColorMinePortable which may be close enough.
  • flndr
    flndr about 5 years
    Just doing a quick search, it looks like the user might have deleted their repo. It was forked by others though: github.com/hvalidi/ColorMine
  • Stefan
    Stefan about 4 years
    Wouldn't be H = (H % 360 + 360) % 360; be way more efficient than those two while loops?
  • Bloopy
    Bloopy over 2 years
    @IsaacBolinger I wanted the same and changing the hue line to the following worked perfectly for me: hue = (color.GetHue() + 180) % 360