#include "image.hpp"
#include <map>
Buf::Buf(unsigned _w, unsigned _h): buf((unsigned char*)malloc(_w*_h*3)), proxy(false), off_x(0), off_y(0), width(_w), height(_h), w(_w), h(_h) {
assert(w && h);
}
Buf::Buf(const Buf& b): buf((unsigned char*)memcpy(malloc(b.width*b.height*3), b.buf, b.width*b.height*3)), proxy(false), off_x(0), off_y(0), width(b.width), height(b.height), w(b.w), h(b.h) {
}
Buf::Buf(Buf* b, unsigned _x, unsigned _y, unsigned _w, unsigned _h): buf(b->buf), proxy(true), off_x(_x), off_y(_y), width(b->width), height(b->height), w(_w), h(_h) {
assert(off_x + w < width && off_y + h < height);
}
Buf::~Buf() {
if (!proxy) {
free(buf);
}
}
void Image::put(unsigned x, unsigned y, const Image* other) {
assert(x < buf.w && y < buf.h);
for (unsigned xx=0; xx<MIN(other->buf.w, other->buf.h); ++xx) {
for (unsigned yy=0; yy<MIN(other->buf.h, buf.h-y); ++yy) {
buf.at(x+xx, y+yy) = other->buf.at(xx, yy);
}
}
}
Image* Image::box(unsigned dim) const {
assert(dim);
if (dim > buf.w || dim > buf.h) return NULL;
if (dim == buf.w && dim == buf.h) return new Image(*this);
unsigned x_skip=0, y_skip=0;
if (buf.w > buf.h) {
x_skip = (buf.w-buf.h)/2;
} else if (buf.h > buf.w) {
y_skip = (buf.h-buf.w)/2;
}
const unsigned sample = MIN(buf.w, buf.h)/dim; // TODO: rounding etc?
Image* im = new Image(dim, dim);
for (unsigned x=0; x<dim; x++) {
for (unsigned y=0; y<dim; y++) {
im->buf.at(x, y) = avg(x_skip+(x*sample), y_skip+(y*sample), sample, sample);
}
}
return im;
}
Image* Image::boxed(unsigned x, unsigned y, unsigned w, unsigned h) {
assert(x < buf.w && y < buf.h);
#if 1
return new Image(&buf, x, y, w, h);
#else
Image* im = new Image(w, h);
for (unsigned xx=x; xx<MIN(buf.w, x+w); ++xx) {
for (unsigned yy=y; yy<MIN(buf.h, y+h); ++yy) {
im->buf.at(xx-x, yy-y) = buf.at(xx, yy);
}
}
return im;
#endif
}
rgb_t Image::avg(unsigned x, unsigned y, unsigned w, unsigned h) const {
assert(x < buf.w && y < buf.h);
#if 1
unsigned num = 0;
unsigned sum[3] = {};
for (unsigned xx=x; xx<MIN(buf.w, x+w); ++xx) {
for (unsigned yy=y; yy<MIN(buf.h, y+h); ++yy) {
num++;
sum[0] += buf.at(xx, yy).r;
sum[1] += buf.at(xx, yy).g;
sum[2] += buf.at(xx, yy).b;
}
}
rgb_t rv = {};
if (num) {
rv.r = sum[0]/num;
rv.g = sum[1]/num;
rv.b = sum[2]/num;
}
return rv;
#elif 0
static unsigned palette[25][25][25];
memset(palette, 0, sizeof(palette));
unsigned max_num = 0;
rgb_t max_rgb = {};
for (unsigned xx=x; xx<MIN(buf.w, x+w); ++xx) {
for (unsigned yy=y; yy<MIN(buf.h, y+h); ++yy) {
const rgb_t& rgb = buf.at(xx, yy);
unsigned& p = palette[rgb.r/10][rgb.g/10][rgb.b/10];
if (++p > max_num) {
max_num = p;
max_rgb = rgb;
}
}
}
return max_rgb;
#endif
}
rgb_t Image::med(unsigned x, unsigned y, unsigned w, unsigned h) const {
#if 1
assert(x < buf.w && y < buf.h);
const unsigned char bucket_width = 1; // TODO:
std::map<rgb_t, unsigned> buckets;
std::map<rgb_t, unsigned>::const_iterator max_bucket = buckets.end();
for (unsigned xx=x; xx<MIN(buf.w, x+w); ++xx) {
for (unsigned yy=y; yy<MIN(buf.h, y+h); ++yy) {
const rgb_t& rgb = buf.at(xx, yy);
const rgb_t& value = {
(unsigned char)(rgb.r / bucket_width),
(unsigned char)(rgb.g / bucket_width),
(unsigned char)(rgb.b / bucket_width)
};
std::map<rgb_t, unsigned>::iterator bucket = buckets.find(value);
if (bucket != buckets.end()) {
bucket->second = bucket->second + 1;
} else {
bucket = buckets.insert(std::pair<rgb_t, unsigned>(value, 1)).first;
}
if (max_bucket == buckets.end() || bucket->second > max_bucket->second) {
max_bucket = bucket;
}
}
}
assert(max_bucket != buckets.end());
return rgb_t{
(unsigned char)(max_bucket->first.r + (bucket_width / 2)),
(unsigned char)(max_bucket->first.g + (bucket_width / 2)),
(unsigned char)(max_bucket->first.b + (bucket_width / 2)),
};
#else
return avg(x, y, w, h);
#endif
}
void Image::tint(unsigned x, unsigned y, unsigned w, unsigned h, const rgb_t& c, unsigned char alpha) {
for (unsigned xx=x; xx<MIN(buf.w, x+w); ++xx) {
for (unsigned yy=y; yy<MIN(buf.h, y+h); ++yy) {
buf.at(xx, yy).tint(c, alpha);
}
}
}
void Image::tint(const Image* im, unsigned char alpha) {
for (unsigned x=0; x<MIN(buf.w, im->buf.w); ++x) {
for (unsigned y=0; y<MIN(buf.h, im->buf.h); ++y) {
buf.at(x, y).tint(im->buf.at(x, y), alpha);
}
}
}
unsigned char Image::dist(const rgb_t& c) const {
unsigned rv = 0;
for (unsigned x=0; x<buf.w; ++x) {
for (unsigned y=0; y<buf.h; ++y) {
rv += c.dist(buf.at(x, y));
}
}
return rv / (buf.w * buf.h);
}
unsigned char Image::dist(const Image* im) const {
assert(buf.w == im->buf.w && buf.h == im->buf.h);
unsigned rv = 0;
for (unsigned x=0; x<buf.w; ++x) {
for (unsigned y=0; y<buf.h; ++y) {
rv += buf.at(x, y).dist(im->buf.at(x, y));
}
}
return rv / (buf.w * buf.h);
}
double Image::fdist(const Image* im) const {
assert(buf.w == im->buf.w && buf.h == im->buf.h);
double rv = 0;
for (unsigned x=0; x<buf.w; ++x) {
for (unsigned y=0; y<buf.h; ++y) {
rv += buf.at(x, y).fdist(im->buf.at(x, y));
}
}
return rv / (buf.w * buf.h);
}