Last active
December 11, 2015 03:59
-
-
Save usagi/4542114 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <iomanip> | |
#include <stdexcept> | |
#include <limits> | |
#include <vector> | |
#include <array> | |
#include <set> | |
#include <cmath> | |
#include <algorithm> | |
#include <string> | |
#include <cassert> | |
#include <fstream> | |
using namespace std; | |
struct RGB24 { uint8_t r, g, b; }; | |
template<class T> | |
struct HSL { T h, s, l; }; | |
using HSL192F = HSL<double>; | |
using HSL96F = HSL<float>; | |
template<class HSL_TYPE> | |
bool operator<(const HSL_TYPE& a,const HSL_TYPE& b) { | |
if ( a.l > b.l || a.s > b.s ) return false; | |
return a.h < b.h; | |
} | |
template<class HSL_TYPE> | |
bool operator==(const HSL_TYPE& a,const HSL_TYPE& b) { | |
return a.h == b.h && a.s == b.s && a.l == b.l; | |
} | |
template<class INTERNAL_TYPE = double, class RGB_TYPE = RGB24, class HSL_TYPE = HSL192F> | |
HSL_TYPE hsl_from_rgb(RGB_TYPE&& i){ | |
using internal_type = INTERNAL_TYPE; | |
using rgb_type = RGB_TYPE; | |
constexpr internal_type | |
zero = 0., one = 1., two = 2., four = 4., six = 6., | |
binary_1 = one / two, | |
senary_1 = one / six, | |
max_factor = numeric_limits<decltype(i.r)>::max(), | |
unorm_factor = one / max_factor; | |
const auto | |
r = internal_type( i.r ) * unorm_factor, | |
g = internal_type( i.g ) * unorm_factor, | |
b = internal_type( i.b ) * unorm_factor; | |
const auto | |
max_value = max({r, g, b}), | |
min_value = min({r, g, b}); | |
const auto l = (max_value + min_value) * binary_1; | |
if (max_value == min_value) | |
return { | |
static_cast<decltype(HSL_TYPE::h)>(zero), | |
static_cast<decltype(HSL_TYPE::s)>(zero), | |
static_cast<decltype(HSL_TYPE::l)>(l) | |
}; | |
auto d = max_value - min_value; | |
const auto s = d / ( | |
(l > binary_1) | |
? (two - max_value - min_value) | |
: (max_value + min_value) | |
); | |
if (max_value == r) | |
return { | |
static_cast<decltype(HSL_TYPE::h)>( ((g - b) / d + (g < b ? six : zero)) * senary_1 ), | |
static_cast<decltype(HSL_TYPE::s)>(s), | |
static_cast<decltype(HSL_TYPE::l)>(l) | |
}; | |
if (max_value == g) | |
return { | |
static_cast<decltype(HSL_TYPE::h)>( ((b - r) / d + two) * senary_1 ), | |
static_cast<decltype(HSL_TYPE::s)>(s), | |
static_cast<decltype(HSL_TYPE::l)>(l) | |
}; | |
return { | |
static_cast<decltype(HSL_TYPE::h)>( ((r - g) / d + four) * senary_1 ), | |
static_cast<decltype(HSL_TYPE::s)>(s), | |
static_cast<decltype(HSL_TYPE::l)>(l) | |
}; | |
} | |
template<class INTERNAL_TYPE = double, class HSL_TYPE = HSL192F> | |
vector<HSL_TYPE> generate_hsl_colors_from_rgb24() { | |
constexpr uint_fast16_t u = numeric_limits<uint8_t>::max() + 1; | |
constexpr size_t | |
b8 = 256, | |
b16 = b8 * b8, | |
b24 = b16 * b8; | |
vector<HSL_TYPE> colors(b24); | |
#pragma omp parallel for | |
for(uint_fast16_t r = 0; r < u; ++r) | |
for(uint_fast16_t g = 0; g < u; ++g) | |
for(uint_fast16_t b = 0; b < u; ++b) | |
colors[ r + g * b8 + b * b16 ] = hsl_from_rgb<INTERNAL_TYPE, RGB24, HSL_TYPE>({ | |
static_cast<uint8_t>(r), | |
static_cast<uint8_t>(g), | |
static_cast<uint8_t>(b) | |
}); | |
sort(colors.begin(), colors.end()); | |
auto unique_ = unique(colors.begin(), colors.end()); | |
colors.resize(unique_ - colors.begin()); | |
return move(colors); | |
} | |
template<class INTERNAL_TYPE, class HSL_TYPE> | |
void test(const string& filename){ | |
auto cs = generate_hsl_colors_from_rgb24<INTERNAL_TYPE, HSL_TYPE>(); | |
ofstream s(filename); | |
for(auto c : cs) | |
s << c.h << "\t" << c.s << "\t" << c.l << "\n"; | |
} | |
int main() try { | |
constexpr unsigned binary64_precision = log2(52.); | |
constexpr unsigned binary32_precision = log2(23.); | |
setiosflags(ios::scientific); | |
#define TEST(a,b) test<a, b>("hsl_" #a "_" #b ".tsv"); | |
cout.precision(binary64_precision); | |
TEST(double, HSL192F) | |
TEST(float, HSL192F) | |
cout.precision(binary32_precision); | |
TEST(double, HSL96F) | |
TEST(float, HSL96F) | |
#undef TEST | |
} catch (exception e) { | |
cerr << "oops! : " << e.what(); | |
} catch (...) { | |
cerr << "oops! : unknown exception"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment