C-直線
ppmファイルを操作するCの基本的なアプローチ。アルゴリズムは、すべてのピクセルを埋めるために最適なライン長で垂直ラインを配置しようとします。背景色と線の色は、元の画像の平均値(各カラーチャンネルの中央値)として計算されます。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define SIGN(x) ((x > 0) ? 1 : (x < 0) ? -1 : 0)
#define MIN(x, y) ((x > y) ? y : x)
#define MAX(x, y) ((x > y) ? x : y)
typedef struct {
size_t width;
size_t height;
unsigned char *r;
unsigned char *g;
unsigned char *b;
} image;
typedef struct {
unsigned char r;
unsigned char g;
unsigned char b;
} color;
void init_image(image *data, size_t width, size_t height) {
data->width = width;
data->height = height;
data->r = malloc(sizeof(data->r) * data->width * data->height);
data->g = malloc(sizeof(data->g) * data->width * data->height);
data->b = malloc(sizeof(data->b) * data->width * data->height);
}
#define BUFFER_LEN 1024
int load_image(const char *filename, image* data) {
FILE *f = fopen(filename, "r");
char buffer[BUFFER_LEN]; /* read buffer */
size_t max_value;
size_t i;
fgets(buffer, BUFFER_LEN, f);
if (strncmp(buffer, "P3", 2) != 0) {
printf("File begins with %s instead of P3\n", buffer);
return 0;
}
fscanf(f, "%u", &data->width);
fscanf(f, "%u", &data->height);
fscanf(f, "%u", &max_value);
assert(max_value==255);
init_image(data, data->width, data->height);
for (i = 0; i < data->width * data->height; i++) {
fscanf(f, "%hhu", &(data->r[i]));
fscanf(f, "%hhu", &(data->g[i]));
fscanf(f, "%hhu", &(data->b[i]));
}
fclose(f);
printf("Read %zux%zu pixels from %s.\n", data->width, data->height, filename);
}
int write_image(const char *filename, image *data) {
FILE *f = fopen(filename, "w");
size_t i;
fprintf(f, "P3\n%zu %zu\n255\n", data->width, data->height);
for (i = 0; i < data->width * data->height; i++) {
fprintf(f, "%hhu %hhu %hhu ", data->r[i], data->g[i], data->b[i]);
}
fclose(f);
}
unsigned char average(unsigned char *data, size_t data_len) {
size_t i;
size_t j;
size_t hist[256];
for (i = 0; i < 256; i++) hist[i] = 0;
for (i = 0; i < data_len; i++) hist[data[i]]++;
j = 0;
for (i = 0; i < 256; i++) {
j += hist[i];
if (j >= data_len / 2) return i;
}
return 255;
}
void set_pixel(image *data, size_t x, size_t y, unsigned char r, unsigned char g, unsigned char b) {
data->r[x + data->width * y] = r;
data->g[x + data->width * y] = g;
data->b[x + data->width * y] = b;
}
color get_pixel(image *data, size_t x, size_t y) {
color ret;
ret.r = data->r[x + data->width * y];
ret.g = data->g[x + data->width * y];
ret.b = data->b[x + data->width * y];
return ret;
}
void fill(image *data, unsigned char r, unsigned char g, unsigned char b) {
size_t i;
for (i = 0; i < data->width * data->height; i++) {
data->r[i] = r;
data->g[i] = g;
data->b[i] = b;
}
}
void line(image *data, size_t x1, size_t y1, size_t x2, size_t y2, unsigned char r, unsigned char g, unsigned char b) {
size_t x, y, t, pdx, pdy, ddx, ddy, es, el;
int dx, dy, incx, incy, err;
dx=x2-x1;
dy=y2-y1;
incx=SIGN(dx);
incy=SIGN(dy);
if(dx<0) dx=-dx;
if(dy<0) dy=-dy;
if (dx>dy) {
pdx=incx;
pdy=0;
ddx=incx;
ddy=incy;
es=dy;
el=dx;
} else {
pdx=0;
pdy=incy;
ddx=incx;
ddy=incy;
es=dx;
el=dy;
}
x=x1;
y=y1;
err=el/2;
set_pixel(data, x, y, r, g, b);
for(t=0; t<el; t++) {
err -= es;
if(err<0) {
err+=el;
x+=ddx;
y+=ddy;
} else {
x+=pdx;
y+=pdy;
}
set_pixel(data, x, y, r, g, b);
}
}
color average_line(image *data, size_t x1, size_t y1, size_t x2, size_t y2) {
size_t x, y, t, pdx, pdy, ddx, ddy, es, el;
int dx, dy, incx, incy, err;
color ret;
color px;
size_t i;
size_t j;
size_t hist_r[256];
size_t hist_g[256];
size_t hist_b[256];
size_t data_len = 0;
for (i = 0; i < 256; i++) {
hist_r[i] = 0;
hist_g[i] = 0;
hist_b[i] = 0;
}
dx=x2-x1;
dy=y2-y1;
incx=SIGN(dx);
incy=SIGN(dy);
if(dx<0) dx=-dx;
if(dy<0) dy=-dy;
if (dx>dy) {
pdx=incx;
pdy=0;
ddx=incx;
ddy=incy;
es=dy;
el=dx;
} else {
pdx=0;
pdy=incy;
ddx=incx;
ddy=incy;
es=dx;
el=dy;
}
x=x1;
y=y1;
err=el/2;
px = get_pixel(data, x, y);
hist_r[px.r]++;
hist_g[px.g]++;
hist_b[px.b]++;
data_len++;
for(t=0; t<el; t++) {
err -= es;
if(err<0) {
err+=el;
x+=ddx;
y+=ddy;
} else {
x+=pdx;
y+=pdy;
}
px = get_pixel(data, x, y);
hist_r[px.r]++;
hist_g[px.g]++;
hist_b[px.b]++;
data_len++;
}
j = 0;
for (i = 0; i < 256; i++) {
j += hist_r[i];
if (j >= data_len / 2) {
ret.r = i;
break;
}
}
j = 0;
for (i = 0; i < 256; i++) {
j += hist_g[i];
if (j >= data_len / 2) {
ret.g = i;
break;
}
}
j = 0;
for (i = 0; i < 256; i++) {
j += hist_b[i];
if (j >= data_len / 2) {
ret.b = i;
break;
}
}
return ret;
}
void lines(image *source, image *dest, size_t L, float m, float M) {
size_t i, j;
float dx;
float mx, my;
float mm = MAX(MIN(source->width * source->height / L, M), m);
unsigned char av_r = average(source->r, source->width * source->height);
unsigned char av_g = average(source->g, source->width * source->height);
unsigned char av_b = average(source->b, source->width * source->height);
fill(dest, av_r, av_g, av_b);
dx = (float)source->width / L;
mx = 0;
my = mm / 2;
for (i = 0; i < L; i++) {
color avg;
mx += dx;
my += (source->height - mm) / 8;
if (my + mm / 2 > source->height) {
my = mm / 2 + ((size_t)(my + mm / 2) % (size_t)(source->height - mm));
}
avg = average_line(source, mx, my - mm / 2, mx, my + mm / 2);
line(dest, mx, my - mm / 2, mx, my + mm / 2, avg.r, avg.g, avg.b);
}
}
int main(int argc, char *argv[]) {
image source;
image dest;
size_t L;
float m;
float M;
load_image(argv[1], &source);
L = atol(argv[2]);
m = atof(argv[3]);
M = atof(argv[4]);
init_image(&dest, source.width, source.height);
lines(&source, &dest, L, m, M);
write_image(argv[5], &dest);
}
L = 5000、m = 10、M = 50
L = 5000、m = 10、M = 50
L = 100000、m = 10、M = 50