How to Convert RGB Color to HSV?

115,098

Solution 1

Have you considered simply using System.Drawing namespace? For example:

System.Drawing.Color color = System.Drawing.Color.FromArgb(red, green, blue);
float hue = color.GetHue();
float saturation = color.GetSaturation();
float lightness = color.GetBrightness();

Note that it's not exactly what you've asked for (see differences between HSL and HSV and the Color class does not have a conversion back from HSL/HSV but the latter is reasonably easy to add.

Solution 2

Note that Color.GetSaturation() and Color.GetBrightness() return HSL values, not HSV.
The following code demonstrates the difference.

Color original = Color.FromArgb(50, 120, 200);
// original = {Name=ff3278c8, ARGB=(255, 50, 120, 200)}

double hue;
double saturation;
double value;
ColorToHSV(original, out hue, out saturation, out value);
// hue        = 212.0
// saturation = 0.75
// value      = 0.78431372549019607

Color copy = ColorFromHSV(hue, saturation, value);
// copy = {Name=ff3278c8, ARGB=(255, 50, 120, 200)}

// Compare that to the HSL values that the .NET framework provides: 
original.GetHue();        // 212.0
original.GetSaturation(); // 0.6
original.GetBrightness(); // 0.490196079

The following C# code is what you want. It converts between RGB and HSV using the algorithms described on Wikipedia. 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

There's a C implementation here:

http://www.cs.rit.edu/~ncs/color/t_convert.html

Should be very straightforward to convert to C#, as almost no functions are called - just calculations.

found via Google

Solution 4

The EasyRGB has many color space conversions. Here is the code for the RGB->HSV conversion.

Solution 5

This is the VB.net version which works fine for me ported from the C code in BlaM's post.

There's a C implementation here:

http://www.cs.rit.edu/~ncs/color/t_convert.html

Should be very straightforward to convert to C#, as almost no functions are called - just > calculations.


Public Sub HSVtoRGB(ByRef r As Double, ByRef g As Double, ByRef b As Double, ByVal h As Double, ByVal s As Double, ByVal v As Double)
    Dim i As Integer
    Dim f, p, q, t As Double

    If (s = 0) Then
        ' achromatic (grey)
        r = v
        g = v
        b = v
        Exit Sub
    End If

    h /= 60 'sector 0 to 5
    i = Math.Floor(h)
    f = h - i 'factorial part of h
    p = v * (1 - s)
    q = v * (1 - s * f)
    t = v * (1 - s * (1 - f))

    Select Case (i)
        Case 0
            r = v
            g = t
            b = p
            Exit Select
        Case 1
            r = q
            g = v
            b = p
            Exit Select
        Case 2
            r = p
            g = v
            b = t
            Exit Select
        Case 3
            r = p
            g = q
            b = v
            Exit Select
        Case 4
            r = t
            g = p
            b = v
            Exit Select
        Case Else   'case 5:
            r = v
            g = p
            b = q
            Exit Select
    End Select
End Sub
Share:
115,098
Tom Smykowski
Author by

Tom Smykowski

Updated on October 29, 2021

Comments

  • Tom Smykowski
    Tom Smykowski over 2 years

    How can I convert a RGB Color to HSV using C#?
    I've searched for a fast method without using any external library.

  • Greg
    Greg over 14 years
    As you point out, this doesn't actually answer the question because these methods provide a RGB to HSL conversion, not RGB to HSV.
  • leppie
    leppie over 14 years
    @greg: I agree, this will lead to terrible results, as I have experienced myself.
  • mistertodd
    mistertodd over 14 years
    -1: As this is not the answer to the question. HSV is very different from HSL. Note: HSV is sometimes known as HSB (especially in Photoshop, and in .NET)
  • mistertodd
    mistertodd over 14 years
    i think you transposed the sample values of Saturation and Value in your answer. When i convert rgb(50,120,200) to Hue-Saturation-Value (HSV) i get hsv(212, 75%, 78.4%). Looking at wikipedia formulas for HSV: V=Max(r,g,b). In this case max(50,120,200)=200. 200/255 = 0.7843
  • mistertodd
    mistertodd over 14 years
    i'll just edit the answer, transposing Saturation and Value numbers. Saturation should be 0.75, Value should be 0.7843...
  • Dan Messing
    Dan Messing over 11 years
    This implementation is not correct. It seems to be based on this example code but it's missing a section (the normalization part). Had me tripped up for a while!
  • Itai Bar-Haim
    Itai Bar-Haim almost 11 years
    I'm not sure what the difference is between lightness, brightness and value (always thought they were synonyms), but looking at the System.Drawing.Color implementation I see it is not based on the NTSC weights for Red, Green and Blue, but treat them all the same, yielding suboptimal results.
  • Jake Drew
    Jake Drew over 8 years
    Any idea how to convert saturation from 0-1 to the saturation value that MS Paint uses (ie 0-240 scale)?
  • WSBT
    WSBT about 8 years
    Great answer! Maybe consider using float instead of double, to be consistent with what .NET color.GetHue() returns?
  • dotNET
    dotNET over 6 years
    Don't know if I'm doing something wrong, but this pair of functions doesn't do round-trip for me. Doing ToHSV(FromHSV(32,1, 1)) returns 32, but ToHSV(FromHSV(33,1, 1)) returns 32.9411773. ToHSV(FromHSV(34,1, 1)) returns 33.8823547. ToHSV(FromHSV(35,1, 1)) returns 35.0588264. ToHSV(FromHSV(36,1, 1)) returns 36 again. It appears that multiples of 4 work correctly, while others are shifted by a multiple of 1/17. Now where does that magic number come from, I have got no idea.
  • dotNET
    dotNET over 6 years
    Got it. HSV variables are using double type, which has got much higher granularity than what 8-bit RGB channels can hold. Therefore 100% round-trip mapping is not possible. However, I'm interested in knowing if these functions can be improved to perform safely for the RGB subset.
  • Sha
    Sha over 5 years
  • Informagic
    Informagic over 4 years
    @IanBoyd While what you’re stating wrt. HSV, HSL, and HSB is correct, the problem is that the System.Drawing implementation of HSB appears to be, in fact, a misnomer: they’ve implemented HSL. The .NET API states that Color.GetBrightness() returns lightness, not value (i.e., it’s not the “V” in HSV, but the “L” in HSL).
  • Admin
    Admin over 2 years
    @Greg: Please forgive my ignorant question (as I'm Learning on the go; so maybe I'm missing some C# Lessons) but... How would you get the value? The question suggests a way to retrieve a converted value. In my knowledge perspective your method requests the parameters that the user wants to retrieve and nothing is returned. Can you please enlighten me?
  • Greg
    Greg over 2 years
    @Berig In the method signature for ColorToHSV the parameters hue, saturation, and value are defined as "out parameters". Values are passed out of the method, not into the method, for those three parameters. The first block of code in the answer demonstrates calling the method.
  • ToolmakerSteve
    ToolmakerSteve about 2 years
    Note: Greg's linked answer also includes ColorFromHSV, which is the opposite direction.