diff --git a/colour_extractor.cpp b/colour_extractor.cpp index 3c5a69d..b97d7ff 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 v_levels) + size_t l_levels) :m_pixels(NULL), m_max_colour_count(0), m_h_levels(h_levels), - m_s_levels(s_levels), m_v_levels(v_levels) + m_s_levels(s_levels), m_l_levels(l_levels) { - 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)); + 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)); } // PROTECTED FUNCS -size_t ColourExtractor::quantize(struct ColourHSV hsv) const +size_t ColourExtractor::quantize(struct ColourHSL hsl) const { size_t result = 0; size_t h_quant = 0; size_t s_quant = 0; - size_t v_quant = 0; + size_t l_quant = 0; - v_quant = static_cast(round(hsv.v * (m_v_levels - 1))); - if (0 == v_quant) + l_quant = static_cast(round(hsl.l * (m_l_levels - 1))); + if (0 == l_quant) { goto end; } - s_quant = static_cast(round(hsv.s * (m_s_levels - 1))); + s_quant = static_cast(round(hsl.s * (m_s_levels - 1))); if (0 == s_quant) { goto end; } - h_quant = static_cast(round(hsv.h / 360.0 * (m_h_levels - 1))); + h_quant = static_cast(round(hsl.h / 360.0 * (m_h_levels - 1))); end: result += h_quant; @@ -42,21 +42,21 @@ size_t ColourExtractor::quantize(struct ColourHSV hsv) const result *= m_s_levels; result += s_quant; - result *= m_v_levels; - result += v_quant; + result *= m_l_levels; + result += l_quant; return result; } -struct ColourHSV ColourExtractor::dequantize(size_t colour) const +struct ColourHSL ColourExtractor::dequantize(size_t colour) const { - struct ColourHSV result; + struct ColourHSL result; size_t h_quant; size_t s_quant; - size_t v_quant; + size_t l_quant; - v_quant = colour % m_v_levels; - colour /= m_v_levels; + l_quant = colour % m_l_levels; + colour /= m_l_levels; s_quant = colour % m_s_levels; colour /= m_s_levels; @@ -65,31 +65,31 @@ struct ColourHSV 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.v = static_cast(v_quant) / (m_v_levels - 1); + result.l = static_cast(l_quant) / (m_l_levels - 1); return result; } // PUBLIC FUNCS void ColourExtractor::get_quantization_levels(size_t& h_levels, - size_t& s_levels, size_t& v_levels) const + size_t& s_levels, size_t& l_levels) const { h_levels = m_h_levels; s_levels = m_s_levels; - v_levels = m_v_levels; + l_levels = m_l_levels; } void ColourExtractor::set_quantization_levels(size_t h_levels, size_t s_levels, - size_t v_levels) + size_t l_levels) { delete[] m_pixels; m_h_levels = h_levels; m_s_levels = s_levels; - m_v_levels = v_levels; + m_l_levels = l_levels; - 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)); + 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)); } 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_v_levels]; - memset(m_pixels, 0, m_h_levels * m_s_levels * m_v_levels * sizeof(size_t)); + 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)); } 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_v_levels]; - memset(m_pixels, 0, m_h_levels * m_s_levels * m_v_levels * sizeof(size_t)); + 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)); } size_t ColourExtractor::get_v_quantization_levels() const { - return m_v_levels; + return m_l_levels; } -void ColourExtractor::set_v_quantization_levels(size_t v_levels) +void ColourExtractor::set_v_quantization_levels(size_t l_levels) { delete[] m_pixels; - m_v_levels = v_levels; + m_l_levels = l_levels; - 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)); + 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)); } -void ColourExtractor::add_pixel(struct ColourHSV hsv) +void ColourExtractor::add_pixel(struct ColourHSL hsl) { size_t colour_quant; - colour_quant = quantize(hsv); + colour_quant = quantize(hsl); m_pixels[colour_quant] += 1; if (m_max_colour_count < m_pixels[colour_quant]) @@ -152,22 +152,22 @@ void ColourExtractor::add_pixel(struct ColourHSV hsv) void ColourExtractor::clear_pixels() { - for (size_t i = 0; i < m_h_levels * m_s_levels * m_v_levels; ++i) + for (size_t i = 0; i < m_h_levels * m_s_levels * m_l_levels; ++i) { m_pixels[i] = 0; } m_max_colour_count = 0; } -struct ColourHSV ColourExtractor::extract_colour() const +struct ColourHSL ColourExtractor::extract_colour() const { - struct ColourHSV result = {0.0, 0.0, 0.0}; - struct ColourHSV temp_colour; + struct ColourHSL result = {0.0, 0.0, 0.0}; + struct ColourHSL 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_v_levels; ++i) + for (size_t i = 0; i < m_h_levels * m_s_levels * m_l_levels; ++i) { if (0 == m_pixels[i]) { diff --git a/colour_extractor.h b/colour_extractor.h index 5f5d715..e07303b 100644 --- a/colour_extractor.h +++ b/colour_extractor.h @@ -7,7 +7,7 @@ class ColourExtractor { -private: +protected: // Holds all quantized pixels size_t* m_pixels; @@ -17,30 +17,30 @@ private: // Quantization levels for the HSV colours size_t m_h_levels; size_t m_s_levels; - size_t m_v_levels; + size_t m_l_levels; // Quantizes the colour - size_t quantize(struct ColourHSV hsv) const; + size_t quantize(struct ColourHSL hsl) const; // Dequantizes the colour - struct ColourHSV dequantize(size_t colour) const; + struct ColourHSL dequantize(size_t colour) const; protected: // Evaluates the given colour based on its weight - virtual size_t evaluate_colour(struct ColourHSV hsv, double weight) + virtual size_t evaluate_colour(struct ColourHSL hsl, double weight) const = 0; public: // Params: HSV quantization levels ColourExtractor(size_t h_levels = 36, size_t s_levels = 10, - size_t v_levels = 10); + size_t l_levels = 10); void get_quantization_levels(size_t& h_levels, size_t& s_levels, - size_t& v_levels) const; + size_t& l_levels) const; // Note: clears all pixels void set_quantization_levels(size_t h_levels, size_t s_levels, - size_t v_levels); + size_t l_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 v_levels); + void set_v_quantization_levels(size_t l_levels); // Adds a pixel to be considered for extraction - void add_pixel(struct ColourHSV hsv); + void add_pixel(struct ColourHSL hsl); // Clears all pixels void clear_pixels(); // Extracts a single colour from all added pixels - struct ColourHSV extract_colour() const; + struct ColourHSL extract_colour() const; ~ColourExtractor(); }; diff --git a/complimentary_colour_extractor.cpp b/complimentary_colour_extractor.cpp index d4a0bb6..b0ad7f4 100644 --- a/complimentary_colour_extractor.cpp +++ b/complimentary_colour_extractor.cpp @@ -3,53 +3,63 @@ #include // CONSTRUCTORS -ComplimentaryColourExtractor::ComplimentaryColourExtractor(struct ColourHSV hsv, +ComplimentaryColourExtractor::ComplimentaryColourExtractor(struct ColourHSL hsl, size_t h_levels, size_t s_levels, size_t v_levels) -:ColourExtractor(h_levels, s_levels, v_levels), m_main_colour(hsv) +:ColourExtractor(h_levels, s_levels, v_levels), m_main_colour(hsl) { } // PROTECTED FUNCS -size_t ComplimentaryColourExtractor::evaluate_colour(struct ColourHSV hsv, +size_t ComplimentaryColourExtractor::evaluate_colour(struct ColourHSL hsl, double weight) const { size_t result = 0; double angle_delta; - double additional_colour_weight; + // double additional_colour_weight; - if ((0.0 == hsv.s) || (0.0 == m_main_colour.s)) + // 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) { - 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 */ + angle_delta = 360.0F - angle_delta; } // 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) * hsv.v * - 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)); return result; } // PUBLIC FUNCS -struct ColourHSV ComplimentaryColourExtractor::get_main_colour() const +struct ColourHSL ComplimentaryColourExtractor::get_main_colour() const { return m_main_colour; } -void ComplimentaryColourExtractor::set_main_colour(struct ColourHSV hsv) +void ComplimentaryColourExtractor::set_main_colour(struct ColourHSL hsl) { - m_main_colour = hsv; + m_main_colour = hsl; } diff --git a/complimentary_colour_extractor.h b/complimentary_colour_extractor.h index 9b4f86a..7ef22fd 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 ColourHSV m_main_colour; + struct ColourHSL m_main_colour; protected: // Implemented - Evaluates the given colour based on its weight - virtual size_t evaluate_colour(struct ColourHSV hsv, double weight) const; + virtual size_t evaluate_colour(struct ColourHSL hsl, double weight) const; public: - ComplimentaryColourExtractor(struct ColourHSV hsv, size_t h_levels = 36, + ComplimentaryColourExtractor(struct ColourHSL hsl, size_t h_levels = 36, size_t s_levels = 10, size_t v_levels = 10); - struct ColourHSV get_main_colour() const; - void set_main_colour(struct ColourHSV hsv); + struct ColourHSL get_main_colour() const; + void set_main_colour(struct ColourHSL hsl); }; #endif // COMPLIMENTARY_COLOUR_EXTRACTOR_H_ diff --git a/main.cpp b/main.cpp index 5788556..b0c5d07 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #define STB_IMAGE_IMPLEMENTATION @@ -11,6 +12,16 @@ 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; @@ -27,8 +38,8 @@ int main(int argc, char **argv) unsigned char *image = nullptr; ColourRGB pixel; ColourRGB pixel2; - ColourHSV pixel_hsv; - MainColourExtractor main_extractor(0.2, 36, 10, 10); + ColourHSL pixel_hsl; + MainColourExtractor main_extractor(36, 10, 10); ComplimentaryColourExtractor comp_extractor({0, 0, 0}, 36, 10, 10); if (argc < 2) @@ -75,19 +86,23 @@ int main(int argc, char **argv) // TODO: Handle alpha here } - // TODO: Add pixel to evaluator here - pixel_hsv = RGBtoHSV(pixel); - main_extractor.add_pixel(pixel_hsv); - comp_extractor.add_pixel(pixel_hsv); + pixel_hsl = RGBtoHSL(pixel); + main_extractor.add_pixel(pixel_hsl); + comp_extractor.add_pixel(pixel_hsl); } stbi_image_free(image); - pixel_hsv = main_extractor.extract_colour(); - comp_extractor.set_main_colour(pixel_hsv); - pixel = HSVtoRGB(pixel_hsv); - pixel2 = HSVtoRGB(comp_extractor.extract_colour()); + pixel_hsl = main_extractor.extract_colour(); + comp_extractor.set_main_colour(pixel_hsl); + pixel = HSLtoRGB(pixel_hsl); + pixel2 = HSLtoRGB(comp_extractor.extract_colour()); - // TODO: Print them to console + cout << "Main - "; + print_pixel(pixel); + cout << endl; + cout << "Comp - "; + print_pixel(pixel2); + cout << endl; x_size = 16; y_size = 16; @@ -106,7 +121,7 @@ int main(int argc, char **argv) image[i * channels + 2] = static_cast(round(pixel.b * 255)); } - stbi_write_png("main.png", x_size, y_size, channels, image, x_size * channels); + stbi_write_png("0 - main.png", x_size, y_size, channels, image, x_size * channels); for (int i = 0; i < x_size * y_size; ++i) { @@ -115,7 +130,7 @@ int main(int argc, char **argv) image[i * channels + 2] = static_cast(round(pixel2.b * 255)); } - stbi_write_png("comp.png", x_size, y_size, channels, image, x_size * channels); + stbi_write_png("1 - 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 80d7188..df7cb80 100644 --- a/main_colour_extractor.cpp +++ b/main_colour_extractor.cpp @@ -3,49 +3,21 @@ #include // CONSTRUCTORS -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) +MainColourExtractor::MainColourExtractor(size_t h_levels, size_t s_levels, + size_t l_levels) +: ColourExtractor(h_levels, s_levels, l_levels) { } -// PRIVATE FUNCS -double MainColourExtractor::calculate_lightness(struct ColourHSV hsv) const -{ - double result = 0.0; - struct ColourRGB rgb; - - 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) +size_t MainColourExtractor::evaluate_colour(struct ColourHSL hsl, 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))); - } + 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))); 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 0f1deec..2388686 100644 --- a/main_colour_extractor.h +++ b/main_colour_extractor.h @@ -5,24 +5,13 @@ 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 ColourHSV hsv, double weight) const; + virtual size_t evaluate_colour(struct ColourHSL hsv, double weight) const; public: - 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); + MainColourExtractor(size_t h_levels = 36, size_t s_levels = 10, + size_t l_levels = 10); }; #endif // MAIN_COLOUR_EXTRACTOR_H_