HSV Colors

Adam Haile edited this page Mar 23, 2017 · 4 revisions

Most of the credit for the following goes to FastLED, without which the BiblioPixel HSV code would be much slower.

The Hue-Saturation-Value color model differs from 'traditional' computer HSV color models in two important respects: first is differences in the numeric range of values used to represent colors (everything here is a one-byte value from 0-255), and second is in the mapping of hue numbers to colors themselves (BiblioPixel defaults to using a richer 'rainbow' color map, instead of the traditional 'spectrum' color mapping).

Numeric range differences: everything here is 0-255

In 'traditional' computer HSV color models, hue is represented as a number (of degrees) from 0-360. Saturation and value are often represented as numbers (percentages) from 0-100. But neither "360" nor "100" is a particularly computer-native number, and there's no strong reason to use 'degrees' to represent hue, nor 'percentages' to represent saturation or value; they're all pretty much arbitrary scales. Accordingly, to make your code smaller, faster, and more efficient, the BiblioPixel library uses simple one-byte values (from 0-255) for hue, and for saturation, and for value. The performance implications are discussed further below, but suffice it to say that it's faster this way.

Color map: "Rainbow" vs "Spectrum"

Traditional computer HSV color models use a 'spectrum' color map, and BiblioPixel does offer a "hsv2rgb_spectrum" function. However, by default BiblioPixel uses a 'rainbow' color map instead of a spectrum. The 'rainbow' color map provides more evenly-spaced color bands, including a band of 'yellow' which is the same width as other colors, and which has an appropriately high inherent brightness. Traditional 'spectrum' HSV color maps have much narrower bands of yellow, and the yellow can also appear muddy. (Wikipedia has further discussion about the nature of spectrum-vs-rainbow: http://en.wikipedia.org/wiki/Rainbow#Number_of_colours_in_spectrum_or_rainbow )

Here is the "Rainbow" color map that BiblioPixel uses for everything by default: Click here for full-size chart.

Here is the "Spectrum" color map that BiblioPixel provides if you call hsv2rgb_spectrum explicitly: Click here for full-size chart.

These charts show several things about each part of the color map:

  • The bottom grayscale bar is the Radiance of each color: the total amount of light emitted. The BiblioPixel color maps have extremely uniform radiance across the entire color map, and a correspondingly uniform power consumption across colors. In the Rainbow color map, rendering yellow takes a little bit more power than other colors, but otherwise the power usage and radiance curves are absolutely flat.
  • The top grayscale bar is the Luminance (Y) of each color: Luminance is Radiance weighted by the sensitivity of the human eye to each component of the light, and represents the apparent brightness of each color, more or less. All things being equal, the human eye is most sensitive to green.
  • The mixed color itself, rendered in such a way that it 'looks about right' on a computer monitor, despite the fact that in practice the color will be generated by a set of independent LEDs.
  • The Red, Green, and Blue components of each color, shown below the color mix.

Why BiblioPixel full-range one-byte hues are faster

Animations using BiblioPixel HSV colors are often be much, much faster than traditional HSV code, because BiblioPixel HSV code has been designed for maximum performance, even when running on slower embedded devices like the Raspberry Pi. One of the big design decisions was to represent hue as a number from 0-255, rather than from 0-359 (or 0-95); here's an example of how the BiblioPixel hue range design (from 0-255) makes your animation code faster, just by keeping 'hue' down to a single full-range one-byte number.

Each of the following 3 lines of code were run 10,000 times on a Windows 8 system running on a 4th Gen 2.8GHz Core i7.

#hue2rgb uses an internal lookup table
colors = [colors.hue2rgb_raw(h) for h in range(256)]
#hsv2rgb uses the BiblioPixel single byte HSV conversion code
colors = [colors.hsv2rgb_raw((h, 255, 255)) for h in range(256)]
#hsv2rgb_360 uses python native colorsys.hsv_to_rgb
colors = [colors.hsv2rgb_360((h, 1.0, 1.0)) for h in range(256)]

The average time for each is as follows:

As you can see, hsv2rgb_360 (which uses the python native, 0-360, colorsys.hsv_to_rgb) takes almost twice as long as the BiblioPixel hsv2rgb method. More important, when at all possible, the hue2rgb method should be used which is 4 times faster still. This method only takes the desired hue value and assumes maximum saturation and value but uses a look-up table instead for performance. If 0-360 hue values are required but saturation and value can be maximum values, hue2rgb_360 is also provided which provides similar performance to hue2rgb.