The HSV Colour Model

By Mark Roberts


The HSV model is based on the following concepts

This means that the colour can be manipulated in more intuitive terms (although hue is not very easy to imagine).  HSV models are normally represented as a 2D plot of to of the attributes and a single 1D plot of the third.  The image below shows a H/S plot with separate brightness for the marked point.


 
 

Figure 2.  A H/S space with a V scale of the point marked.

The HSV colour space has the shape of a hexagonal cone.  The reasons for this become obvious after looking at the folloiwng diagram.  It shows the standard RGB colour cube, viewed along the black/white diagonal.  This view shows the top of the HSV hexcone.
 
 
 
 

Figure 3. The RGB cube (left) viewed from above forming the top of the HSV hexcone (right)

Representation of HSV Values

We obviously need a specialised representation for these these values.  There representations are as follows
 
Hue 0 to 360 degrees around the cone
Saturation  0 to 1, distance from the centre of the cone
Value 0 to 1, vertical position in the cone where 0 = black and 1 = white

What does it look like?

HSV to RGB conversion

The following piece of C++ code shows how to do the HSV->RGB and RGB->HSV conversion.  Calculating the hue is the hardest part and involves working out how far through each segment the value is.
 
  #include <math.h>

void HSVtoRGB()
{
    int i;
    float f, p, q, t,hTemp;
 
    if( s == 0.0 || h == -1.0) // s==0? Totally unsaturated = grey so R,G and B all equal value
    {
      r = g = b = v;
      return;
    }
    hTemp = h/60.0f;
    i = (int)floor( hTemp );                 // which sector
    f = hTemp - i;                      // how far through sector
    p = v * ( 1 - s );
    q = v * ( 1 - s * f );
    t = v * ( 1 - s * ( 1 - f ) );
 
    switch( i ) 
    {
    case 0:{r = v;g = t;b = p;break;}
    case 1:{r = q;g = v;b = p;break;}
    case 2:{r = p;g = v;b = t;break;}
    case 3:{r = p;g = q;b = v;break;} 
    case 4:{r = t;g = p;b = v;break;}
    case 5:{r = v;g = p;b = q;break;}
    }
}
 
 void RGBtoHSV()
 {

    float mn=r,mx=r;
    int maxVal=0;
 
    if (g > mx){ mx=g;maxVal=1;}
    if (b > mx){ mx=b;maxVal=2;} 
    if (g < mn) mn=g;
    if (b < mn) mn=b; 

    float  delta = mx - mn;
 
    v = mx; 
    if( mx != 0 )
      s = delta / mx; 
    else 
    {
      s = 0;
      h = 0;
      return;
    }
    if (s==0.0f)
    {
      h=-1;
      return;
    }
    else
    { 
      switch (maxVal)
      {
      case 0:{h = ( g - b ) / delta;break;}         // yel < h < mag
      case 1:{h = 2 + ( b - r ) / delta;break;}     // cyan < h < yel
      case 2:{h = 4 + ( r - g ) / delta;break;}     // mag < h < cyan
      }
    }
 
    h *= 60;
    if( h < 0 ) h += 360;
}