From 3d172bca0ee034edb261958f6d93407a621531a5 Mon Sep 17 00:00:00 2001 From: Jojo-1000 <33495614+Jojo-1000@users.noreply.github.com> Date: Tue, 16 Mar 2021 21:14:43 +0100 Subject: [PATCH] Add conversion from RGB to HueSaturation. --- include/hueplusplus/ColorUnits.h | 12 +++++++++--- src/ColorUnits.cpp | 42 ++++++++++++++++++++++++++++++++++++++++-- test/test_ColorUnits.cpp | 35 +++++++++++++++++++++++++++++++---- 3 files changed, 80 insertions(+), 9 deletions(-) diff --git a/include/hueplusplus/ColorUnits.h b/include/hueplusplus/ColorUnits.h index eb26991..077e08c 100644 --- a/include/hueplusplus/ColorUnits.h +++ b/include/hueplusplus/ColorUnits.h @@ -126,6 +126,12 @@ struct RGB //! //! Performs gamma correction so the light color matches the screen color better. XYBrightness toXY(const ColorGamut& gamut) const; + + //! \brief Convert to HueSaturation + //! + //! To get the correct color, set brightness to max(r,g,b). + HueSaturation toHueSaturation() const; + //! \brief Create from XYBrightness //! //! Performs gamma correction so the light color matches the screen color better. @@ -143,9 +149,9 @@ struct RGB }; //! \brief Const function that converts Kelvin to Mired. - //! - //! \param kelvin Unsigned integer value in Kelvin - //! \return Unsigned integer value in Mired +//! +//! \param kelvin Unsigned integer value in Kelvin +//! \return Unsigned integer value in Mired unsigned int kelvinToMired(unsigned int kelvin); //! \brief Const function that converts Mired to Kelvin. diff --git a/src/ColorUnits.cpp b/src/ColorUnits.cpp index be65b21..2d12719 100644 --- a/src/ColorUnits.cpp +++ b/src/ColorUnits.cpp @@ -142,17 +142,55 @@ XYBrightness RGB::toXY(const ColorGamut& gamut) const return xy; } +HueSaturation RGB::toHueSaturation() const +{ + const uint8_t cmax = std::max(r, std::max(g, b)); + const uint8_t cmin = std::min(r, std::min(g, b)); + const float diff = cmax - cmin; + + int h = -1; + int s = -1; + + if (cmax == cmin) + { + h = 0; + } + else if (cmax == r) + { + h = (int)(9307 * ((g - b) / diff) + 65535) % 65535; + } + else if (cmax == g) + { + h = (int)(12750 * ((b - r) / diff) + 25500) % 65535; + } + else if (cmax == b) + { + h = (int)(10710 * ((r - g) / diff) + 46920) % 65535; + } + + if (cmax == 0) + { + s = 0; + } + else + { + s = std::round((diff / cmax) * 254); + } + + return {h, s}; +} + RGB RGB::fromXY(const XYBrightness& xy) { if (xy.brightness < 1e-4) { - return RGB{ 0,0,0 }; + return RGB {0, 0, 0}; } const float z = 1.f - xy.xy.x - xy.xy.y; // use a fixed luminosity and rescale the resulting rgb values using brightness // randomly sampled conversions shown a minimum difference between original values // and values after rgb -> xy -> rgb conversion for Y = 0.3 - // (r-r')^2, (g-g')^2, (b-b')^2: + // (r-r')^2, (g-g')^2, (b-b')^2: // 4.48214, 4.72039, 3.12141 // Max. Difference: // 9, 9, 8 diff --git a/test/test_ColorUnits.cpp b/test/test_ColorUnits.cpp index 6e89329..bd81f1f 100644 --- a/test/test_ColorUnits.cpp +++ b/test/test_ColorUnits.cpp @@ -108,7 +108,7 @@ TEST(RGB, toXY) EXPECT_FLOAT_EQ(xy.brightness, 1.f); } { - const RGB black{ 0,0,0 }; + const RGB black {0, 0, 0}; XYBrightness xy = black.toXY(gamut::maxGamut); EXPECT_FLOAT_EQ(xy.xy.x, 0.32272673f); EXPECT_FLOAT_EQ(xy.xy.y, 0.32902291f); @@ -116,6 +116,34 @@ TEST(RGB, toXY) } } +TEST(RGB, toHueSaturation) +{ + { + const RGB red {255, 0, 0}; + HueSaturation hs = red.toHueSaturation(); + EXPECT_EQ(0, hs.hue); + EXPECT_EQ(254, hs.saturation); + } + { + const RGB darkGreen{64, 128, 128 }; + HueSaturation hs = darkGreen.toHueSaturation(); + EXPECT_EQ(38250, hs.hue); + EXPECT_EQ(127, hs.saturation); + } + { + const RGB white {255, 255, 255}; + HueSaturation hs = white.toHueSaturation(); + EXPECT_EQ(0, hs.hue); + EXPECT_EQ(0, hs.saturation); + } + { + const RGB black {0, 0, 0}; + HueSaturation hs = black.toHueSaturation(); + EXPECT_EQ(0, hs.hue); + EXPECT_EQ(0, hs.saturation); + } +} + TEST(RGB, fromXY) { { @@ -130,7 +158,7 @@ TEST(RGB, fromXY) EXPECT_FLOAT_EQ(xyRed.brightness, reversed.brightness); } { - const XYBrightness xyWhite{ {0.32272673f, 0.32902291f}, 1.f }; + const XYBrightness xyWhite {{0.32272673f, 0.32902291f}, 1.f}; const RGB white = RGB::fromXY(xyWhite); EXPECT_EQ(255, white.r); EXPECT_EQ(255, white.g); @@ -143,7 +171,7 @@ TEST(RGB, fromXY) { const XYBrightness xyRed {{0.70060623f, 0.299301f}, 1.f}; const RGB red = RGB::fromXY(xyRed, gamut::gamutB); - const RGB red2 = RGB::fromXY({ gamut::gamutB.corrected(xyRed.xy), xyRed.brightness }); + const RGB red2 = RGB::fromXY({gamut::gamutB.corrected(xyRed.xy), xyRed.brightness}); EXPECT_EQ(red2.r, red.r); EXPECT_EQ(red2.g, red.g); EXPECT_EQ(red2.b, red.b); @@ -186,7 +214,6 @@ TEST(RGB, fromXY) EXPECT_LE(maxDiffR, 81); EXPECT_LE(maxDiffG, 81); EXPECT_LE(maxDiffB, 64); - } TEST(ColorUnits, kelvinToMired) -- libgit2 0.21.4