#include "colors.hpp"
unsigned char rgb_t::dist(const rgb_t& o) const {
if (config.dist_func == config_t::DIST_LAB) {
lab_s a(*this), b(o);
return a.dist(b) * 255.0 / 400.0;
} else if (config.dist_func == config_t::DIST_EUCLID) {
unsigned rr = ABSDIFF(r, o.r);
unsigned gg = ABSDIFF(g, o.g);
unsigned bb = ABSDIFF(b, o.b);
static const double max = std::sqrt(255.0*255.0*3.0);
return std::sqrt((rr*rr) + (gg*gg) + (bb*bb)) * 255.0 / max;
} else {
assert(config.dist_func == config_t::DIST_AVG);
return ((unsigned)ABSDIFF(r, o.r) + (unsigned)ABSDIFF(g, o.g) + (unsigned)ABSDIFF(b, o.b)) / 3;
}
}
double rgb_t::fdist(const rgb_t& o) const {
if (config.dist_func == config_t::DIST_LAB) {
lab_s a(*this), b(o);
return a.dist(b);
} else if (config.dist_func == config_t::DIST_EUCLID) {
unsigned rr = ABSDIFF(r, o.r);
unsigned gg = ABSDIFF(g, o.g);
unsigned bb = ABSDIFF(b, o.b);
return std::sqrt((rr*rr) + (gg*gg) + (bb*bb));
} else {
assert(config.dist_func == config_t::DIST_AVG);
return ((unsigned)ABSDIFF(r, o.r) + (unsigned)ABSDIFF(g, o.g) + (unsigned)ABSDIFF(b, o.b)) / 3.0;
}
}
void rgb_t::tint(const rgb_t& col, unsigned char alpha) {
r = (int)r + ((((int)col.r - (int)r) * (int)alpha) / 100);
g = (int)g + ((((int)col.g - (int)g) * (int)alpha) / 100);
b = (int)b + ((((int)col.b - (int)b) * (int)alpha) / 100);
}
lab_s::lab_s(const rgb_t& rgb) {
struct L { static double cbrt(double v, double vn) {
v /= vn;
if (v < 0.009) {
return ((24389.0/27.0) * v + 16.0) / 116.0;
} else {
assert(v > 0.0);
return std::pow(v, 1/3.0);
}
}};
static const double xn = 94.811;
static const double yn = 100.0;
static const double zn = 107.304;
double x = (0.4124564 * rgb.r) + (0.3575761 * rgb.g) + (0.1804375 * rgb.b);
double y = (0.2126729 * rgb.r) + (0.7151522 * rgb.g) + (0.0721750 * rgb.b);
double z = (0.0193339 * rgb.r) + (0.1191920 * rgb.g) + (0.9503041 * rgb.b);
x = L::cbrt(x, xn);
y = L::cbrt(y, yn);
z = L::cbrt(z, zn);
l = 116.0 * y - 16.0;
a = 500.0 * (x - y);
b = 200.0 * (y -z);
}
double lab_t::dist(const lab_t& o) const { // 2.3 corresponds to a just noticeable difference
struct L { static double diffsq(double a, double b) {
a -= b;
return a * a;
}};
return std::sqrt(L::diffsq(l, o.l) + L::diffsq(a, o.a) + L::diffsq(b, o.b)); // max should be ~sqrt(100^2 + 270^2 + 250^2)~381
}
/*hsv_u::hsv_u(const rgb_t& rgb) {
const double min = MIN(MIN(rgb.r, rgb.g), rgb.b);
const double max = MAX(MAX(rgb.r, rgb.g), rgb.b);
const double delta = max - min;
v = (max * 100.0) / 255.0;
if (delta < 1.0 || max < 1.0) {
s = 0;
h = 0;
return;
}
s = (delta / max) * 100.0;
if (rgb.r == max) {
h = (((double)rgb.g - (double)rgb.b) / delta); // scaling needed here?
} else if (rgb.g == max) {
h = 2.0 + (((double)rgb.b - (double)rgb.r) / delta);
} else {
h = 4.0 + (((double)rgb.r - (double)rgb.g) / delta);
}
h *= 60.0;
if (h < 0.0) {
h += 360.0;
}
}
unsigned char hsv_u::dist(const hsv_u& o) const {
return (ABSDIFF(h, o.h)/360.0) * 255.0; // TODO
}*/