don't redistribute colors when more than 50% of a cell are of the same two colors
This commit is contained in:
parent
0d8a3e6322
commit
a69ffa848d
1 changed files with 85 additions and 22 deletions
|
@ -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,47 +169,91 @@ 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]++;
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the color channel with the greatest range.
|
|
||||||
int splitIndex = 0;
|
|
||||||
int bestSplit = 0;
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
if (max[i] - min[i] > bestSplit) {
|
|
||||||
bestSplit = max[i] - min[i];
|
|
||||||
splitIndex = i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We just split at the middle of the interval instead of computing the median.
|
std::multimap<int,long> color_per_count;
|
||||||
int splitValue = min[splitIndex] + bestSplit / 2;
|
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));
|
||||||
// Compute a bitmap using the given split and sum the color values for both buckets.
|
}
|
||||||
|
|
||||||
|
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;
|
unsigned int bits = 0;
|
||||||
for (int y = 0; y < 8; y++) {
|
bool direct = count2 > (8*4) / 2;
|
||||||
for (int x = 0; x < 4; x++) {
|
|
||||||
bits = bits << 1;
|
if (direct) {
|
||||||
if (image(x0 + x, y0 + y, 0, splitIndex) > splitValue) {
|
for (int y = 0; y < 8; y++) {
|
||||||
bits |= 1;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Determine the color channel with the greatest range.
|
||||||
|
int splitIndex = 0;
|
||||||
|
int bestSplit = 0;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (max[i] - min[i] > bestSplit) {
|
||||||
|
bestSplit = max[i] - min[i];
|
||||||
|
splitIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We just split at the middle of the interval instead of computing the median.
|
||||||
|
int splitValue = min[splitIndex] + bestSplit / 2;
|
||||||
|
|
||||||
|
// Compute a bitmap using the given split and sum the color values for both buckets.
|
||||||
|
for (int y = 0; y < 8; y++) {
|
||||||
|
for (int x = 0; x < 4; x++) {
|
||||||
|
bits = bits << 1;
|
||||||
|
if (image(x0 + x, y0 + y, 0, splitIndex) > splitValue) {
|
||||||
|
bits |= 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the best bitmap match by counting the bits that don't match,
|
// Find the best bitmap match by counting the bits that don't match,
|
||||||
// including the inverted bitmaps.
|
// including the inverted bitmaps.
|
||||||
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;
|
||||||
|
|
Loading…
Reference in a new issue