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 504 of file hsv2rgb.cpp.
505{
506 uint8_t r = rgb.r;
507 uint8_t g = rgb.g;
508 uint8_t b = rgb.b;
509 uint8_t h, s, v;
510
511
512 uint8_t desat = 255;
513 if( r < desat) desat = r;
514 if( g < desat) desat = g;
515 if( b < desat) desat = b;
516
517
518 r -= desat;
519 g -= desat;
520 b -= desat;
521
522
523
524
525
526
527
528 s = 255 - desat;
529
530
531 if( s != 255 ) {
532
533 s = 255 -
sqrt16( (255-s) * 256);
534 }
535
536
537
538
539
540
541
542
543 if( (r + g + b) == 0) {
544
545 return CHSV( 0, 0, 255 - s);
546 }
547
548
549 if( s < 255) {
550 if( s == 0) s = 1;
551 uint32_t scaleup = 65535 / (s);
552 r = ((uint32_t)(r) * scaleup) / 256;
553 g = ((uint32_t)(g) * scaleup) / 256;
554 b = ((uint32_t)(b) * scaleup) / 256;
555 }
556
557
558
559
560 uint16_t total = r + g + b;
561
562
563
564
565 if( total < 255) {
566 if( total == 0) total = 1;
567 uint32_t scaleup = 65535 / (total);
568 r = ((uint32_t)(r) * scaleup) / 256;
569 g = ((uint32_t)(g) * scaleup) / 256;
570 b = ((uint32_t)(b) * scaleup) / 256;
571 }
572
573
574
575
576 if( total > 255 ) {
577 v = 255;
578 } else {
579 v =
qadd8(desat,total);
580
581 if( v != 255) v =
sqrt16( v * 256);
582
583
584
585 }
586
587
588
589
590#if 0
591
592
593 if( v != 255) {
594
595
596 uint16_t s16;
597 s16 = (s * 256);
598 s16 /= v;
599
600 if( s16 < 256) {
601 s = s16;
602 } else {
603 s = 255;
604 }
605 }
606#endif
607
608
609
610
611
612
613
614
615
616
617
618 uint8_t highest = r;
619 if( g > highest) highest = g;
620 if( b > highest) highest = b;
621
622 if( highest == r ) {
623
624
625 if( g == 0 ) {
626
629 } else if ( (r - g) > g) {
630
633 } else {
634
637 }
638
639 } else if ( highest == g) {
640
641
642 if( b == 0) {
643
644
645
649 uint8_t rgadj = radj + gadj;
650 uint8_t hueadv = rgadj / 2;
651 h += hueadv;
652
653
654 } else {
655
656 if( (g-b) > b) {
659 } else {
662 }
663 }
664
665 } else {
666
667
668 if( r == 0) {
669
672 } else if ( (b-r) > r) {
673
676 } else {
677
680 }
681 }
682
683 h += 1;
684 return CHSV( h, s, v);
685}
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.
@ HUE_PURPLE
Purple (270°)
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().