Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kriegsman <kriegsman@tr.org>2015-01-03 23:52:38 +0300
committerMark Kriegsman <kriegsman@tr.org>2015-01-03 23:52:38 +0300
commit4b0780ae32e8dbc2c9449a7b05ab320d709e9f94 (patch)
treeec207ae006001935cdbd541d6a41fe5423e81fed
parent23f568979b6812a6ea05028806271634f8103c9d (diff)
Adding rgb2hsv_approximate. It's (1) just an approximation, (2) not nearly as fast as the normal HSV-to-RGB conversion, and (3) it's most accurate when it's converting back to HSV from RGB colors that came from fully-saturated HSV colors to start with, e.g., CHSV( hue, 255,255)-> CRGB-> CHSV will give best results.
-rw-r--r--hsv2rgb.cpp132
-rw-r--r--hsv2rgb.h38
2 files changed, 170 insertions, 0 deletions
diff --git a/hsv2rgb.cpp b/hsv2rgb.cpp
index 8a6d0575..ab037e82 100644
--- a/hsv2rgb.cpp
+++ b/hsv2rgb.cpp
@@ -474,3 +474,135 @@ void hsv2rgb_spectrum( const struct CHSV* phsv, struct CRGB * prgb, int numLeds)
hsv2rgb_spectrum(phsv[i], prgb[i]);
}
}
+
+
+
+#define FIXFRAC8(N,D) (((N)*256)/(D))
+
+// This function is only an approximation, and it is not
+// nearly as fast as the normal HSV-to-RGB conversion.
+// See extended notes in the .h file.
+CHSV rgb2hsv_approximate( const CRGB& rgb)
+{
+ byte r = rgb.r;
+ byte g = rgb.g;
+ byte b = rgb.b;
+ byte h, s, v;
+
+ // find desaturation
+ byte desat = 255;
+ if( r < desat) desat = r;
+ if( g < desat) desat = g;
+ if( b < desat) desat = b;
+
+ // remove saturation from all channels
+ r -= desat;
+ g -= desat;
+ b -= desat;
+
+ // at least one channel is now zero
+
+ // if all three channels are zero, we had a
+ // shade of gray.
+
+ uint16_t total = r + g + b;
+
+ if( total == 0) {
+ // we pick hue zero for no special reason
+ h = 0;
+ return CHSV( h, s, v);
+ }
+
+ // since this wasn't a pure shade of gray,
+ // the interesting question is what hue is it
+
+ // scale all channels up to a total of 255
+ if( total != 255) {
+ uint32_t scaleup = 65535 / (total);
+ r = ((uint32_t)(r) * scaleup) / 256;
+ g = ((uint32_t)(g) * scaleup) / 256;
+ b = ((uint32_t)(b) * scaleup) / 256;
+ }
+
+ if( total > 255 ) {
+ v = 255;
+ } else {
+ v = qadd8(desat,total);
+ // undo 'dimming' of brightness
+ if( v != 255) v = sqrt16( v * 256);
+ // without lib8tion: float ... ew ... sqrt... double ew, or rather, ew ^ 0.5
+ // if( v != 255) v = (256.0 * sqrt( (float)(v) / 256.0));
+
+ }
+
+ // saturation is opposite of desaturation
+ s = 255 - desat;
+ if( v != 255) s = (s * 256) / v;
+
+ // undo 'dimming' of saturation
+ if( s != 255 ) s = 255 - sqrt16( (255-s) * 256);
+ // without lib8tion: float ... ew ... sqrt... double ew, or rather, ew ^ 0.5
+ // if( s != 255 ) s = (255 - (256.0 * sqrt( (float)(255-s) / 256.0)));
+
+ // start with which channel is highest
+ // (ties don't matter)
+ byte highest = r;
+ if( g > highest) highest = g;
+ if( b > highest) highest = b;
+
+ if( highest == r ) {
+ // Red is highest.
+ // Hue could be Purple/Pink-Red,Red-Orange,Orange-Yellow
+ if( g == 0 ) {
+ // if green is zero, we're in Purple/Pink-Red
+ h = (HUE_PURPLE + HUE_PINK) / 2;
+ h += scale8( r - 128, FIXFRAC8(48,128));
+ } else if ( (r - g) > g) {
+ // if R-G > G then we're in Red-Orange
+ h = HUE_RED;
+ h += scale8( g, FIXFRAC8(32,85));
+ } else {
+ // R-G < G, we're in Orange-Yellow
+ h = HUE_ORANGE;
+ h += scale8( qsub8((g - 85) + (171 - r), 4), FIXFRAC8(32,85)); //221
+ }
+
+ } else if ( highest == g) {
+ // Green is highest
+ // Hue could be Yellow-Green, Green-Aqua
+ if( b == 0) {
+ // if Blue is zero, we're in Yellow-Green
+ h = HUE_YELLOW;
+ h += scale8( qadd8( qadd8((g - 128), (128 - r)), 4), FIXFRAC8(32,255)); //
+ } else {
+ // if Blue is nonzero we're in Green-Aqua
+ if( (g-b) > b) {
+ h = HUE_GREEN;
+ h += scale8( b, FIXFRAC8(32,85));
+ } else {
+ h = HUE_AQUA;
+ h += scale8( b - 85, FIXFRAC8(8,42));
+ }
+ }
+
+ } else /* highest == b */ {
+ // Blue is highest
+ // Hue could be Aqua/Blue-Blue, Blue-Purple, Purple-Pink
+ if( r == 0) {
+ // if red is zero, we're in Aqua/Blue-Blue
+ h = HUE_AQUA + ((HUE_BLUE - HUE_AQUA) / 4);
+ h += scale8( b - 128, FIXFRAC8(24,128));
+ } else if ( (b-r) > r) {
+ // B-R > R, we're in Blue-Purple
+ h = HUE_BLUE;
+ h += scale8( r, FIXFRAC8(32,85));
+ } else {
+ // B-R < R, we're in Purple-Pink
+ h = HUE_PURPLE;
+ h += scale8( r - 85, FIXFRAC8(32,85));
+ }
+ }
+
+ h += 1;
+ return CHSV( h, s, v);
+}
diff --git a/hsv2rgb.h b/hsv2rgb.h
index 959c754a..f5c79b79 100644
--- a/hsv2rgb.h
+++ b/hsv2rgb.h
@@ -45,4 +45,42 @@ void hsv2rgb_raw(const struct CHSV& hsv, struct CRGB & rgb);
void hsv2rgb_raw(const struct CHSV* phsv, struct CRGB * prgb, int numLeds);
#define HUE_MAX 191
+
+// hsv2rgb_approximate - recover _approximate_ HSV values from RGB.
+//
+// NOTE 1: This function is a long-term work in process; expect
+// results to change slightly over time as this function is
+// refined and improved.
+//
+// NOTE 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.
+//
+// NOTE 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.
+//
+// NOTE 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.
+//
+CHSV rgb2hsv_approximate( const CRGB& rgb);
+
#endif