How to Convert RGB Color to HSV?
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
Tom Smykowski
Updated on October 29, 2021Comments
-
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 over 14 yearsAs you point out, this doesn't actually answer the question because these methods provide a RGB to HSL conversion, not RGB to HSV.
-
leppie over 14 years@greg: I agree, this will lead to terrible results, as I have experienced myself.
-
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 over 14 yearsi 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 over 14 yearsi'll just edit the answer, transposing Saturation and Value numbers. Saturation should be 0.75, Value should be 0.7843...
-
Dan Messing over 11 yearsThis 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 almost 11 yearsI'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 over 8 yearsAny idea how to convert saturation from 0-1 to the saturation value that MS Paint uses (ie 0-240 scale)?
-
WSBT about 8 yearsGreat answer! Maybe consider using float instead of double, to be consistent with what .NET color.GetHue() returns?
-
dotNET over 6 yearsDon'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))
returns32
, butToHSV(FromHSV(33,1, 1))
returns32.9411773
.ToHSV(FromHSV(34,1, 1))
returns33.8823547
.ToHSV(FromHSV(35,1, 1))
returns35.0588264
.ToHSV(FromHSV(36,1, 1))
returns36
again. It appears that multiples of4
work correctly, while others are shifted by a multiple of1/17
. Now where does that magic number come from, I have got no idea. -
dotNET over 6 yearsGot 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 over 5 yearsThis is not HSV but HSL. stackoverflow.com/questions/15668623/hsb-vs-hsl-vs-hsv
-
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 thatColor.GetBrightness()
returns lightness, not value (i.e., it’s not the “V” in HSV, but the “L” in HSL). -
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 over 2 years@Berig In the method signature for
ColorToHSV
the parametershue
,saturation
, andvalue
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 about 2 yearsNote: Greg's linked answer also includes
ColorFromHSV
, which is the opposite direction.