From 8dd297434b590eba058a5f2f01a44c17941c6bcd Mon Sep 17 00:00:00 2001 From: nedko Date: Wed, 7 Dec 2022 14:40:01 +0200 Subject: [PATCH] Revert "Changed colour extractor to use HSL" This reverts commit 6b60b152896e8af78f3e0f30b4b75ebdc31a1846. --- colour_extractor.cpp | 80 +++++++++++++++--------------- colour_extractor.h | 22 ++++---- complimentary_colour_extractor.cpp | 56 +++++++++------------ complimentary_colour_extractor.h | 10 ++-- main.cpp | 41 +++++---------- main_colour_extractor.cpp | 48 ++++++++++++++---- main_colour_extractor.h | 17 +++++-- 7 files changed, 144 insertions(+), 130 deletions(-) diff --git a/colour_extractor.cpp b/colour_extractor.cpp index b97d7ff..3c5a69d 100644 --- a/colour_extractor.cpp +++ b/colour_extractor.cpp @@ -5,36 +5,36 @@ // CONSTRUCTORS ColourExtractor::ColourExtractor(size_t h_levels, size_t s_levels, - size_t l_levels) + size_t v_levels) :m_pixels(NULL), m_max_colour_count(0), m_h_levels(h_levels), - m_s_levels(s_levels), m_l_levels(l_levels) + m_s_levels(s_levels), m_v_levels(v_levels) { - m_pixels = new size_t[m_h_levels * m_s_levels * m_l_levels]; - memset(m_pixels, 0, m_h_levels * m_s_levels * m_l_levels * sizeof(size_t)); + m_pixels = new size_t[m_h_levels * m_s_levels * m_v_levels]; + memset(m_pixels, 0, m_h_levels * m_s_levels * m_v_levels * sizeof(size_t)); } // PROTECTED FUNCS -size_t ColourExtractor::quantize(struct ColourHSL hsl) const +size_t ColourExtractor::quantize(struct ColourHSV hsv) const { size_t result = 0; size_t h_quant = 0; size_t s_quant = 0; - size_t l_quant = 0; + size_t v_quant = 0; - l_quant = static_cast(round(hsl.l * (m_l_levels - 1))); - if (0 == l_quant) + v_quant = static_cast(round(hsv.v * (m_v_levels - 1))); + if (0 == v_quant) { goto end; } - s_quant = static_cast(round(hsl.s * (m_s_levels - 1))); + s_quant = static_cast(round(hsv.s * (m_s_levels - 1))); if (0 == s_quant) { goto end; } - h_quant = static_cast(round(hsl.h / 360.0 * (m_h_levels - 1))); + h_quant = static_cast(round(hsv.h / 360.0 * (m_h_levels - 1))); end: result += h_quant; @@ -42,21 +42,21 @@ size_t ColourExtractor::quantize(struct ColourHSL hsl) const result *= m_s_levels; result += s_quant; - result *= m_l_levels; - result += l_quant; + result *= m_v_levels; + result += v_quant; return result; } -struct ColourHSL ColourExtractor::dequantize(size_t colour) const +struct ColourHSV ColourExtractor::dequantize(size_t colour) const { - struct ColourHSL result; + struct ColourHSV result; size_t h_quant; size_t s_quant; - size_t l_quant; + size_t v_quant; - l_quant = colour % m_l_levels; - colour /= m_l_levels; + v_quant = colour % m_v_levels; + colour /= m_v_levels; s_quant = colour % m_s_levels; colour /= m_s_levels; @@ -65,31 +65,31 @@ struct ColourHSL ColourExtractor::dequantize(size_t colour) const result.h = static_cast(h_quant) * 360.0 / (m_h_levels - 1); result.s = static_cast(s_quant) / (m_s_levels - 1); - result.l = static_cast(l_quant) / (m_l_levels - 1); + result.v = static_cast(v_quant) / (m_v_levels - 1); return result; } // PUBLIC FUNCS void ColourExtractor::get_quantization_levels(size_t& h_levels, - size_t& s_levels, size_t& l_levels) const + size_t& s_levels, size_t& v_levels) const { h_levels = m_h_levels; s_levels = m_s_levels; - l_levels = m_l_levels; + v_levels = m_v_levels; } void ColourExtractor::set_quantization_levels(size_t h_levels, size_t s_levels, - size_t l_levels) + size_t v_levels) { delete[] m_pixels; m_h_levels = h_levels; m_s_levels = s_levels; - m_l_levels = l_levels; + m_v_levels = v_levels; - m_pixels = new size_t[m_h_levels * m_s_levels * m_l_levels]; - memset(m_pixels, 0, m_h_levels * m_s_levels * m_l_levels * sizeof(size_t)); + m_pixels = new size_t[m_h_levels * m_s_levels * m_v_levels]; + memset(m_pixels, 0, m_h_levels * m_s_levels * m_v_levels * sizeof(size_t)); } size_t ColourExtractor::get_h_quantization_levels() const @@ -103,8 +103,8 @@ void ColourExtractor::set_h_quantization_levels(size_t h_levels) m_h_levels = h_levels; - m_pixels = new size_t[m_h_levels * m_s_levels * m_l_levels]; - memset(m_pixels, 0, m_h_levels * m_s_levels * m_l_levels * sizeof(size_t)); + m_pixels = new size_t[m_h_levels * m_s_levels * m_v_levels]; + memset(m_pixels, 0, m_h_levels * m_s_levels * m_v_levels * sizeof(size_t)); } size_t ColourExtractor::get_s_quantization_levels() const @@ -118,30 +118,30 @@ void ColourExtractor::set_s_quantization_levels(size_t s_levels) m_s_levels = s_levels; - m_pixels = new size_t[m_h_levels * m_s_levels * m_l_levels]; - memset(m_pixels, 0, m_h_levels * m_s_levels * m_l_levels * sizeof(size_t)); + m_pixels = new size_t[m_h_levels * m_s_levels * m_v_levels]; + memset(m_pixels, 0, m_h_levels * m_s_levels * m_v_levels * sizeof(size_t)); } size_t ColourExtractor::get_v_quantization_levels() const { - return m_l_levels; + return m_v_levels; } -void ColourExtractor::set_v_quantization_levels(size_t l_levels) +void ColourExtractor::set_v_quantization_levels(size_t v_levels) { delete[] m_pixels; - m_l_levels = l_levels; + m_v_levels = v_levels; - m_pixels = new size_t[m_h_levels * m_s_levels * m_l_levels]; - memset(m_pixels, 0, m_h_levels * m_s_levels * m_l_levels * sizeof(size_t)); + m_pixels = new size_t[m_h_levels * m_s_levels * m_v_levels]; + memset(m_pixels, 0, m_h_levels * m_s_levels * m_v_levels * sizeof(size_t)); } -void ColourExtractor::add_pixel(struct ColourHSL hsl) +void ColourExtractor::add_pixel(struct ColourHSV hsv) { size_t colour_quant; - colour_quant = quantize(hsl); + colour_quant = quantize(hsv); m_pixels[colour_quant] += 1; if (m_max_colour_count < m_pixels[colour_quant]) @@ -152,22 +152,22 @@ void ColourExtractor::add_pixel(struct ColourHSL hsl) void ColourExtractor::clear_pixels() { - for (size_t i = 0; i < m_h_levels * m_s_levels * m_l_levels; ++i) + for (size_t i = 0; i < m_h_levels * m_s_levels * m_v_levels; ++i) { m_pixels[i] = 0; } m_max_colour_count = 0; } -struct ColourHSL ColourExtractor::extract_colour() const +struct ColourHSV ColourExtractor::extract_colour() const { - struct ColourHSL result = {0.0, 0.0, 0.0}; - struct ColourHSL temp_colour; + struct ColourHSV result = {0.0, 0.0, 0.0}; + struct ColourHSV temp_colour; size_t max_colour_value = 0; size_t temp_colour_value; double temp_colour_weight; - for (size_t i = 0; i < m_h_levels * m_s_levels * m_l_levels; ++i) + for (size_t i = 0; i < m_h_levels * m_s_levels * m_v_levels; ++i) { if (0 == m_pixels[i]) { diff --git a/colour_extractor.h b/colour_extractor.h index e07303b..5f5d715 100644 --- a/colour_extractor.h +++ b/colour_extractor.h @@ -7,7 +7,7 @@ class ColourExtractor { -protected: +private: // Holds all quantized pixels size_t* m_pixels; @@ -17,30 +17,30 @@ protected: // Quantization levels for the HSV colours size_t m_h_levels; size_t m_s_levels; - size_t m_l_levels; + size_t m_v_levels; // Quantizes the colour - size_t quantize(struct ColourHSL hsl) const; + size_t quantize(struct ColourHSV hsv) const; // Dequantizes the colour - struct ColourHSL dequantize(size_t colour) const; + struct ColourHSV dequantize(size_t colour) const; protected: // Evaluates the given colour based on its weight - virtual size_t evaluate_colour(struct ColourHSL hsl, double weight) + virtual size_t evaluate_colour(struct ColourHSV hsv, double weight) const = 0; public: // Params: HSV quantization levels ColourExtractor(size_t h_levels = 36, size_t s_levels = 10, - size_t l_levels = 10); + size_t v_levels = 10); void get_quantization_levels(size_t& h_levels, size_t& s_levels, - size_t& l_levels) const; + size_t& v_levels) const; // Note: clears all pixels void set_quantization_levels(size_t h_levels, size_t s_levels, - size_t l_levels); + size_t v_levels); size_t get_h_quantization_levels() const; @@ -55,16 +55,16 @@ public: size_t get_v_quantization_levels() const; // Note: clears all pixels - void set_v_quantization_levels(size_t l_levels); + void set_v_quantization_levels(size_t v_levels); // Adds a pixel to be considered for extraction - void add_pixel(struct ColourHSL hsl); + void add_pixel(struct ColourHSV hsv); // Clears all pixels void clear_pixels(); // Extracts a single colour from all added pixels - struct ColourHSL extract_colour() const; + struct ColourHSV extract_colour() const; ~ColourExtractor(); }; diff --git a/complimentary_colour_extractor.cpp b/complimentary_colour_extractor.cpp index b0ad7f4..d4a0bb6 100644 --- a/complimentary_colour_extractor.cpp +++ b/complimentary_colour_extractor.cpp @@ -3,63 +3,53 @@ #include // CONSTRUCTORS -ComplimentaryColourExtractor::ComplimentaryColourExtractor(struct ColourHSL hsl, +ComplimentaryColourExtractor::ComplimentaryColourExtractor(struct ColourHSV hsv, size_t h_levels, size_t s_levels, size_t v_levels) -:ColourExtractor(h_levels, s_levels, v_levels), m_main_colour(hsl) +:ColourExtractor(h_levels, s_levels, v_levels), m_main_colour(hsv) { } // PROTECTED FUNCS -size_t ComplimentaryColourExtractor::evaluate_colour(struct ColourHSL hsl, +size_t ComplimentaryColourExtractor::evaluate_colour(struct ColourHSV hsv, double weight) const { size_t result = 0; double angle_delta; - // double additional_colour_weight; + double additional_colour_weight; - // if ((0.0 == hsl.s) || (0.0 == m_main_colour.s)) - // { - // angle_delta = 180.0; - // additional_colour_weight = 0.5; - // } - // else - // { - // additional_colour_weight = 1.0; - // /* SECTION BEGIN */ - // angle_delta = fabs(hsl.h - m_main_colour.h); - // if (angle_delta > 180.0F) - // { - // angle_delta = 360.0F - angle_delta; - // } - // /* SECTION END */ - // } - - angle_delta = fabs(hsl.h - m_main_colour.h); - if (angle_delta > 180.0F) + if ((0.0 == hsv.s) || (0.0 == m_main_colour.s)) { - angle_delta = 360.0F - angle_delta; + angle_delta = 180.0; + additional_colour_weight = 0.5; + } + else + { + additional_colour_weight = 1.0; + /* SECTION BEGIN */ + angle_delta = fabs(hsv.h - m_main_colour.h); + if (angle_delta > 180.0F) + { + angle_delta = 360.0F - angle_delta; + } + /* SECTION END */ } // result = static_cast(round(1000.0 * pow(weight, 0.3) * hsv.v * // fmin(1.0, hsv.v + hsv.s) * additional_colour_weight * angle_delta)); - // result = static_cast(round(1000.0 * pow(weight, 0.3) * hsl.l * - // additional_colour_weight * angle_delta)); - - result = static_cast(round(1000.0 * pow(weight, 0.3) * - ((1.0 - fabs(2 * hsl.l - 1.0)) * (1 - 1.0 / m_l_levels) + 1.0 / m_l_levels) * - angle_delta)); + result = static_cast(round(1000.0 * pow(weight, 0.3) * hsv.v * + additional_colour_weight * angle_delta)); return result; } // PUBLIC FUNCS -struct ColourHSL ComplimentaryColourExtractor::get_main_colour() const +struct ColourHSV ComplimentaryColourExtractor::get_main_colour() const { return m_main_colour; } -void ComplimentaryColourExtractor::set_main_colour(struct ColourHSL hsl) +void ComplimentaryColourExtractor::set_main_colour(struct ColourHSV hsv) { - m_main_colour = hsl; + m_main_colour = hsv; } diff --git a/complimentary_colour_extractor.h b/complimentary_colour_extractor.h index 7ef22fd..9b4f86a 100644 --- a/complimentary_colour_extractor.h +++ b/complimentary_colour_extractor.h @@ -7,18 +7,18 @@ class ComplimentaryColourExtractor : public ColourExtractor { private: // Main colour against which we are finding the complimentary - struct ColourHSL m_main_colour; + struct ColourHSV m_main_colour; protected: // Implemented - Evaluates the given colour based on its weight - virtual size_t evaluate_colour(struct ColourHSL hsl, double weight) const; + virtual size_t evaluate_colour(struct ColourHSV hsv, double weight) const; public: - ComplimentaryColourExtractor(struct ColourHSL hsl, size_t h_levels = 36, + ComplimentaryColourExtractor(struct ColourHSV hsv, size_t h_levels = 36, size_t s_levels = 10, size_t v_levels = 10); - struct ColourHSL get_main_colour() const; - void set_main_colour(struct ColourHSL hsl); + struct ColourHSV get_main_colour() const; + void set_main_colour(struct ColourHSV hsv); }; #endif // COMPLIMENTARY_COLOUR_EXTRACTOR_H_ diff --git a/main.cpp b/main.cpp index b0c5d07..5788556 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,4 @@ #include -#include #include #define STB_IMAGE_IMPLEMENTATION @@ -12,16 +11,6 @@ using namespace std; -void print_pixel(ColourRGB rgb) -{ - uint8_t r = static_cast(round(rgb.r * 255)); - uint8_t g = static_cast(round(rgb.g * 255)); - uint8_t b = static_cast(round(rgb.b * 255)); - - cout << "#" << std::hex << (int)r << (int)g << (int)b; - cout << std::dec << " - " << (int)r << " " << (int)g << " " << (int)b; -} - void usage(char *name) { cout << "Usage: " << name << " [input image]" << endl; @@ -38,8 +27,8 @@ int main(int argc, char **argv) unsigned char *image = nullptr; ColourRGB pixel; ColourRGB pixel2; - ColourHSL pixel_hsl; - MainColourExtractor main_extractor(36, 10, 10); + ColourHSV pixel_hsv; + MainColourExtractor main_extractor(0.2, 36, 10, 10); ComplimentaryColourExtractor comp_extractor({0, 0, 0}, 36, 10, 10); if (argc < 2) @@ -86,23 +75,19 @@ int main(int argc, char **argv) // TODO: Handle alpha here } - pixel_hsl = RGBtoHSL(pixel); - main_extractor.add_pixel(pixel_hsl); - comp_extractor.add_pixel(pixel_hsl); + // TODO: Add pixel to evaluator here + pixel_hsv = RGBtoHSV(pixel); + main_extractor.add_pixel(pixel_hsv); + comp_extractor.add_pixel(pixel_hsv); } stbi_image_free(image); - pixel_hsl = main_extractor.extract_colour(); - comp_extractor.set_main_colour(pixel_hsl); - pixel = HSLtoRGB(pixel_hsl); - pixel2 = HSLtoRGB(comp_extractor.extract_colour()); + pixel_hsv = main_extractor.extract_colour(); + comp_extractor.set_main_colour(pixel_hsv); + pixel = HSVtoRGB(pixel_hsv); + pixel2 = HSVtoRGB(comp_extractor.extract_colour()); - cout << "Main - "; - print_pixel(pixel); - cout << endl; - cout << "Comp - "; - print_pixel(pixel2); - cout << endl; + // TODO: Print them to console x_size = 16; y_size = 16; @@ -121,7 +106,7 @@ int main(int argc, char **argv) image[i * channels + 2] = static_cast(round(pixel.b * 255)); } - stbi_write_png("0 - main.png", x_size, y_size, channels, image, x_size * channels); + stbi_write_png("main.png", x_size, y_size, channels, image, x_size * channels); for (int i = 0; i < x_size * y_size; ++i) { @@ -130,7 +115,7 @@ int main(int argc, char **argv) image[i * channels + 2] = static_cast(round(pixel2.b * 255)); } - stbi_write_png("1 - comp.png", x_size, y_size, channels, image, x_size * channels); + stbi_write_png("comp.png", x_size, y_size, channels, image, x_size * channels); delete[] image; diff --git a/main_colour_extractor.cpp b/main_colour_extractor.cpp index df7cb80..80d7188 100644 --- a/main_colour_extractor.cpp +++ b/main_colour_extractor.cpp @@ -3,21 +3,49 @@ #include // CONSTRUCTORS -MainColourExtractor::MainColourExtractor(size_t h_levels, size_t s_levels, - size_t l_levels) -: ColourExtractor(h_levels, s_levels, l_levels) +MainColourExtractor::MainColourExtractor(double lightness_threshold, + size_t h_levels, size_t s_levels, size_t v_levels) +:ColourExtractor(h_levels, s_levels, v_levels), + m_lightness_threshold(lightness_threshold) { } -// PROTECTED FUNCS -size_t MainColourExtractor::evaluate_colour(struct ColourHSL hsl, double weight) - const +// PRIVATE FUNCS +double MainColourExtractor::calculate_lightness(struct ColourHSV hsv) const { - size_t result = 0; + double result = 0.0; + struct ColourRGB rgb; - result = static_cast(round(1000.0 * pow(weight, 0.3) * - (hsl.s + 1.0 / m_h_levels) * - ((1.0 - fabs(2 * hsl.l - 1.0)) * (1 - 1.0 / m_l_levels) + 1.0 / m_l_levels))); + rgb = HSVtoRGB(hsv); + result = 0.299F * rgb.r + 0.587F * rgb.g + 0.114F * rgb.b; return result; } + +// PROTECTED FUNCS +size_t MainColourExtractor::evaluate_colour(struct ColourHSV hsv, double weight) + const +{ + size_t result = 0; + double lightness; + + lightness = calculate_lightness(hsv); + if (lightness >= m_lightness_threshold) + { + result = static_cast(round(1000.0 * (pow(weight, 0.3) + + 0.009999999776482582) * hsv.v * (hsv.s + 0.1))); + } + + return result; +} + +// PUBLIC FUNCS +double MainColourExtractor::get_lightness_threshold() const +{ + return m_lightness_threshold; +} + +void MainColourExtractor::set_lightness_threshold(double value) +{ + m_lightness_threshold = value; +} diff --git a/main_colour_extractor.h b/main_colour_extractor.h index 2388686..0f1deec 100644 --- a/main_colour_extractor.h +++ b/main_colour_extractor.h @@ -5,13 +5,24 @@ class MainColourExtractor : public ColourExtractor { +private: + // The minimum lightness a colour needs to have to be considered for + // evaluation + double m_lightness_threshold; + + // Calculates the lightness of a colour + double calculate_lightness(struct ColourHSV hsv) const; + protected: // Implemented - Evaluates the given colour based on its weight - virtual size_t evaluate_colour(struct ColourHSL hsv, double weight) const; + virtual size_t evaluate_colour(struct ColourHSV hsv, double weight) const; public: - MainColourExtractor(size_t h_levels = 36, size_t s_levels = 10, - size_t l_levels = 10); + MainColourExtractor(double lightness_threshold = 0.2, size_t h_levels = 36, + size_t s_levels = 10, size_t v_levels = 10); + + double get_lightness_threshold() const; + void set_lightness_threshold(double value); }; #endif // MAIN_COLOUR_EXTRACTOR_H_