Commit 3d172bca0ee034edb261958f6d93407a621531a5
Committed by
Moritz Wirger
1 parent
ce0d8213
Add conversion from RGB to HueSaturation.
Co-authored-by: Adam Honse <calcprogrammer1@gmail.com>
Showing
3 changed files
with
80 additions
and
9 deletions
include/hueplusplus/ColorUnits.h
| ... | ... | @@ -126,6 +126,12 @@ struct RGB |
| 126 | 126 | //! |
| 127 | 127 | //! Performs gamma correction so the light color matches the screen color better. |
| 128 | 128 | XYBrightness toXY(const ColorGamut& gamut) const; |
| 129 | + | |
| 130 | + //! \brief Convert to HueSaturation | |
| 131 | + //! | |
| 132 | + //! To get the correct color, set brightness to max(r,g,b). | |
| 133 | + HueSaturation toHueSaturation() const; | |
| 134 | + | |
| 129 | 135 | //! \brief Create from XYBrightness |
| 130 | 136 | //! |
| 131 | 137 | //! Performs gamma correction so the light color matches the screen color better. |
| ... | ... | @@ -143,9 +149,9 @@ struct RGB |
| 143 | 149 | }; |
| 144 | 150 | |
| 145 | 151 | //! \brief Const function that converts Kelvin to Mired. |
| 146 | - //! | |
| 147 | - //! \param kelvin Unsigned integer value in Kelvin | |
| 148 | - //! \return Unsigned integer value in Mired | |
| 152 | +//! | |
| 153 | +//! \param kelvin Unsigned integer value in Kelvin | |
| 154 | +//! \return Unsigned integer value in Mired | |
| 149 | 155 | unsigned int kelvinToMired(unsigned int kelvin); |
| 150 | 156 | |
| 151 | 157 | //! \brief Const function that converts Mired to Kelvin. | ... | ... |
src/ColorUnits.cpp
| ... | ... | @@ -142,17 +142,55 @@ XYBrightness RGB::toXY(const ColorGamut& gamut) const |
| 142 | 142 | return xy; |
| 143 | 143 | } |
| 144 | 144 | |
| 145 | +HueSaturation RGB::toHueSaturation() const | |
| 146 | +{ | |
| 147 | + const uint8_t cmax = std::max(r, std::max(g, b)); | |
| 148 | + const uint8_t cmin = std::min(r, std::min(g, b)); | |
| 149 | + const float diff = cmax - cmin; | |
| 150 | + | |
| 151 | + int h = -1; | |
| 152 | + int s = -1; | |
| 153 | + | |
| 154 | + if (cmax == cmin) | |
| 155 | + { | |
| 156 | + h = 0; | |
| 157 | + } | |
| 158 | + else if (cmax == r) | |
| 159 | + { | |
| 160 | + h = (int)(9307 * ((g - b) / diff) + 65535) % 65535; | |
| 161 | + } | |
| 162 | + else if (cmax == g) | |
| 163 | + { | |
| 164 | + h = (int)(12750 * ((b - r) / diff) + 25500) % 65535; | |
| 165 | + } | |
| 166 | + else if (cmax == b) | |
| 167 | + { | |
| 168 | + h = (int)(10710 * ((r - g) / diff) + 46920) % 65535; | |
| 169 | + } | |
| 170 | + | |
| 171 | + if (cmax == 0) | |
| 172 | + { | |
| 173 | + s = 0; | |
| 174 | + } | |
| 175 | + else | |
| 176 | + { | |
| 177 | + s = std::round((diff / cmax) * 254); | |
| 178 | + } | |
| 179 | + | |
| 180 | + return {h, s}; | |
| 181 | +} | |
| 182 | + | |
| 145 | 183 | RGB RGB::fromXY(const XYBrightness& xy) |
| 146 | 184 | { |
| 147 | 185 | if (xy.brightness < 1e-4) |
| 148 | 186 | { |
| 149 | - return RGB{ 0,0,0 }; | |
| 187 | + return RGB {0, 0, 0}; | |
| 150 | 188 | } |
| 151 | 189 | const float z = 1.f - xy.xy.x - xy.xy.y; |
| 152 | 190 | // use a fixed luminosity and rescale the resulting rgb values using brightness |
| 153 | 191 | // randomly sampled conversions shown a minimum difference between original values |
| 154 | 192 | // and values after rgb -> xy -> rgb conversion for Y = 0.3 |
| 155 | - // (r-r')^2, (g-g')^2, (b-b')^2: | |
| 193 | + // (r-r')^2, (g-g')^2, (b-b')^2: | |
| 156 | 194 | // 4.48214, 4.72039, 3.12141 |
| 157 | 195 | // Max. Difference: |
| 158 | 196 | // 9, 9, 8 | ... | ... |
test/test_ColorUnits.cpp
| ... | ... | @@ -108,7 +108,7 @@ TEST(RGB, toXY) |
| 108 | 108 | EXPECT_FLOAT_EQ(xy.brightness, 1.f); |
| 109 | 109 | } |
| 110 | 110 | { |
| 111 | - const RGB black{ 0,0,0 }; | |
| 111 | + const RGB black {0, 0, 0}; | |
| 112 | 112 | XYBrightness xy = black.toXY(gamut::maxGamut); |
| 113 | 113 | EXPECT_FLOAT_EQ(xy.xy.x, 0.32272673f); |
| 114 | 114 | EXPECT_FLOAT_EQ(xy.xy.y, 0.32902291f); |
| ... | ... | @@ -116,6 +116,34 @@ TEST(RGB, toXY) |
| 116 | 116 | } |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | +TEST(RGB, toHueSaturation) | |
| 120 | +{ | |
| 121 | + { | |
| 122 | + const RGB red {255, 0, 0}; | |
| 123 | + HueSaturation hs = red.toHueSaturation(); | |
| 124 | + EXPECT_EQ(0, hs.hue); | |
| 125 | + EXPECT_EQ(254, hs.saturation); | |
| 126 | + } | |
| 127 | + { | |
| 128 | + const RGB darkGreen{64, 128, 128 }; | |
| 129 | + HueSaturation hs = darkGreen.toHueSaturation(); | |
| 130 | + EXPECT_EQ(38250, hs.hue); | |
| 131 | + EXPECT_EQ(127, hs.saturation); | |
| 132 | + } | |
| 133 | + { | |
| 134 | + const RGB white {255, 255, 255}; | |
| 135 | + HueSaturation hs = white.toHueSaturation(); | |
| 136 | + EXPECT_EQ(0, hs.hue); | |
| 137 | + EXPECT_EQ(0, hs.saturation); | |
| 138 | + } | |
| 139 | + { | |
| 140 | + const RGB black {0, 0, 0}; | |
| 141 | + HueSaturation hs = black.toHueSaturation(); | |
| 142 | + EXPECT_EQ(0, hs.hue); | |
| 143 | + EXPECT_EQ(0, hs.saturation); | |
| 144 | + } | |
| 145 | +} | |
| 146 | + | |
| 119 | 147 | TEST(RGB, fromXY) |
| 120 | 148 | { |
| 121 | 149 | { |
| ... | ... | @@ -130,7 +158,7 @@ TEST(RGB, fromXY) |
| 130 | 158 | EXPECT_FLOAT_EQ(xyRed.brightness, reversed.brightness); |
| 131 | 159 | } |
| 132 | 160 | { |
| 133 | - const XYBrightness xyWhite{ {0.32272673f, 0.32902291f}, 1.f }; | |
| 161 | + const XYBrightness xyWhite {{0.32272673f, 0.32902291f}, 1.f}; | |
| 134 | 162 | const RGB white = RGB::fromXY(xyWhite); |
| 135 | 163 | EXPECT_EQ(255, white.r); |
| 136 | 164 | EXPECT_EQ(255, white.g); |
| ... | ... | @@ -143,7 +171,7 @@ TEST(RGB, fromXY) |
| 143 | 171 | { |
| 144 | 172 | const XYBrightness xyRed {{0.70060623f, 0.299301f}, 1.f}; |
| 145 | 173 | const RGB red = RGB::fromXY(xyRed, gamut::gamutB); |
| 146 | - const RGB red2 = RGB::fromXY({ gamut::gamutB.corrected(xyRed.xy), xyRed.brightness }); | |
| 174 | + const RGB red2 = RGB::fromXY({gamut::gamutB.corrected(xyRed.xy), xyRed.brightness}); | |
| 147 | 175 | EXPECT_EQ(red2.r, red.r); |
| 148 | 176 | EXPECT_EQ(red2.g, red.g); |
| 149 | 177 | EXPECT_EQ(red2.b, red.b); |
| ... | ... | @@ -186,7 +214,6 @@ TEST(RGB, fromXY) |
| 186 | 214 | EXPECT_LE(maxDiffR, 81); |
| 187 | 215 | EXPECT_LE(maxDiffG, 81); |
| 188 | 216 | EXPECT_LE(maxDiffB, 64); |
| 189 | - | |
| 190 | 217 | } |
| 191 | 218 | |
| 192 | 219 | TEST(ColorUnits, kelvinToMired) | ... | ... |