userx01
userx01

Reputation: 275

understanding HSL to RGB color space conversion algorithm

I've read the HSL to RGB algorithm in wikipedia. I understand it and can convert using it. However I came upon another algorithm here, and the math is "explained" here.

The algorithm is:

//H, S and L input range = 0 ÷ 1.0
//R, G and B output range = 0 ÷ 255

if ( S == 0 )
{

   R = L * 255
   G = L * 255
   B = L * 255
}
else
{
   if ( L < 0.5 ) var_2 = L * ( 1 + S )
   else           var_2 = ( L + S ) - ( S * L )

   var_1 = 2 * L - var_2

   R = 255 * Hue_2_RGB( var_1, var_2, H + ( 1 / 3 ) )
   G = 255 * Hue_2_RGB( var_1, var_2, H )
   B = 255 * Hue_2_RGB( var_1, var_2, H - ( 1 / 3 ) )
}

Hue_2_RGB( v1, v2, vH )             //Function Hue_2_RGB
{
   if ( vH < 0 ) vH += 1
   if( vH > 1 ) vH -= 1
   if ( ( 6 * vH ) < 1 ) return ( v1 + ( v2 - v1 ) * 6 * vH )
   if ( ( 2 * vH ) < 1 ) return ( v2 )
   if ( ( 3 * vH ) < 2 ) return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6)
   return ( v1 )
}

I've tried following the math but I can't figure it. How does it work?

Upvotes: 1

Views: 1389

Answers (2)

racitup
racitup

Reputation: 464

If anyone would like a much simplified version, using 8bit integers rather than floats and using max colour intensity (L = 0.5, S = 1; meaning v1 = 0.0, v2 = 1.0) it might help to explain things.

  • For the 1st sixth of hue, brightness of either RGB is increased from zero to max
  • For the next third of hue, brightness of either RGB is max
  • For the next sixth of hue, brightness of either RGB is decreased to zero
  • For the remainder third, brightness of either RGB is zero
  • RGB are offset from each other by a third
void huetoRGB (const uint8_t hue, uint8_t *RGB) {
  RGB[0] = hueconv(hue + 85);   // R
  RGB[1] = hueconv(hue);        // G
  RGB[2] = hueconv(hue - 85);   // B
}

// 0 <= vH <= 255
uint8_t hueconv(int vH) {
  if (vH < 0) vH += 256;
  if (vH > 255) vH -= 256;
  if (vH <= 42) return 6 * vH;
  if (vH <= 127) return 255;
  if (vH <= 170) return (170 - vH) * 6;
  return 0;
}

Upvotes: 0

gsamaras
gsamaras

Reputation: 73444

The first part if ( S == 0 ) is for the case that there is no Saturation it means that it’s a shade of grey. You set the Luminance, set RGB to that grey scale level and you are done.

If this is not the case, then we need to perform the tricky part:

We shall use var_1 and var_2 as temporary values, only for making the code more readable.

So, if Luminance is smaller then 0.5 (50%) then var_2 = Luminance x (1.0 + Saturation. If Luminance is equal or larger then 0.5 (50%) then var_2 = Luminance + Saturation – Luminance x Saturation. That's the else part of:

if ( L < 0.5 ) var_2 = L * ( 1 + S )
else           var_2 = ( L + S ) - ( S * L )

Then we do:

var1 = 2 x Luminance – var_2

which is going to be useful later.

Now we need another three temporary variables for each color channel, as far as Hue is conserned. For Red, we add 0.333 to it (H + (1/3) in code), for Green we do nothing, and for Blue, we subtract 0.333 from it (H + (1/3)). That temporaty value is called vH (value Hue) in Hue_2_RGB().

Now each color channel will be treated separetely, thus the three function calls. There are four formulas that can be applied to a color channel. Every color channel should "use" only one formula.

Which one? It depends on the value of Hue (vH).

By the way, the value of vH must be normalized, thus if it's negative we add 1, or if it's greater than 1, we subtract 1 from it, so that vH lies in [0, 1].

  1. If 6 x vH is smaller then 1, Color channel = var_1 + (var_2 – var_1) x 6 x vH
  2. If 2 x vH is smaller then 1, Color channel = var_2
  3. If 3 x vH is smaller then 2, Color channel = var_1 + (var_2 – var_1) x (0.666 – vH) x 6
  4. Else, Color channel = var_1

For R = 255 * Hue_2_RGB( var_1, var_2, H + ( 1 / 3 ) ), the Color Channel would be the Red, named R in the code.

Upvotes: 1

Related Questions