středa 1. července 2015

Color conversion from Hue to RGB without ifs

The conversion of Hue value to RGB components usually involves a set of conditions because there are six different intervals of hue values where always two of the RGB components reach maximum value or zero while the third one is the only one changing between zero and the maximum.  One of many examples can be seen here.
Although such approach is technically correct and, of course, returns correct value, the number of necessary if statements gives the algorithm untidy and kind of "unsystematic" look and feel.
Considering the circular essence of Hue, one can intuitively feel that it should be enough to have one function converting Hue to the respective Red, Green or Blue value, using a "rotation" parameter.
Let us remember that maximum Red value is occurs at Hue = 0° or 360°, and maximum Green and Blue occur at 120° and 240°, respectively.  Additionally, the red maximum 100% occurs in the intervals from 0° to 60° and between 300° and 360°.  If we translate these values from 0°...360° range to -180°...+ 180°, we can see that the interval -60° to 60° is 100% Red and the adjacent 60 degree segments represent red fade-out zone.
Obviously, the Red maximum is at Hue = 0°.  Thus, the Red component will depend on the Hue distance from zero.  
R' = | Hue mod 360 - 180 | 
The next task is to ensure that Red will become zero at the distance of 120° from Hue = 0° and that it will be constant and maximal between -60° and +60°.  In the interval of interest value of R' is within the range <60,180>. To adjust the value to zero we just subtract 60:
R'' = | Hue mod 360 - 180 | - 60
Now our R'' value is between 0 and 120 in the interval of interest.  However, we want to make Red constant within ±60° around Hue = 0°.  Easy to do, we will cap the value not to exceed R'' for Hue = 60°, i.e. 60.  In most programming languages we can use minimum function to achieve the capping:
R''' = MIN( | Hue mod 360 - 180 | - 60, 60 )
Our Hue to Red conversion is almost perfect. Within 60° off Hue = 0 we have the maximum Red and within 120° around zero the Red gradually fades out.  However, for Hue < -120 or Hue > 120 our Red value (R''') is negative.  To keep Red within the range of non-negative numbers we will use the same trick that we used for cap, now setting the floor to be zero:
Red = MAX ( MIN( | Hue mod 360 - 180 | - 60, 60 ), 0 )
So, we are done with the Red.  How about Green and Blue, though?  RGB colors in HSL scheme are placed around a circle, do you remember? Therefore we can use the same algorithm for Green and Blue, we just need to "rotate" the input Hue value to obtain the correct Green and Blue maxima.  The Green maximum occurs at Hue = 120, i.e. shifted by +120° from the Red maximum.  We have to subtract 120° from Hue to obtain Green value.  And because the circle has 360°, subtracting 120° is the same as adding 240°:
Green = MAX ( MIN( | (Hue+240) mod 360 - 180 | - 60, 60 ), 0 )
And the Blue value will be obtained using the same pattern, only this time the shift will be 120°:
Blue = MAX ( MIN( | (Hue+120) mod 360 - 180 | - 60, 60 ), 0 )
Go, try this in your favorite programming language.  Can you implement this in your Arduino driving red, green and blue LEDs?

Žádné komentáře:

Okomentovat