Created
December 19, 2016 15:42
-
-
Save AxelStrem/bd322a564b9b5107f655d9a8463ae95f to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// BorderZoom.cpp : Defines the entry point for the console application. | |
// | |
#include "stdafx.h" | |
#include <vector> | |
#include <windows.h> | |
#include <fstream> | |
#include <string> | |
#include <sstream> | |
#include <map> | |
#include <unordered_map> | |
#include <iostream> | |
struct COLOR_3B | |
{ | |
BYTE b; | |
BYTE g; | |
BYTE r; | |
BYTE a; | |
}; | |
bool in_palette(COLOR_3B col) | |
{ | |
return (col.a | col.b | col.g | col.r) != 0; | |
} | |
struct CTABLE_255 | |
{ | |
COLOR_3B colors[256]; | |
}; | |
using namespace std; | |
typedef COLOR_3B COLOR_4B; | |
#define ZOOM 3 | |
#define SATURATED 20000 | |
struct zpat | |
{ | |
short p[ZOOM*ZOOM]; | |
int visits; | |
zpat() : visits(0), p{} | |
{} | |
template<class S> void Serialize(S& file) | |
{} | |
template<> void Serialize<std::ifstream>(ifstream& file) | |
{ | |
file.read(reinterpret_cast<char*>(&visits), sizeof(visits)); | |
for (int i = 0; i < ZOOM; i++) | |
for (int j = 0; j < ZOOM; j++) | |
{ | |
file.read(reinterpret_cast<char*>(&p[i*ZOOM + j]), sizeof(p[i*ZOOM + j])); | |
} | |
} | |
template<> void Serialize<std::ofstream>(ofstream& file) | |
{ | |
file.write(reinterpret_cast<char*>(&visits), sizeof(visits)); | |
for (int i = 0; i < ZOOM; i++) | |
for (int j = 0; j < ZOOM; j++) | |
{ | |
file.write(reinterpret_cast<char*>(&p[i*ZOOM + j]), sizeof(p[i*ZOOM + j])); | |
} | |
} | |
float getQuality() | |
{ | |
if (visits < 5) return 0.f; | |
short lowest = SATURATED; | |
for (int i = 0; i < ZOOM*ZOOM; i++) | |
lowest = min(lowest, abs(p[i])); | |
return static_cast<float>(lowest) / visits; | |
} | |
}; | |
char dezoom(const std::vector<char>& aperture) | |
{ | |
int r = 0; | |
for (char c : aperture) | |
r += (c ? 1 : -1); | |
if (r > 0) return 1; | |
if (r < 0) return 0; | |
return aperture[0]; | |
} | |
typedef int64_t keytype; | |
template<int size> class Zoomer | |
{ | |
std::map<keytype,zpat> patterns; | |
public: | |
Zoomer(){} | |
void train(const std::vector<char*>& data, const std::vector<char*>& data_dezoomed) | |
{ | |
keytype index = 0; | |
for (int i = 0; i < (size*size); i++) | |
{ | |
index <<= 1; | |
if (data_dezoomed[i / size][i % size]) index++; | |
} | |
if (patterns.find(index) == patterns.end()) | |
{ | |
patterns[index] = {}; | |
} | |
for(int i=0;i<ZOOM;i++) | |
for (int j = 0; j < ZOOM; j++) | |
{ | |
short v = patterns[index].p[i*ZOOM + j]; | |
if (data[(ZOOM*(size - 1) / 2) + i][(ZOOM*(size - 1) / 2) + j] > 0) v = min(v + 1, SATURATED); | |
else v = max(v - 1, -SATURATED); | |
patterns[index].p[i*ZOOM + j] = v; | |
} | |
patterns[index].visits = min(patterns[index].visits + 1, SATURATED); | |
} | |
zpat Apply(std::vector<char>& aperture) | |
{ | |
keytype index = 0; | |
for (int i = 0; i < (size*size); i++) | |
{ | |
index <<= 1; | |
if (aperture[i]) index++; | |
} | |
if (patterns.find(index) == patterns.end()) return zpat(); | |
return patterns[index]; | |
} | |
template<class S> void Serialize(S& file) | |
{} | |
template<> void Serialize<std::ifstream>(ifstream& file) | |
{ | |
int ps; | |
file.read(reinterpret_cast<char*>(&ps), sizeof(ps)); | |
for (int i = 0; i < ps; i++) | |
{ | |
keytype index; | |
file.read(reinterpret_cast<char*>(&index), sizeof(index)); | |
patterns[index] = {}; | |
patterns[index].Serialize(file); | |
} | |
} | |
template<> void Serialize<std::ofstream>(ofstream& file) | |
{ | |
int ps = patterns.size(); | |
file.write(reinterpret_cast<char*>(&ps), sizeof(ps)); | |
for (auto& p : patterns) | |
{ | |
file.write(reinterpret_cast<const char*>(&p.first), sizeof(p.first)); | |
p.second.Serialize(file); | |
} | |
} | |
}; | |
template <int size> class ZoomerCascade | |
{ | |
public: | |
Zoomer<size> Z; | |
ZoomerCascade<size - 2> fallback; | |
template<class S> void Serialize(S& file) | |
{ | |
Z.Serialize(file); | |
fallback.Serialize(file); | |
} | |
}; | |
template <> class ZoomerCascade<1> | |
{ | |
public: | |
Zoomer<1> Z; | |
template<class S> void Serialize(S& file) | |
{ | |
Z.Serialize(file); | |
} | |
}; | |
template <> class ZoomerCascade<0> | |
{ | |
public: | |
template<class S> void Serialize(S& file) | |
{ | |
} | |
}; | |
class Image | |
{ | |
int sx, sy; | |
vector<vector<char>> original; | |
vector<vector<char>> dezoomed; | |
public: | |
Image(int nsx, int nsy) : sx(nsx), sy(nsy) | |
{ | |
original.resize(nsy); | |
for (auto& v : original) v.resize(nsx); | |
dezoomed.resize(nsy / ZOOM); | |
for (auto& v : dezoomed) v.resize(nsx / ZOOM); | |
} | |
void Set(int x, int y, char ch) | |
{ | |
original[y][x] = ch; | |
} | |
char Get(int x, int y) | |
{ | |
return original[y][x]; | |
} | |
void SetDownscaled(int x, int y, char ch) | |
{ | |
dezoomed[y][x] = ch; | |
} | |
void Dezoom() | |
{ | |
vector<char> aperture; | |
aperture.resize(ZOOM*ZOOM); | |
for(int x=0;x<(sx/ZOOM);x++) | |
for (int y = 0; y < (sy / ZOOM); y++) | |
{ | |
for(int i=0;i<ZOOM;i++) | |
for (int j = 0; j < ZOOM; j++) | |
{ | |
aperture[i*ZOOM + j] = original[y*ZOOM + i][x*ZOOM + j]; | |
} | |
dezoomed[y][x] = dezoom(aperture); | |
} | |
} | |
template<int size> float ZoomAperture(ZoomerCascade<size>& c, vector<char>& input, vector<char>& output) | |
{ | |
zpat r = c.Z.Apply(input); | |
float quality = r.getQuality(); | |
if (quality < 0.01f) | |
{ | |
vector<char> input2; | |
int ns = size - 2; | |
input2.resize(ns*ns); | |
for (int i = 0; i < ns; i++) | |
for (int j = 0; j < ns; j++) | |
input2[i*ns + j] = input[(i + 1)*size + j + 1]; | |
float fbq = ZoomAperture(c.fallback, input2, output); | |
for (int i = 0; i < output.size(); i++) | |
if (output[i]) output[i]++; | |
return fbq; | |
} | |
for(int i=0;i<ZOOM;i++) | |
for (int j = 0; j < ZOOM; j++) | |
{ | |
output[i*ZOOM + j] = (r.p[i*ZOOM + j] > 0) ? 1 : 0; | |
} | |
return quality; | |
} | |
template<> float ZoomAperture<1>(ZoomerCascade<1>& c, vector<char>& input, vector<char>& output) | |
{ | |
zpat r = c.Z.Apply(input); | |
float quality = r.getQuality(); | |
for (int i = 0; i<ZOOM; i++) | |
for (int j = 0; j < ZOOM; j++) | |
{ | |
output[i*ZOOM + j] = (r.p[i*ZOOM + j] > 0) ? 1 : 0; | |
} | |
return quality; | |
} | |
template<int size> void Zoom(ZoomerCascade<size>& c) | |
{ | |
vector<char> input; | |
vector<char> output; | |
input.resize(size*size); | |
output.resize(ZOOM*ZOOM); | |
bool clip = false; | |
for (int x = 0; x<(sx / ZOOM); x++) | |
for (int y = 0; y < (sy / ZOOM); y++) | |
{ | |
for(int i=0;i<size;i++) | |
for (int j = 0; j < size; j++) | |
{ | |
int dx = x + i - (size / 2); | |
int dy = y + j - (size / 2); | |
clip = false; | |
if ((dx < 0) || (dy < 0) || (dx >= (sx / ZOOM)) || (dy >= (sy / ZOOM))) clip = true; | |
input[j*size + i] = clip ? 0 : dezoomed[dy][dx]; | |
} | |
ZoomAperture(c, input, output); | |
for(int i=0;i<ZOOM;i++) | |
for (int j = 0; j < ZOOM; j++) | |
{ | |
Set(x*ZOOM + i, y*ZOOM + j, output[j*ZOOM + i]); | |
} | |
} | |
} | |
template<int size> void TrainZoomer(Zoomer<size>& z) | |
{ | |
vector<char*> data; | |
vector<char*> data_dezoomed; | |
data.resize(size*ZOOM); | |
data_dezoomed.resize(size); | |
for(int x=0;x<=((sx/ZOOM)-size);x++) | |
for (int y = 0; y <= ((sy / ZOOM) - size); y++) | |
{ | |
for (int i = 0; i < size; i++) | |
{ | |
data_dezoomed[i] = &(dezoomed[y + i][x]); | |
for (int j = 0; j < ZOOM; j++) | |
{ | |
data[i*ZOOM+j] = &(original[(y + i)*ZOOM+j][x*ZOOM]); | |
} | |
} | |
z.train(data, data_dezoomed); | |
} | |
} | |
template<int size> void TrainCascade(ZoomerCascade<size>& c) | |
{ | |
TrainZoomer(c.Z); | |
TrainCascade(c.fallback); | |
} | |
template<> void TrainCascade<1>(ZoomerCascade<1>& c) | |
{ | |
TrainZoomer(c.Z); | |
} | |
template<> void TrainCascade<0>(ZoomerCascade<0>& c) | |
{ | |
} | |
template<int size> float ApplyZoomer(Zoomer<size>& z) | |
{ | |
vector<char*> data; | |
vector<char*> data_dezoomed; | |
data.resize(size*ZOOM); | |
data_dezoomed.resize(size); | |
for (int x = 0; x <= ((sx / ZOOM) - size); x++) | |
for (int y = 0; y <= ((sy / ZOOM) - size); y++) | |
{ | |
for (int i = 0; i < size; i++) | |
{ | |
data_dezoomed[i] = &(dezoomed[y + i][x]); | |
for (int j = 0; j < ZOOM; j++) | |
{ | |
data[i*ZOOM + j] = &(original[(y + i)*ZOOM + j][x*ZOOM]); | |
} | |
} | |
z.train(data, data_dezoomed); | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment