Skip to content

Instantly share code, notes, and snippets.

@AxelStrem
Created December 19, 2016 15:42
Show Gist options
  • Save AxelStrem/bd322a564b9b5107f655d9a8463ae95f to your computer and use it in GitHub Desktop.
Save AxelStrem/bd322a564b9b5107f655d9a8463ae95f to your computer and use it in GitHub Desktop.
// 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