LEDHSV - help me test a library

Status
Not open for further replies.

aedile

Member
I've recommended to enough people to use HSV colorspace instead of RGB for various projects that I thought it was time I took code I used and made it into a library.

https://github.com/aedile/LEDHSV

I'm not a C++ programmer at all (many other languages, though), so I'm not 100% sure if I'm breaking any fundamental rules or not. This is all based on trial and error (and help from cplusplus.com). If anybody has the time and the inclination, I'd love it if I could get some help testing/reviewing the code. There is an example sketch that uses three LEDs and a button to test the basic functionality. Here is a link to a video of the sketch running (it's a little washed out even though I set the brightness almost to zero, anybody have tips on filming LEDs?).

https://www.youtube.com/watch?v=ZnVeqdcNfQk

Also in the repository is auto-generated docs based on javadoc blocks. So far it's all worked pretty well, but I haven't done much beyond test it with 3 common cathode and then 3 common anode LEDs, all on a Teensy 2.0++. On my agenda is to test with a TLC5940 soon.

If you get around to playing with it and have suggestions, please don't hesitate to let me know here in a reply. Thanks very much in advance!
 
Just a note, I posted this to reddit as well in the arduino sub, and user SideSam had the following to say:
I have few ideas:
At void LEDHSV::setRedValue(int pRedValue){..}, if you are going to allow values from 0 to 255 why not use byte as type instead of silently setting them to 0 or 255? This way you would be able to catch problems during compile time.
Also the validation code is repeated in many places - encapsulate that into method/function (whaterver you guys call it).
If you are going to create this kind of complex library might as well add feature to compensate for non-linear human eye brightness perception, I really think that this is often forgotten feature.

I'm looking into human eye brightness perception (most of the links are to scientific studies), but the other pieces of advice make perfect sense and I plan on incorporating them right away.
 
This will be very helpful as I was planning to incorporate something similar into one of my projects. Thanks for posting this!
 
If you wanted to take into account the human perception of brightness (and human perception of hue differences), then HSV (and the related HSL) would be poor choices as, by design, they totally ignore them. Both color models are a reaction to the definition of CIE LAB, CIELUV and (in particular) their polar forms, in 1976. By ignoring the color measurement-based CIE XYZ on which LUV and LAB are built, and instead using the hardware-oriented RGB space as a basis, HSV and HSL give a similar-looking polar color space with a light-to-dark axis, a saturation or chroma axis, and a hue angle. They were published an implemented between 1977 and 1980.

The advantages of HSV and HSL are simple computation, ease of interpolating colors (there are no 'out of gamut' results) and no need for characterisation of the color generating device. The disadvantages are that comparing two HSV or HSL colors tells you little about how they look. As an example, RGB yellow (255, 255, 0) and RGB blue (0, 0, 255) have the same Lightness (in HSL) or Value (in HSV) while clearly, the yellow is much lighter than the blue. Also along the hue angle, some areas are bunched up while other areas are spread out in terms of how different they look for the same change in hue angle.

HSV and HSL still have value, in terms of selecting a single color with immediate visual feedback. Usability studies demonstrate an improvement in time to get reasonably close to a given color, compared to using RGB sliders. I suggest you concentrate on that advantage.

If on the other hand you want to go deeper into color perception, you would need a spectrometer to measure the emittance spectrum of each primary color that you are using, and either a spectro or a colorimeter to measure the transfer curve (relationship between input signal and light intensity). You could then check that they are additive, compute the gamut of displayable colors, and write a function which, given a color in LAB, would either let you display that color or say that it was out of gamut. It all depends really on what you want to use it for.
 
HSV and HSL still have value, in terms of selecting a single color with immediate visual feedback. Usability studies demonstrate an improvement in time to get reasonably close to a given color, compared to using RGB sliders. I suggest you concentrate on that advantage.

This was precisely why I went this route in the first place. I wanted user selectable custom colors in a project and my wife (who is my primary usability tester) couldn't make heads or tails of how to make the shade of pink she wanted with RGB sliders. HSV sliders, however, basically brought it down to one knob (although she liked lightening it with the saturation knob as well). The other thing I find really nice about HSV, especially when working with LEDs, is that it's MUCH easier to fade in and out with adjustments to a single value than calculating decrement percentages and hoping for the best.

Also along the hue angle, some areas are bunched up while other areas are spread out in terms of how different they look for the same change in hue angle.

I've noticed this in some situations. Particularly, red/magenta/purple seem to have overlarge areas and green/yellow are particularly hard to dial in directly. I've been thinking of ways to ameliorate this, perhaps changing the incremental resolution as I cycle through values, but that's an exercise for a later date.

I really appreciate the digest on human perception of brightness and colorspace! You've given me a lot to think about and I'll probably leave brightness perception off the table for now. Time is my most valuable asset right now, and you just saved me a bunch of it, so thanks very much!
 
Relatedly - the next release of FastSPI_LED2 will have a fairly high performance HSV2RGB library that will include, among other things:

* at least two 'profiles' for defining the color wheel (standard HSV, and something with a color distribution more in line with what you see in a rainbow)
* psychometric adjustments to account for things like extra-eye sensitivity to the color green as well as expected percetpion that at equal brightness/output, yellow "looks" brighter

and if time is kind to me, realtime translation from hsv to rgb while writing data out to the led hardware, so that instead of having one array of HSV data for doing your work in, and one array of RGB data for writing things out to the led strips, you just have one HSV data array - halving memory requirements :)

Finally - one piece of advice for your code - neither arduinos nor avrs have floating point hardware - making floating point operations really slow. This rapidly becomes an issue when you're juggling data for hundreds or thousands of leds.
 
... and by high performance I mean about 56 clock cycles on the teensy 3 to convert a pixel from hsv to rgb, and roughly 30-34 on avr (been a while since i've done exact measurements, this is roughly clock counting the asm that's used on avr). My partner in crime, and the primary force behind the hsv2rgb code we'll have has thoughts on one last round of optimization pushing for the teensy 3/arm code, too - so that number may go down before the final version of the library goes out :)
 
Last edited:
I have some code that does HSVtoRGB that uses only integer math tuhus its a lot less computationally expensive than a floating point algorithm. This is part of the library that goes along with my HPRGB LED shied http://ledshield.wordpress.com/ but is generic and can be used in any other library. It uses a resolution, however of 8 bit for H,S and V which produces suboptimal result and I have another less quick but much smoother algorithm with a higher resolution for H. It's not yet optimized for speed but works nicely. I can post Both if there is interest.
 
Few more things that came to my mind. It's not always true that HSV is better than RGB. It depends on what effect you are trying to achieve. In my lighting systems trippylighting.com I use an algorithm that draws a line through two randomly picked coordinates in RGB space using a 3D Bresenham algorithm. This creates a very dynamic fading experience that provides very nice pastel colors. No HSV needed. If you are intuitively trying to pick a color then HSV is the way to go.

Also, while CIE lab brightness correction is not most physically and physiologically correct algorithm it provides for a much more linear fading experience. However, in order to do that you need more than 8-Bit resolution to do so because otherwise you will experience perceivable jumps in brightness. Here also it depends on the application whether a particular algorithm is useful or not.

While my LED driver boards use a PCA9586 for 12 bit dimming, the Teensy3 PWM pins can be configured for anywhere between 8 and 16 bit.
 
Last edited:
That's one of the reasons I'm trying to keep the library well optimized for using either RGB or HSV (or both - I have some layered pattern stuff that uses HSV for some set of patterns and RGB for others). Let people decide what makes the most sense for whatever project they're doing at the moment.
 
Finally - one piece of advice for your code - neither arduinos nor avrs have floating point hardware - making floating point operations really slow. This rapidly becomes an issue when you're juggling data for hundreds or thousands of leds.

I am currently in process for converting all the floating point math and all of the int data types to uint8_t or unit16_t for improved performance (you and a couple of folks over on the reddit arduino sub all pointed this out). As someone who generally does PHP and Java programming during the day, having to think about variable size and computational speed isn't something that I normally worry about. I'm really glad that I sat down and did this, and also really glad that folks like you have taken time to go over my code and point this out. If nothing else, it's making me think like a better programmer. Thanks for the advice and I'm looking forward to trying out the new version of the FastSPI_LED2 library (hadn't even heard of the old one!).
 
Status
Not open for further replies.
Back
Top