don't redistribute colors when more than 50% of a cell are of the same two colors

This commit is contained in:
stefan.haustein@gmail.com 2017-10-16 22:28:22 +02:00
parent 0d8a3e6322
commit a69ffa848d

View file

@ -1,6 +1,7 @@
#include <iostream> #include <iostream>
#include <bitset> #include <bitset>
#include <cmath> #include <cmath>
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -168,38 +169,81 @@ CharData getCharData(const cimg_library::CImg<unsigned char> & image, int x0, in
CharData getCharData(const cimg_library::CImg<unsigned char> & image, int x0, int y0) { CharData getCharData(const cimg_library::CImg<unsigned char> & image, int x0, int y0) {
int min[3] = {255, 255, 255}; int min[3] = {255, 255, 255};
int max[3] = {0}; int max[3] = {0};
std::map<long,int> count_per_color;
// Determine the minimum and maximum value for each color channel // Determine the minimum and maximum value for each color channel
for (int y = 0; y < 8; y++) { for (int y = 0; y < 8; y++) {
for (int x = 0; x < 4; x++) { for (int x = 0; x < 4; x++) {
long color = 0;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
int d = image(x0 + x, y0 + y, 0, i); int d = image(x0 + x, y0 + y, 0, i);
min[i] = std::min(min[i], d); min[i] = std::min(min[i], d);
max[i] = std::max(max[i], d); max[i] = std::max(max[i], d);
color = (color << 8) | d;
}
count_per_color[color]++;
}
}
std::multimap<int,long> color_per_count;
for (auto i = count_per_color.begin(); i != count_per_color.end(); ++i) {
color_per_count.insert(std::pair<int,long>(i->second, i->first));
}
auto iter = color_per_count.rbegin();
int count2 = iter->first;
long max_count_color_1 = iter->second;
long max_count_color_2 = max_count_color_1;
if (iter != color_per_count.rend()) {
++iter;
count2 += iter->first;
max_count_color_2 = iter->second;
}
unsigned int bits = 0;
bool direct = count2 > (8*4) / 2;
if (direct) {
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 4; x++) {
bits = bits << 1;
int d1 = 0;
int d2 = 0;
for (int i = 0; i < 3; i++) {
int shift = 16 - 8 * i;
int c1 = (max_count_color_1 >> shift) & 255;
int c2 = (max_count_color_2 >> shift) & 255;
int c = image(x0 + x, y0 + y, 0, i);
d1 += (c1-c) * (c1-c);
d2 += (c2-c) * (c2-c);
}
if (d1 > d2) {
bits |= 1;
}
} }
} }
}
// Determine the color channel with the greatest range. } else {
int splitIndex = 0; // Determine the color channel with the greatest range.
int bestSplit = 0; int splitIndex = 0;
for (int i = 0; i < 3; i++) { int bestSplit = 0;
if (max[i] - min[i] > bestSplit) { for (int i = 0; i < 3; i++) {
bestSplit = max[i] - min[i]; if (max[i] - min[i] > bestSplit) {
splitIndex = i; bestSplit = max[i] - min[i];
splitIndex = i;
}
} }
}
// We just split at the middle of the interval instead of computing the median. // We just split at the middle of the interval instead of computing the median.
int splitValue = min[splitIndex] + bestSplit / 2; int splitValue = min[splitIndex] + bestSplit / 2;
// Compute a bitmap using the given split and sum the color values for both buckets. // Compute a bitmap using the given split and sum the color values for both buckets.
unsigned int bits = 0; for (int y = 0; y < 8; y++) {
for (int y = 0; y < 8; y++) { for (int x = 0; x < 4; x++) {
for (int x = 0; x < 4; x++) { bits = bits << 1;
bits = bits << 1; if (image(x0 + x, y0 + y, 0, splitIndex) > splitValue) {
if (image(x0 + x, y0 + y, 0, splitIndex) > splitValue) { bits |= 1;
bits |= 1; }
} }
} }
} }
@ -209,6 +253,7 @@ CharData getCharData(const cimg_library::CImg<unsigned char> & image, int x0, in
int best_diff = 8; int best_diff = 8;
unsigned int best_pattern = 0x0000ffff; unsigned int best_pattern = 0x0000ffff;
int codepoint = 0x2584; int codepoint = 0x2584;
bool inverted = false;
for (int i = 0; BITMAPS[i + 1] != 0; i += 2) { for (int i = 0; BITMAPS[i + 1] != 0; i += 2) {
unsigned int pattern = BITMAPS[i]; unsigned int pattern = BITMAPS[i];
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
@ -217,11 +262,27 @@ CharData getCharData(const cimg_library::CImg<unsigned char> & image, int x0, in
best_pattern = BITMAPS[i]; // pattern might be inverted. best_pattern = BITMAPS[i]; // pattern might be inverted.
codepoint = BITMAPS[i + 1]; codepoint = BITMAPS[i + 1];
best_diff = diff; best_diff = diff;
inverted = best_pattern != pattern;
} }
pattern = ~pattern; pattern = ~pattern;
} }
} }
if (direct) {
CharData result;
if (inverted) {
long tmp = max_count_color_1;
max_count_color_1 = max_count_color_2;
max_count_color_2 = tmp;
}
for (int i = 0; i < 3; i++) {
int shift = 16 - 8 * i;
result.fgColor[i] = (max_count_color_2 >> shift) & 255;
result.bgColor[i] = (max_count_color_1 >> shift) & 255;
result.codePoint = codepoint;
}
return result;
}
return getCharData(image, x0, y0, codepoint, best_pattern); return getCharData(image, x0, y0, codepoint, best_pattern);
} }
@ -230,10 +291,12 @@ int clamp_byte(int value) {
return value < 0 ? 0 : (value > 255 ? 255 : value); return value < 0 ? 0 : (value > 255 ? 255 : value);
} }
double sqr(double n) { double sqr(double n) {
return n*n; return n*n;
} }
int best_index(int value, const int data[], int count) { int best_index(int value, const int data[], int count) {
int best_diff = std::abs(data[0] - value); int best_diff = std::abs(data[0] - value);
int result = 0; int result = 0;
@ -282,7 +345,6 @@ void emit_color(int flags, int r, int g, int b) {
} }
void emitCodepoint(int codepoint) { void emitCodepoint(int codepoint) {
if (codepoint < 128) { if (codepoint < 128) {
std::cout << (char) codepoint; std::cout << (char) codepoint;
@ -318,6 +380,7 @@ void emit_image(const cimg_library::CImg<unsigned char> & image, int flags) {
} }
} }
void emit_usage() { void emit_usage() {
std::cerr << "Terminal Image Viewer" << std::endl << std::endl; std::cerr << "Terminal Image Viewer" << std::endl << std::endl;
std::cerr << "usage: tiv [options] <image> [<image>...]" << std::endl << std::endl; std::cerr << "usage: tiv [options] <image> [<image>...]" << std::endl << std::endl;