rgb2hsv_approximate - recover approximate HSV from RGB Just committed to the github repo on

rgb2hsv_approximate - recover approximate HSV from RGB

Just committed to the github repo on the FastLED3.1 branch: code that lets you recover an approximate set of HSV values from an RGB color. Because of FastLED’s HSV ‘rainbow’ (instead of a plain ‘spectrum’), conversion from RGB back to HSV is trickier than if we used a plain spectrum. Accordingly, there are a few, uh, provisos. Ah, a couple of quid pro quo.

  1. This function is a long-term work in process; expect results to change slightly over time as this function is refined and improved.

  2. This function is most accurate when the input is an RGB color that came from a fully-saturated HSV color to start with. E.g. CHSV( hue, 255, 255) -> CRGB -> CHSV will give best results.

  3. This function is not nearly as fast as HSV-to-RGB. It is provided for those situations when the need for this function cannot be avoided, or when extremely high performance is not needed.

  4. Why is this ‘only’ an “approximation”? Not all RGB colors have HSV equivalents! For example, there is no HSV value that will ever convert to RGB(255,255,0) using the code provided in this library. So if you try to convert RGB(255,255,0) ‘back’ to HSV, you’ll necessarily get only an approximation. Emphasis has been placed on getting the ‘hue’ as close as usefully possible, but even that’s a bit of a challenge. The 8-bit HSV and 8-bit RGB color spaces are not a “bijection”.

Nevertheless, this function does a pretty good job, particularly at recovering the ‘hue’ from fully saturated RGB colors that originally came from HSV rainbow colors. So if you start with CHSV(hue_in,255,255), and convert that to RGB, and then convert it back to HSV using this function, the resulting output hue will either exactly the same, or very close (+/-1). The more desaturated the original RGB color is, the rougher the approximation, and the less accurate the results.

Finally, work on this function is not as high a priority as some other work we’re doing on the library, so while we may change and improve it, those changes and improvements may not show up anytime soon. Just setting expectations here.

We are not at this time going to implement automatic conversion from CHSV to CRGB. If you need this functionality, call it explicitly.

SO, with that all said, it does basically work. As always, it’s probably better to avoid needing this function, but if you’re stuck, and you do need it, here it is.

Usage is like this:

CRGB rgb;
CHSV hsv;
hsv = rgb2hsv_approximate( rgb );

Enjoy… if needed.

Converting between colors spaces when you have 8 bit channels is tricky business.

Could there be future in moving to 16 bit? It would demand more resources but be a lot more accurate when doing anything lossy. Perhaps it would only be worth on more powerful non AVR chips? Just brainstorming, here.

Nice work!

@Alex_Wayne : There’s definitely some loss of precision along the way. The case I’ve tried hard to optimize for is this one:
CHSV(hue,255,255) -> CRGB -> CHSV
That case works pretty well, and you get back the hue you started with +/-1.

Eventually, we’ll be adding “16-bit” color as well: 16 bits for each RGB channel, and 16-bit representations of HSV as well. Forward conversion (HSV->RGB) will still be lightning fast; backward conversion (RGB->HSV) will still be a slower approximation.

But putting aside all the disclaimers I’m slapping on this thing today, it does actually work in what I take to be the most valuable case, when the color in question started with something like CHSV(hue,255,255).

And in all cases, even if the Saturation or Value is off a bit, I try to get the Hue as close as possible.

I imagine being within +/-1 will be plenty close enough 99 +/-1% of the time. Thanks for this option Mark!

I am trying to do this but need a little context. Can someone use this in a sentence? How do I integrate it into my code?

The commented out CRGB lines are working but not giving me the gradient palette results I want. I’m trying to convert to HSV so I can mess with the colors comfortably but I’m definitely missing something… how do I connect this up?

void SetupGradientPalette()
{

CRGB rgb;
CHSV hsv;
hsv = rgb2hsv_approximate( rgb );

CRGB light = CHSV( HUE + 25, SATURATION - 20, BRIGHTNESS);
CRGB dark = CHSV( HUE, SATURATION - 15, BRIGHTNESS);
CRGB medium = CHSV ( HUE - 25, SATURATION, BRIGHTNESS);

// CRGB light = CRGB (gammatable[(int)r], gammatable[(int)g], gammatable[(int)b]);
// CRGB dark = CRGB ((gammatable[(int)r]+5), (gammatable[(int)g]+1), (gammatable[(int)b]+1));
// CRGB medium = CRGB ((gammatable[(int)r]-5), (gammatable[(int)g]-1), (gammatable[(int)b]-1));