Last active
January 1, 2016 03:38
-
-
Save duckie/8086422 to your computer and use it in GitHub Desktop.
C++11 - Associate a RGB color to a given unsigned integral number in order to maximize local contrast. Two algorithms are given. The second is called in the main loop.
With no arguments, a consistency check verifies that every possible color in the context are used, with no overlap.
With 1 arguments, it outputs the colors from index 0 to ARG (in…
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 <array> | |
#include <cstdlib> | |
#include <functional> | |
#include <iostream> | |
#include <tuple> | |
#include <set> | |
#include <map> | |
#include <vector> | |
namespace colorscale { | |
using uchar_t = unsigned char; | |
using color_t = std::array<uchar_t, 3>; | |
color_t ComputeColorFromIndexSimple(size_t index) { | |
color_t result {{0,0,0}}; | |
for(size_t i = 0; i < 8; ++i) { | |
size_t power = 7 - i; | |
for(uchar_t& elem : result) { | |
elem |= ((index%2) << power); | |
index /= 2; | |
} | |
} | |
return result; | |
} | |
// First element is the abcissa, second is the direction | |
// Third element is the ordinate, 4th is the direction | |
// 5th tells if the last dimension must be set to 0 (false) or 255 (true) | |
using range_t = std::tuple<uchar_t, bool, uchar_t, bool, bool>; | |
using cube_8th_t = std::array<range_t, 3>; | |
color_t ComputeColorFromIndex(size_t index) { | |
// Defining constants data describing the RGB cube face parts | |
std::array<color_t, 8> const summits {{ | |
{{0,0,0}} | |
, {{255,0,0}} | |
, {{255,255,0}} | |
, {{0,255,0}} | |
, {{0,0,255}} | |
, {{255,0,255}} | |
, {{255,255,255}} | |
, {{0,255,255}} | |
}}; | |
std::array<cube_8th_t, 8> const faces_parts {{ | |
{{ range_t(0,true,2,true, false), range_t(2,true,1,true,false), range_t(1,true,0,true,false) }} | |
, {{ range_t(1,true,2,true,true), range_t(2,true,0,false,false), range_t(0,false,1,true,false) }} | |
, {{ range_t(0,false,2,true,true), range_t(2,true, 1, false, true), range_t(1,false,0,false, false) }} | |
, {{ range_t(1,false,2,true,false), range_t(2,true,0,true,true), range_t(0,true,1,false,false) }} | |
, {{ range_t(2,false,0,true,false), range_t(0,true,1,true,true), range_t(1,true,2,false,false) }} | |
, {{ range_t(2,false,1,true,true), range_t(1,true,0,false,true), range_t(0,false,2,false,false) }} | |
, {{ range_t(2,false,0,false,true), range_t(0,false,1,false,true), range_t(1,false,2,false,true) }} | |
, {{ range_t(2,false,1,false,false), range_t(1,false,0,true,true), range_t(0,true,2,false,true) }} | |
}}; | |
auto const choose_bucket = [](size_t i) -> size_t { | |
switch (i) { | |
case 0: return 2; | |
case 1: return 5; | |
case 2: return 0; | |
case 3: return 3; | |
case 4: return 6; | |
case 5: return 1; | |
case 6: return 4; | |
case 7: | |
default: return 7; | |
} | |
}; | |
// This algorithm is limited to the external faces of the RGB cube | |
index %= (2*256*256 + 2*256*254 + 2*254*254); | |
// The first 3 bits chose the summit | |
size_t summit_index = index % 8; | |
index /= 8; | |
color_t result {{ 0, 0, 0 }}; | |
if(0u == index) { | |
result = summits[summit_index]; | |
} | |
else { | |
// Choose a face then normalize the index | |
--index; | |
size_t chosen_face_index = index % 3; | |
index /= 3; | |
// Extract x component and y component | |
size_t x_comp = index%128; | |
size_t y_comp = index/128; | |
// The following lines work for 128x127 areas but is not | |
// easily extendable to other dimensions | |
size_t x_coord = 16*choose_bucket(x_comp%8) + x_comp/8; | |
size_t y_coord = 16*choose_bucket(y_comp%8) + y_comp/8 + 1; | |
// Project that position on the given face | |
range_t const & face = faces_parts[summit_index][chosen_face_index]; | |
result[std::get<0>(face)] = std::get<1>(face) ? x_coord : 255 - x_coord; | |
result[std::get<2>(face)] = std::get<3>(face) ? y_coord : 255 - y_coord; | |
// Find the third axis | |
size_t sum = std::get<0>(face) + std::get<2>(face); | |
size_t third_axis = (1 == sum) ? 2u : ((2 == sum) ? 1u : 0u); | |
result[third_axis] = std::get<4>(face) ? 255u : 0u; | |
} | |
return result; | |
} | |
} // namespace colorscale | |
int main(int argc, char * argv[]) { | |
using colorscale::color_t; | |
using colorscale::ComputeColorFromIndex; | |
size_t index_start = 0; | |
size_t index_end = 390151; | |
if (2 < argc) { | |
index_start = ::atoi(argv[1]); | |
index_end = ::atoi(argv[2]); | |
} | |
else if (1 < argc) { | |
index_end = ::atoi(argv[1]); | |
} | |
// With no arguments, we do a consistency check | |
if(1 == argc) { | |
std::set<color_t> color_set; | |
for (size_t i = index_start; i <= index_end; ++i) { | |
color_set.insert(ComputeColorFromIndex(i)); | |
if(0 == i%3900) std::cout << "\rConsistency check " << 100*(i-index_start)/(index_end-index_start) << " % " << std::flush; | |
} | |
std::cout << std::endl; | |
if(index_end + 1 == color_set.size()) { | |
std::cout << "Consistency test succeeded." << std::endl; | |
} | |
else { | |
std::cout << "Consistency test failed." << std::endl; | |
return 1; | |
} | |
} | |
else { | |
for (size_t i = index_start; i <= index_end; ++i) { | |
color_t color = ComputeColorFromIndex(i); | |
std::cout << static_cast<size_t>(color[0]) << ',' << static_cast<size_t>(color[1]) << ',' << static_cast<size_t>(color[2]) << std::endl; | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See this forum post for rendering examples: http://www.developpez.net/forums/d1402061/c-cpp/cpp/selection-d-couleur-rgb/#post7623238