Recover approximate HSV values from RGB.
These values are approximate, not exact. Why is this "only" an approximation? Because 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.
- Note
- This function is a long-term work in progress; expect results to change slightly over time as this function is refined and improved.
- Note
- 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
- 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.
- See also
- https://en.wikipedia.org/wiki/Bijection
- Parameters
-
rgb | an RGB value to convert |
- Returns
- the approximate HSV equivalent of the RGB value
Definition at line 550 of file hsv2rgb.cpp.
551{
552 uint8_t r = rgb.r;
553 uint8_t g = rgb.g;
554 uint8_t b = rgb.b;
555 uint8_t h, s, v;
556
557
558 uint8_t desat = 255;
559 if( r < desat) desat = r;
560 if( g < desat) desat = g;
561 if( b < desat) desat = b;
562
563
564 r -= desat;
565 g -= desat;
566 b -= desat;
567
568
569
570
571
572
573
574 s = 255 - desat;
575
576
577 if( s != 255 ) {
578
579 s = 255 -
sqrt16( (255-s) * 256);
580 }
581
582
583
584
585
586
587
588
589 if( (r + g + b) == 0) {
590
591 return CHSV( 0, 0, 255 - s);
592 }
593
594
595 if( s < 255) {
596 if( s == 0) s = 1;
597 uint32_t scaleup = 65535 / (s);
598 r = ((uint32_t)(r) * scaleup) / 256;
599 g = ((uint32_t)(g) * scaleup) / 256;
600 b = ((uint32_t)(b) * scaleup) / 256;
601 }
602
603
604
605
606 uint16_t total = r + g + b;
607
608
609
610
611 if( total < 255) {
612 if( total == 0) total = 1;
613 uint32_t scaleup = 65535 / (total);
614 r = ((uint32_t)(r) * scaleup) / 256;
615 g = ((uint32_t)(g) * scaleup) / 256;
616 b = ((uint32_t)(b) * scaleup) / 256;
617 }
618
619
620
621
622 if( total > 255 ) {
623 v = 255;
624 } else {
625 v =
qadd8(desat,total);
626
627 if( v != 255) v =
sqrt16( v * 256);
628
629
630
631 }
632
633
634
635
636#if 0
637
638
639 if( v != 255) {
640
641
642 uint16_t s16;
643 s16 = (s * 256);
644 s16 /= v;
645
646 if( s16 < 256) {
647 s = s16;
648 } else {
649 s = 255;
650 }
651 }
652#endif
653
654
655
656
657
658
659
660
661
662
663
664 uint8_t highest = r;
665 if( g > highest) highest = g;
666 if( b > highest) highest = b;
667
668 if( highest == r ) {
669
670
671 if( g == 0 ) {
672
675 } else if ( (r - g) > g) {
676
679 } else {
680
683 }
684
685 } else if ( highest == g) {
686
687
688 if( b == 0) {
689
690
691
695 uint8_t rgadj = radj + gadj;
696 uint8_t hueadv = rgadj / 2;
697 h += hueadv;
698
699
700 } else {
701
702 if( (g-b) > b) {
705 } else {
708 }
709 }
710
711 } else {
712
713
714 if( r == 0) {
715
718 } else if ( (b-r) > r) {
719
722 } else {
723
726 }
727 }
728
729 h += 1;
730 return CHSV( h, s, v);
731}
@ HUE_PURPLE
Purple (270°)
LIB8STATIC_ALWAYS_INLINE uint8_t qadd8(uint8_t i, uint8_t j)
Add one byte to another, saturating at 0xFF.
LIB8STATIC uint8_t sqrt16(uint16_t x)
Square root for 16-bit integers.
LIB8STATIC_ALWAYS_INLINE uint8_t qsub8(uint8_t i, uint8_t j)
Subtract one byte from another, saturating at 0x00.
LIB8STATIC_ALWAYS_INLINE uint8_t scale8(uint8_t i, fract8 scale)
Scale one byte by a second one, which is treated as the numerator of a fraction whose denominator is ...
#define FIXFRAC8(N, D)
Convert a fractional input into a constant.
Representation of an HSV pixel (hue, saturation, value (aka brightness)).
References FIXFRAC8, HUE_AQUA, HUE_BLUE, HUE_GREEN, HUE_ORANGE, HUE_PINK, HUE_PURPLE, HUE_RED, HUE_YELLOW, qadd8(), qsub8(), scale8(), and sqrt16().