Added old extractors
This commit is contained in:
parent
a4886d07c0
commit
99aa3ab2b8
195
colour_extractor.cpp
Normal file
195
colour_extractor.cpp
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
#include "colour_extractor.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// CONSTRUCTORS
|
||||||
|
ColourExtractor::ColourExtractor(size_t h_levels, size_t s_levels,
|
||||||
|
size_t v_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_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 ColourHSV hsv) const
|
||||||
|
{
|
||||||
|
size_t result = 0;
|
||||||
|
|
||||||
|
size_t h_quant = 0;
|
||||||
|
size_t s_quant = 0;
|
||||||
|
size_t v_quant = 0;
|
||||||
|
|
||||||
|
v_quant = static_cast<size_t>(round(hsv.v * (m_v_levels - 1)));
|
||||||
|
if (0 == v_quant)
|
||||||
|
{
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_quant = static_cast<size_t>(round(hsv.s * (m_s_levels - 1)));
|
||||||
|
if (0 == s_quant)
|
||||||
|
{
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
h_quant = static_cast<size_t>(round(hsv.h / 360.0 * (m_h_levels - 1)));
|
||||||
|
|
||||||
|
end:
|
||||||
|
result += h_quant;
|
||||||
|
|
||||||
|
result *= m_s_levels;
|
||||||
|
result += s_quant;
|
||||||
|
|
||||||
|
result *= m_v_levels;
|
||||||
|
result += v_quant;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColourHSV ColourExtractor::dequantize(size_t colour) const
|
||||||
|
{
|
||||||
|
struct ColourHSV result;
|
||||||
|
size_t h_quant;
|
||||||
|
size_t s_quant;
|
||||||
|
size_t v_quant;
|
||||||
|
|
||||||
|
v_quant = colour % m_v_levels;
|
||||||
|
colour /= m_v_levels;
|
||||||
|
|
||||||
|
s_quant = colour % m_s_levels;
|
||||||
|
colour /= m_s_levels;
|
||||||
|
|
||||||
|
h_quant = colour % m_h_levels;
|
||||||
|
|
||||||
|
result.h = static_cast<double>(h_quant) * 360.0 / (m_h_levels - 1);
|
||||||
|
result.s = static_cast<double>(s_quant) / (m_s_levels - 1);
|
||||||
|
result.v = static_cast<double>(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& v_levels) const
|
||||||
|
{
|
||||||
|
h_levels = m_h_levels;
|
||||||
|
s_levels = m_s_levels;
|
||||||
|
v_levels = m_v_levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColourExtractor::set_quantization_levels(size_t h_levels, size_t s_levels,
|
||||||
|
size_t v_levels)
|
||||||
|
{
|
||||||
|
delete[] m_pixels;
|
||||||
|
|
||||||
|
m_h_levels = h_levels;
|
||||||
|
m_s_levels = s_levels;
|
||||||
|
m_v_levels = v_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));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ColourExtractor::get_h_quantization_levels() const
|
||||||
|
{
|
||||||
|
return m_h_levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColourExtractor::set_h_quantization_levels(size_t h_levels)
|
||||||
|
{
|
||||||
|
delete[] m_pixels;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ColourExtractor::get_s_quantization_levels() const
|
||||||
|
{
|
||||||
|
return m_s_levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColourExtractor::set_s_quantization_levels(size_t s_levels)
|
||||||
|
{
|
||||||
|
delete[] m_pixels;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ColourExtractor::get_v_quantization_levels() const
|
||||||
|
{
|
||||||
|
return m_v_levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColourExtractor::set_v_quantization_levels(size_t v_levels)
|
||||||
|
{
|
||||||
|
delete[] m_pixels;
|
||||||
|
|
||||||
|
m_v_levels = v_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));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColourExtractor::add_pixel(struct ColourHSV hsv)
|
||||||
|
{
|
||||||
|
size_t colour_quant;
|
||||||
|
|
||||||
|
colour_quant = quantize(hsv);
|
||||||
|
m_pixels[colour_quant] += 1;
|
||||||
|
|
||||||
|
if (m_max_colour_count < m_pixels[colour_quant])
|
||||||
|
{
|
||||||
|
m_max_colour_count = m_pixels[colour_quant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColourExtractor::clear_pixels()
|
||||||
|
{
|
||||||
|
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 ColourHSV ColourExtractor::extract_colour() const
|
||||||
|
{
|
||||||
|
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_v_levels; ++i)
|
||||||
|
{
|
||||||
|
if (0 == m_pixels[i])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp_colour = dequantize(i);
|
||||||
|
temp_colour_weight = static_cast<double>(m_pixels[i]);
|
||||||
|
temp_colour_weight /= m_max_colour_count;
|
||||||
|
|
||||||
|
temp_colour_value = evaluate_colour(temp_colour, temp_colour_weight);
|
||||||
|
if (temp_colour_value > max_colour_value)
|
||||||
|
{
|
||||||
|
result = temp_colour;
|
||||||
|
max_colour_value = temp_colour_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColourExtractor::~ColourExtractor()
|
||||||
|
{
|
||||||
|
delete[] m_pixels;
|
||||||
|
}
|
||||||
72
colour_extractor.h
Normal file
72
colour_extractor.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#ifndef COLOUR_EXTRACTOR_H_
|
||||||
|
#define COLOUR_EXTRACTOR_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "colours.h"
|
||||||
|
|
||||||
|
class ColourExtractor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// Holds all quantized pixels
|
||||||
|
size_t* m_pixels;
|
||||||
|
|
||||||
|
// Holds the ammount of the colour that appears the most
|
||||||
|
size_t m_max_colour_count;
|
||||||
|
|
||||||
|
// Quantization levels for the HSV colours
|
||||||
|
size_t m_h_levels;
|
||||||
|
size_t m_s_levels;
|
||||||
|
size_t m_v_levels;
|
||||||
|
|
||||||
|
// Quantizes the colour
|
||||||
|
size_t quantize(struct ColourHSV hsv) const;
|
||||||
|
|
||||||
|
// Dequantizes the colour
|
||||||
|
struct ColourHSV dequantize(size_t colour) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Evaluates the given colour based on its 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 v_levels = 10);
|
||||||
|
|
||||||
|
void get_quantization_levels(size_t& h_levels, size_t& s_levels,
|
||||||
|
size_t& v_levels) const;
|
||||||
|
|
||||||
|
// Note: clears all pixels
|
||||||
|
void set_quantization_levels(size_t h_levels, size_t s_levels,
|
||||||
|
size_t v_levels);
|
||||||
|
|
||||||
|
size_t get_h_quantization_levels() const;
|
||||||
|
|
||||||
|
// Note: clears all pixels
|
||||||
|
void set_h_quantization_levels(size_t h_levels);
|
||||||
|
|
||||||
|
size_t get_s_quantization_levels() const;
|
||||||
|
|
||||||
|
// Note: clears all pixels
|
||||||
|
void set_s_quantization_levels(size_t s_levels);
|
||||||
|
|
||||||
|
size_t get_v_quantization_levels() const;
|
||||||
|
|
||||||
|
// Note: clears all pixels
|
||||||
|
void set_v_quantization_levels(size_t v_levels);
|
||||||
|
|
||||||
|
// Adds a pixel to be considered for extraction
|
||||||
|
void add_pixel(struct ColourHSV hsv);
|
||||||
|
|
||||||
|
// Clears all pixels
|
||||||
|
void clear_pixels();
|
||||||
|
|
||||||
|
// Extracts a single colour from all added pixels
|
||||||
|
struct ColourHSV extract_colour() const;
|
||||||
|
|
||||||
|
~ColourExtractor();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COLOUR_EXTRACTOR_H_
|
||||||
188
colours.c
Normal file
188
colours.c
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
#include "colours.h"
|
||||||
|
|
||||||
|
#include <tgmath.h>
|
||||||
|
|
||||||
|
struct ColourRGB CMYKtoRGB(struct ColourCMYK cmyk)
|
||||||
|
{
|
||||||
|
struct ColourRGB result;
|
||||||
|
|
||||||
|
result.r = (1.0 - cmyk.c) * (1.0 - cmyk.k);
|
||||||
|
result.g = (1.0 - cmyk.m) * (1.0 - cmyk.k);
|
||||||
|
result.b = (1.0 - cmyk.y) * (1.0 - cmyk.k);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColourRGB HSVtoRGB(struct ColourHSV hsv)
|
||||||
|
{
|
||||||
|
struct ColourRGB result;
|
||||||
|
double c;
|
||||||
|
double x;
|
||||||
|
double m;
|
||||||
|
|
||||||
|
c = hsv.s * hsv.v;
|
||||||
|
x = c * (1 - fabs(fmod(hsv.h / 60.0, 2) - 1));
|
||||||
|
m = hsv.v - c;
|
||||||
|
|
||||||
|
int angle = hsv.h / 60;
|
||||||
|
switch (angle)
|
||||||
|
{
|
||||||
|
// 0 - 60
|
||||||
|
case 6:
|
||||||
|
case 0:
|
||||||
|
result.r = c;
|
||||||
|
result.g = x;
|
||||||
|
result.b = 0;
|
||||||
|
break;
|
||||||
|
// 60 - 120
|
||||||
|
case 1:
|
||||||
|
result.r = x;
|
||||||
|
result.g = c;
|
||||||
|
result.b = 0;
|
||||||
|
break;
|
||||||
|
// 120 - 180
|
||||||
|
case 2:
|
||||||
|
result.r = 0;
|
||||||
|
result.g = c;
|
||||||
|
result.b = x;
|
||||||
|
break;
|
||||||
|
// 180 - 240
|
||||||
|
case 3:
|
||||||
|
result.r = 0;
|
||||||
|
result.g = x;
|
||||||
|
result.b = c;
|
||||||
|
break;
|
||||||
|
// 240 - 300
|
||||||
|
case 4:
|
||||||
|
result.r = x;
|
||||||
|
result.g = 0;
|
||||||
|
result.b = c;
|
||||||
|
break;
|
||||||
|
// 300 - 360
|
||||||
|
case 5:
|
||||||
|
result.r = c;
|
||||||
|
result.g = 0;
|
||||||
|
result.b = x;
|
||||||
|
break;
|
||||||
|
// Should never happen
|
||||||
|
default:
|
||||||
|
result.r = 0;
|
||||||
|
result.g = 0;
|
||||||
|
result.b = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.r += m;
|
||||||
|
result.g += m;
|
||||||
|
result.b += m;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColourRGB HSLtoRGB(struct ColourHSL hsl)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColourCMYK RGBtoCMYK(struct ColourRGB rgb)
|
||||||
|
{
|
||||||
|
struct ColourCMYK result;
|
||||||
|
|
||||||
|
|
||||||
|
// max(r,g,b)
|
||||||
|
result.k = rgb.r > rgb.g ? rgb.r : rgb.g;
|
||||||
|
result.k = rgb.b > result.k ? rgb.b : result.k;
|
||||||
|
result.k = 1.0 - result.k;
|
||||||
|
|
||||||
|
if (1.0 == result.k)
|
||||||
|
{
|
||||||
|
result.c = 0;
|
||||||
|
result.m = 0;
|
||||||
|
result.y = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.c = (1.0 - rgb.r - result.k) / (1.0 - result.k);
|
||||||
|
result.m = (1.0 - rgb.g - result.k) / (1.0 - result.k);
|
||||||
|
result.y = (1.0 - rgb.b - result.k) / (1.0 - result.k);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColourCMYK HSVtoCMYK(struct ColourHSV hsv)
|
||||||
|
{
|
||||||
|
struct ColourCMYK result;
|
||||||
|
|
||||||
|
result = RGBtoCMYK(HSVtoRGB(hsv));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColourHSV RGBtoHSV(struct ColourRGB rgb)
|
||||||
|
{
|
||||||
|
struct ColourHSV result;
|
||||||
|
|
||||||
|
double c_max;
|
||||||
|
double c_min;
|
||||||
|
double delta;
|
||||||
|
|
||||||
|
// max(r,g,b)
|
||||||
|
c_max = rgb.r > rgb.g ? rgb.r : rgb.g;
|
||||||
|
c_max = rgb.b > c_max ? rgb.b : c_max;
|
||||||
|
|
||||||
|
// min(r,g,b)
|
||||||
|
c_min = rgb.r < rgb.g ? rgb.r : rgb.g;
|
||||||
|
c_min = rgb.b < c_min ? rgb.b : c_min;
|
||||||
|
|
||||||
|
delta = c_max - c_min;
|
||||||
|
|
||||||
|
if (delta > 0)
|
||||||
|
{
|
||||||
|
if (c_max == rgb.r)
|
||||||
|
{
|
||||||
|
result.h = 60 * fmod((rgb.g - rgb.b) / delta, 6);
|
||||||
|
}
|
||||||
|
else if (c_max == rgb.g)
|
||||||
|
{
|
||||||
|
result.h = 60 * ((rgb.b - rgb.r) / delta + 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.h = 60 * ((rgb.r - rgb.g) / delta + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c_max > 0)
|
||||||
|
{
|
||||||
|
result.s = delta / c_max;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.s = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.v = c_max;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.h = 0;
|
||||||
|
result.s = 0;
|
||||||
|
result.v = c_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.h < 0)
|
||||||
|
{
|
||||||
|
result.h += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColourHSV CMYKtoHSV(struct ColourCMYK cmyk)
|
||||||
|
{
|
||||||
|
struct ColourHSV result;
|
||||||
|
|
||||||
|
result = RGBtoHSV(CMYKtoRGB(cmyk));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
49
colours.h
Normal file
49
colours.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#ifndef COLOURS_H_
|
||||||
|
#define COLOURS_H_
|
||||||
|
|
||||||
|
struct ColourRGB
|
||||||
|
{
|
||||||
|
double r;
|
||||||
|
double g;
|
||||||
|
double b;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ColourCMYK
|
||||||
|
{
|
||||||
|
double c;
|
||||||
|
double m;
|
||||||
|
double y;
|
||||||
|
double k;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ColourHSV
|
||||||
|
{
|
||||||
|
double h;
|
||||||
|
double s;
|
||||||
|
double v;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ColourHSL
|
||||||
|
{
|
||||||
|
double h;
|
||||||
|
double s;
|
||||||
|
double l;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ColourRGB CMYKtoRGB(struct ColourCMYK cmyk);
|
||||||
|
struct ColourRGB HSVtoRGB(struct ColourHSV hsv);
|
||||||
|
struct ColourRGB HSLtoRGB(struct ColourHSL hsl);
|
||||||
|
|
||||||
|
struct ColourCMYK RGBtoCMYK(struct ColourRGB rgb);
|
||||||
|
struct ColourCMYK HSVtoCMYK(struct ColourHSV hsv);
|
||||||
|
struct ColourCMYK HSLtoCMYK(struct ColourHSL hsl);
|
||||||
|
|
||||||
|
struct ColourHSV RGBtoHSV(struct ColourRGB rgb);
|
||||||
|
struct ColourHSV CMYKtoHSV(struct ColourCMYK cmyk);
|
||||||
|
struct ColourHSV HSLtoHSV(struct ColourHSL hsl);
|
||||||
|
|
||||||
|
struct ColourHSL RGBtoHSL(struct ColourRGB rgb);
|
||||||
|
struct ColourHSL CMYKtoHSL(struct ColourCMYK cmyk);
|
||||||
|
struct ColourHSL HSLtoHSL(struct ColourHSV hsv);
|
||||||
|
|
||||||
|
#endif // COLOURS_H_
|
||||||
55
complimentary_colour_extractor.cpp
Normal file
55
complimentary_colour_extractor.cpp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#include "complimentary_colour_extractor.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
// CONSTRUCTORS
|
||||||
|
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(hsv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROTECTED FUNCS
|
||||||
|
size_t ComplimentaryColourExtractor::evaluate_colour(struct ColourHSV hsv,
|
||||||
|
double weight) const
|
||||||
|
{
|
||||||
|
size_t result = 0;
|
||||||
|
double angle_delta;
|
||||||
|
double additional_colour_weight;
|
||||||
|
|
||||||
|
if ((0.0 == hsv.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(hsv.h - m_main_colour.h);
|
||||||
|
if (angle_delta > 180.0F)
|
||||||
|
{
|
||||||
|
angle_delta = 360.0F - angle_delta;
|
||||||
|
}
|
||||||
|
/* SECTION END */
|
||||||
|
}
|
||||||
|
|
||||||
|
// result = static_cast<size_t>(round(1000.0 * pow(weight, 0.3) * hsv.v *
|
||||||
|
// fmin(1.0, hsv.v + hsv.s) * additional_colour_weight * angle_delta));
|
||||||
|
|
||||||
|
result = static_cast<size_t>(round(1000.0 * pow(weight, 0.3) * hsv.v *
|
||||||
|
additional_colour_weight * angle_delta));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUBLIC FUNCS
|
||||||
|
struct ColourHSV ComplimentaryColourExtractor::get_main_colour() const
|
||||||
|
{
|
||||||
|
return m_main_colour;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComplimentaryColourExtractor::set_main_colour(struct ColourHSV hsv)
|
||||||
|
{
|
||||||
|
m_main_colour = hsv;
|
||||||
|
}
|
||||||
24
complimentary_colour_extractor.h
Normal file
24
complimentary_colour_extractor.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef COMPLIMENTARY_COLOUR_EXTRACTOR_H_
|
||||||
|
#define COMPLIMENTARY_COLOUR_EXTRACTOR_H_
|
||||||
|
|
||||||
|
#include "colour_extractor.h"
|
||||||
|
|
||||||
|
class ComplimentaryColourExtractor : public ColourExtractor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// Main colour against which we are finding the complimentary
|
||||||
|
struct ColourHSV m_main_colour;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Implemented - Evaluates the given colour based on its weight
|
||||||
|
virtual size_t evaluate_colour(struct ColourHSV hsv, double weight) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ComplimentaryColourExtractor(struct ColourHSV hsv, 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COMPLIMENTARY_COLOUR_EXTRACTOR_H_
|
||||||
103
main.cpp
103
main.cpp
@ -0,0 +1,103 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#include "stb_image_write.h"
|
||||||
|
|
||||||
|
#include "Extractor.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
void usage(char *name)
|
||||||
|
{
|
||||||
|
cout << "Usage: " << name << " [input image]" << endl;
|
||||||
|
cout << "Supported image formats: JPG, PNG, TGA, BMP, GIF" << endl;
|
||||||
|
cout << "Image must have 3 or more channels" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int x_size;
|
||||||
|
int y_size;
|
||||||
|
int channels;
|
||||||
|
int error;
|
||||||
|
unsigned char *image = nullptr;
|
||||||
|
PixelRGB pixel;
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
cout << "Not enough arguments" << endl;
|
||||||
|
usage(argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = stbi_info("argv", &x_size, &y_size, &channels);
|
||||||
|
if (1 != error)
|
||||||
|
{
|
||||||
|
cout << "Image type is not supported" << endl;
|
||||||
|
usage(argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channels < 3)
|
||||||
|
{
|
||||||
|
cout << "This image is in grayscale (it has no colour)" << endl;
|
||||||
|
usage(argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
image = stbi_load("argv", &x_size, &y_size, &channels, 0);
|
||||||
|
if (nullptr == image)
|
||||||
|
{
|
||||||
|
cout << "Could not open image" << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < x_size * y_size * channels; i += channels)
|
||||||
|
{
|
||||||
|
pixel.r = image[i + 0];
|
||||||
|
pixel.g = image[i + 1];
|
||||||
|
pixel.b = image[i + 2];
|
||||||
|
|
||||||
|
if (channels > 3)
|
||||||
|
{
|
||||||
|
// TODO: Handle alpha here
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add pixel to evaluator here
|
||||||
|
}
|
||||||
|
stbi_image_free(image);
|
||||||
|
|
||||||
|
// TODO: Get main and comp colours here
|
||||||
|
// TODO: Print them to console
|
||||||
|
|
||||||
|
x_size = 16;
|
||||||
|
y_size = 16;
|
||||||
|
channels = 3;
|
||||||
|
image = new unsigned char[x_size * y_size * channels];
|
||||||
|
if (nullptr == image)
|
||||||
|
{
|
||||||
|
cout << "Could not allocate space for image" << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < x_size * y_size; ++i)
|
||||||
|
{
|
||||||
|
// TODO: Fill image with pixel data here
|
||||||
|
}
|
||||||
|
|
||||||
|
stbi_write_png("main.png", x_size, y_size, channels, image, x_size * channels);
|
||||||
|
|
||||||
|
for (int i = 0; i < x_size * y_size; ++i)
|
||||||
|
{
|
||||||
|
// TODO: Fill image with pixel data here
|
||||||
|
}
|
||||||
|
|
||||||
|
stbi_write_png("comp.png", x_size, y_size, channels, image, x_size * channels);
|
||||||
|
|
||||||
|
delete[] image;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
51
main_colour_extractor.cpp
Normal file
51
main_colour_extractor.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "main_colour_extractor.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
size_t result = 0;
|
||||||
|
double lightness;
|
||||||
|
|
||||||
|
lightness = calculate_lightness(hsv);
|
||||||
|
if (lightness >= m_lightness_threshold)
|
||||||
|
{
|
||||||
|
result = static_cast<size_t>(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;
|
||||||
|
}
|
||||||
28
main_colour_extractor.h
Normal file
28
main_colour_extractor.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef MAIN_COLOUR_EXTRACTOR_H_
|
||||||
|
#define MAIN_COLOUR_EXTRACTOR_H_
|
||||||
|
|
||||||
|
#include "colour_extractor.h"
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAIN_COLOUR_EXTRACTOR_H_
|
||||||
Loading…
Reference in New Issue
Block a user