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

- 25,487
- 54
- 159
- 236
-
35Not an _exact_ duplicate. HSL != HSV. – Adam Rosenfield Dec 11 '08 at 15:01
-
What to do to adapt code from HSL post to use in HSV solution? – Tom Smykowski Dec 11 '08 at 15:03
-
8Wikipedia: Both are mathematically cylindrical, but HSV can be thought of conceptually as an inverted cone of colors, HSL conceptually represents a double-cone or sphere. While “hue” in HSL and HSV refers to the same attribute, their definitions of “saturation” differ dramatically. – BlaM Dec 11 '08 at 15:05
-
2@Adam: I wish the Paint.NET people could figure that out! :) – leppie Jul 27 '09 at 10:56
-
4RE-iterating: HSV is very different from HSL. HSV is sometimes known as HSB (especially in Photoshop, and in .NET) – Ian Boyd Dec 20 '09 at 15:45
7 Answers
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);
}

- 23,155
- 11
- 57
- 79
-
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 – Ian Boyd Dec 20 '09 at 16:13
-
i'll just edit the answer, transposing Saturation and Value numbers. Saturation should be 0.75, Value should be 0.7843... – Ian Boyd Dec 20 '09 at 16:16
-
Any idea how to convert saturation from 0-1 to the saturation value that MS Paint uses (ie 0-240 scale)? – Jake Drew Jan 01 '16 at 02:26
-
Great answer! Maybe consider using float instead of double, to be consistent with what .NET color.GetHue() returns? – WSBT Apr 23 '16 at 23:38
-
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 Nov 28 '17 at 16:31
-
1Got 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. – dotNET Nov 29 '17 at 05:00
-
@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? – Oct 28 '21 at 22:43
-
@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. – Greg Oct 30 '21 at 05:31
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.

- 3,871
- 6
- 44
- 72

- 1,348
- 2
- 12
- 12
-
9As you point out, this doesn't actually answer the question because these methods provide a RGB to HSL conversion, not RGB to HSV. – Greg Oct 26 '09 at 17:38
-
3@greg: I agree, this will lead to terrible results, as I have experienced myself. – leppie Nov 05 '09 at 12:01
-
14-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) – Ian Boyd Dec 20 '09 at 15:44
-
1I'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. – Itai Bar-Haim May 21 '13 at 15:54
-
1@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](https://learn.microsoft.com/en-us/dotnet/api/system.drawing.color.getbrightness), not value (i.e., it’s not the “V” in HSV, but the “L” in HSL). – Informagic Sep 07 '19 at 22:12
The EasyRGB has many color space conversions. Here is the code for the RGB->HSV conversion.

- 905
- 2
- 18
- 31
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

- 28,465
- 32
- 91
- 105
-
4This implementation is not correct. It seems to be [based on this example code](http://en.literateprograms.org/RGB_to_HSV_color_space_conversion_%28C%29) but it's missing a section (the normalization part). Had me tripped up for a while! – Dan Messing Aug 08 '12 at 21:25
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

- 1
- 1

- 408
- 6
- 18
I've ended up here by having the same need.
Bellow I'm sharing the best and simpler solution I could find so far.
This is a modified answer from Greg's (found here); but with a humbler and understandable code.
For those who are learning I've added a few references that are worth checking for the sake of understanding.
References
- "Lukas Stratmann" HSV Model Tool (Incl. Other Model Systems: CMY / CMYK / HSL)
- "The HSV Color Model in Graphic Design"
- "Formula to Determine Perceived Brightness of RGB Color"
- Fastest Formula to Get Hue from RGB
- "Color Conversion Algorithms"
- "Program to Change RGB color model to HSV color model"
- "RGB to HSV Color Conversion Algorithm"
- "RGB to HSV Color Space Conversion (C)"
- "How to Convert RGB Color to HSV"
Code
/// <summary> Convert RGB Color to HSV. </summary>
/// <param name="color"></param>
/// <returns> A double[] Containing HSV Color Values. </returns>
public double[] rgbToHSV(Color color)
{
double[] output = new double[3];
double hue, saturation, 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;
output[0] = hue;
output[1] = saturation;
output[2] = value;
return output;
}
-
Note: Greg's linked answer also includes `ColorFromHSV`, which is the opposite direction. – ToolmakerSteve May 01 '22 at 19:17
FIRST: make sure you have a color as a bitmap, like this:
Bitmap bmp = (Bitmap)pictureBox1.Image.Clone();
paintcolor = bmp.GetPixel(e.X, e.Y);
(e is from the event handler wich picked my color!)
What I did when I had this problem a whilke ago, I first got the rgba (red, green, blue and alpha) values. Next I created 3 floats: float hue, float saturation, float brightness. Then you simply do:
hue = yourcolor.Gethue;
saturation = yourcolor.GetSaturation;
brightness = yourcolor.GetBrightness;
The whole lot looks like this:
Bitmap bmp = (Bitmap)pictureBox1.Image.Clone();
paintcolor = bmp.GetPixel(e.X, e.Y);
float hue;
float saturation;
float brightness;
hue = paintcolor.GetHue();
saturation = paintcolor.GetSaturation();
brightness = paintcolor.GetBrightness();
If you now want to display them in a label, just do:
yourlabelname.Text = hue.ToString;
yourlabelname.Text = saturation.ToString;
yourlabelname.Text = brightness.ToString;
Here you go, you now have RGB Values into HSV values :)
Hope this helps

- 43
- 11
-
1This is not HSV but HSL. https://stackoverflow.com/questions/15668623/hsb-vs-hsl-vs-hsv – Sha Sep 21 '18 at 11:01