45 #define DEFAULT_ALIGNMENT_U8 96 49 uint8_t *buf = calloc(height*stride,
sizeof(uint8_t));
52 image_u8_t tmp = { .
width = width, .height = height, .stride = stride, .buf = buf };
68 if ((stride % alignment) != 0)
69 stride += alignment - (stride % alignment);
76 uint8_t *buf = malloc(in->
height*in->
stride*
sizeof(uint8_t));
115 if (pnm->
max == 255) {
116 for (
int y = 0; y < im->
height; y++)
118 }
else if (pnm->
max == 65535) {
119 for (
int y = 0; y < im->
height; y++)
120 for (
int x = 0; x < im->
width; x++)
132 if (pnm->
max == 255) {
134 for (
int y = 0; y < im->
height; y++) {
135 for (
int x = 0; x < im->
width; x++) {
136 uint8_t gray = (pnm->
buf[y*im->
width*3 + 3*x+0] +
145 }
else if (pnm->
max == 65535) {
146 for (
int y = 0; y < im->
height; y++) {
147 for (
int x = 0; x < im->
width; x++) {
148 int r = pnm->
buf[6*(y*im->
width + x) + 0];
149 int g = pnm->
buf[6*(y*im->
width + x) + 2];
150 int b = pnm->
buf[6*(y*im->
width + x) + 4];
152 im->
buf[y*im->
stride + x] = (r + g + g + b) / 4;
168 int pbmstride = (im->
width + 7) / 8;
170 for (
int y = 0; y < im->
height; y++) {
171 for (
int x = 0; x < im->
width; x++) {
172 int byteidx = y * pbmstride + x / 8;
173 int bitidx = 7 - (x & 7);
176 if ((pnm->
buf[byteidx] >> bitidx) & 1)
194 for (
int y = 0; y < fim->
height; y++) {
195 for (
int x = 0; x < fim->
width; x++) {
197 im->
buf[y*im->
stride + x] = (int) (255 * v);
207 FILE *f = fopen(path,
"wb");
216 fprintf(f,
"P5\n%d %d\n255\n", im->
width, im->
height);
218 for (
int y = 0; y < im->
height; y++) {
236 for (
int y = y0-r; y <= y0+r; y++) {
237 for (
int x = x0-r; x <= x0+r; x++) {
238 float d = (x-x0)*(x-x0) + (y-y0)*(y-y0);
242 if (x >= 0 && x < im->width && y >= 0 && y < im->height) {
243 int idx = y*im->
stride + x;
257 for (
int y = y0-r1; y <= y0+r1; y++) {
258 for (
int x = x0-r1; x <= x0+r1; x++) {
259 float d = (x-x0)*(x-x0) + (y-y0)*(y-y0);
260 if (d < r0 || d > r1)
263 int idx = y*im->
stride + x;
272 double dist = sqrtf((y1-y0)*(y1-y0) + (x1-x0)*(x1-x0));
273 double delta = 0.5 / dist;
276 for (
float f = 0; f <= 1; f += delta) {
277 int x = ((int) (x1 + (x0 - x1) * f));
278 int y = ((int) (y1 + (y0 - y1) * f));
280 if (x < 0 || y < 0 || x >= im->
width || y >= im->
height)
283 int idx = y*im->
stride + x;
295 for (
int y = 0; y < im->
height; y++) {
296 for (
int x = 0; x < im->
width; x++) {
302 static void convolve(
const uint8_t *x, uint8_t *y,
int sz,
const uint8_t *k,
int ksz)
306 for (
int i = 0; i < ksz/2 && i < sz; i++)
309 for (
int i = 0; i < sz - ksz; i++) {
312 for (
int j = 0; j < ksz; j++)
315 y[ksz/2 + i] = acc >> 8;
318 for (
int i = sz - ksz + ksz/2; i < sz; i++)
324 assert((ksz & 1) == 1);
326 for (
int y = 0; y < im->
height; y++) {
334 for (
int x = 0; x < im->
width; x++) {
338 for (
int y = 0; y < im->
height; y++)
343 for (
int y = 0; y < im->
height; y++)
353 assert((ksz & 1) == 1);
360 for (
int i = 0; i < ksz; i++) {
362 double v = exp(-.5*
sq(x / sigma));
368 for (
int i = 0; i < ksz; i++)
371 for (
int i = 0; i < ksz; i++)
375 for (
int i = 0; i < ksz; i++)
379 for (
int i = 0; i < ksz; i++)
380 printf(
"%d %15f %5d\n", i, dk[i], k[i]);
391 float c = cos(rad), s = sin(rad);
393 float p[][2] = { { 0, 0}, { iwidth, 0 }, { iwidth, iheight }, { 0, iheight} };
395 float xmin = HUGE_VALF, xmax = -HUGE_VALF, ymin = HUGE_VALF, ymax = -HUGE_VALF;
396 float icx = iwidth / 2.0, icy = iheight / 2.0;
398 for (
int i = 0; i < 4; i++) {
399 float px = p[i][0] - icx;
400 float py = p[i][1] - icy;
402 float nx = px*c - py*s;
403 float ny = px*s + py*c;
405 xmin = fmin(xmin, nx);
406 xmax = fmax(xmax, nx);
407 ymin = fmin(ymin, ny);
408 ymax = fmax(ymax, ny);
411 int owidth = ceil(xmax-xmin), oheight = ceil(ymax - ymin);
415 for (
int oy = 0; oy < oheight; oy++) {
416 for (
int ox = 0; ox < owidth; ox++) {
419 float sx = ox - owidth / 2.0 + .5;
420 float sy = oy - oheight / 2.0 + .5;
423 int ix = floor(sx*c + sy*s + icx);
424 int iy = floor(-sx*s + sy*c + icy);
426 if (ix >= 0 && iy >= 0 && ix < iwidth && iy < iheight)
437 #include <arm_neon.h> 439 void neon_decimate2(uint8_t * __restrict dest,
int destwidth,
int destheight,
int deststride,
440 uint8_t * __restrict src,
int srcwidth,
int srcheight,
int srcstride)
442 for (
int y = 0; y < destheight; y++) {
443 for (
int x = 0; x < destwidth; x+=8) {
444 uint8x16x2_t row0 = vld2q_u8(src + 2*x);
445 uint8x16x2_t row1 = vld2q_u8(src + 2*x + srcstride);
446 uint8x16_t sum0 = vhaddq_u8(row0.val[0], row1.val[1]);
447 uint8x16_t sum1 = vhaddq_u8(row1.val[0], row0.val[1]);
448 uint8x16_t sum = vhaddq_u8(sum0, sum1);
449 vst1q_u8(dest + x, sum);
456 void neon_decimate3(uint8_t * __restrict dest,
int destwidth,
int destheight,
int deststride,
457 uint8_t * __restrict src,
int srcwidth,
int srcheight,
int srcstride)
459 for (
int y = 0; y < destheight; y++) {
460 for (
int x = 0; x < destwidth; x+=8) {
461 uint8x16x3_t row0 = vld3q_u8(src + 3*x);
462 uint8x16x3_t row1 = vld3q_u8(src + 3*x + srcstride);
463 uint8x16x3_t row2 = vld3q_u8(src + 3*x + 2*srcstride);
465 uint8x16_t sum0 = vhaddq_u8(row0.val[0], row0.val[1]);
466 uint8x16_t sum1 = vhaddq_u8(row0.val[2], row1.val[0]);
467 uint8x16_t sum2 = vhaddq_u8(row1.val[1], row1.val[2]);
468 uint8x16_t sum3 = vhaddq_u8(row2.val[0], row2.val[1]);
470 uint8x16_t suma = vhaddq_u8(sum0, sum1);
471 uint8x16_t sumb = vhaddq_u8(sum2, sum3);
472 uint8x16_t sum = vhaddq_u8(suma, sumb);
474 vst1q_u8(dest + x, sum);
481 void neon_decimate4(uint8_t * __restrict dest,
int destwidth,
int destheight,
int deststride,
482 uint8_t * __restrict src,
int srcwidth,
int srcheight,
int srcstride)
484 for (
int y = 0; y < destheight; y++) {
485 for (
int x = 0; x < destwidth; x+=8) {
486 uint8x16x4_t row0 = vld4q_u8(src + 4*x);
487 uint8x16x4_t row1 = vld4q_u8(src + 4*x + srcstride);
488 uint8x16x4_t row2 = vld4q_u8(src + 4*x + 2*srcstride);
489 uint8x16x4_t row3 = vld4q_u8(src + 4*x + 3*srcstride);
491 uint8x16_t sum0, sum1;
493 sum0 = vhaddq_u8(row0.val[0], row0.val[3]);
494 sum1 = vhaddq_u8(row0.val[2], row0.val[1]);
495 uint8x16_t suma = vhaddq_u8(sum0, sum1);
497 sum0 = vhaddq_u8(row1.val[0], row1.val[3]);
498 sum1 = vhaddq_u8(row1.val[2], row1.val[1]);
499 uint8x16_t sumb = vhaddq_u8(sum0, sum1);
501 sum0 = vhaddq_u8(row2.val[0], row2.val[3]);
502 sum1 = vhaddq_u8(row2.val[2], row2.val[1]);
503 uint8x16_t sumc = vhaddq_u8(sum0, sum1);
505 sum0 = vhaddq_u8(row3.val[0], row3.val[3]);
506 sum1 = vhaddq_u8(row3.val[2], row3.val[1]);
507 uint8x16_t sumd = vhaddq_u8(sum0, sum1);
509 uint8x16_t sumx = vhaddq_u8(suma, sumd);
510 uint8x16_t sumy = vhaddq_u8(sumc, sumb);
512 uint8x16_t sum = vhaddq_u8(sumx, sumy);
514 vst1q_u8(dest + x, sum);
527 if (ffactor == 1.5) {
528 int swidth = width / 3 * 2, sheight = height / 3 * 2;
533 while (sy < sheight) {
535 while (sx < swidth) {
540 uint8_t a = im->
buf[(y+0)*im->
stride + (x+0)];
541 uint8_t b = im->
buf[(y+0)*im->
stride + (x+1)];
542 uint8_t c = im->
buf[(y+0)*im->
stride + (x+2)];
544 uint8_t d = im->
buf[(y+1)*im->
stride + (x+0)];
545 uint8_t e = im->
buf[(y+1)*im->
stride + (x+1)];
546 uint8_t f = im->
buf[(y+1)*im->
stride + (x+2)];
548 uint8_t g = im->
buf[(y+2)*im->
stride + (x+0)];
549 uint8_t h = im->
buf[(y+2)*im->
stride + (x+1)];
550 uint8_t i = im->
buf[(y+2)*im->
stride + (x+2)];
552 decim->
buf[(sy+0)*decim->
stride + (sx + 0)] =
554 decim->
buf[(sy+0)*decim->
stride + (sx + 1)] =
557 decim->
buf[(sy+1)*decim->
stride + (sx + 0)] =
559 decim->
buf[(sy+1)*decim->
stride + (sx + 1)] =
573 int factor = (int) ffactor;
575 int swidth = width / factor, sheight = height / factor;
584 }
else if (factor == 3) {
588 }
else if (factor == 4) {
596 for (
int sy = 0; sy < sheight; sy++) {
597 int sidx = sy * decim->
stride;
598 int idx = (sy*2)*im->
stride;
600 for (
int sx = 0; sx < swidth; sx++) {
601 uint32_t v = im->
buf[idx] + im->
buf[idx+1] +
603 decim->
buf[sidx] = (v>>2);
608 }
else if (factor == 3) {
609 for (
int sy = 0; sy < sheight; sy++) {
610 int sidx = sy * decim->
stride;
611 int idx = (sy*3)*im->
stride;
613 for (
int sx = 0; sx < swidth; sx++) {
614 uint32_t v = im->
buf[idx] + im->
buf[idx+1] + im->
buf[idx+2] +
619 decim->
buf[sidx] = (v>>3);
624 }
else if (factor == 4) {
625 for (
int sy = 0; sy < sheight; sy++) {
626 int sidx = sy * decim->
stride;
627 int idx = (sy*4)*im->
stride;
629 for (
int sx = 0; sx < swidth; sx++) {
630 uint32_t v = im->
buf[idx] + im->
buf[idx+1] + im->
buf[idx+2] + im->
buf[idx+3] +
634 decim->
buf[sidx] = (v>>4);
641 uint32_t row[swidth];
643 for (
int y = 0; y < height; y+= factor) {
644 memset(row, 0,
sizeof(row));
646 for (
int dy = 0; dy < factor; dy++) {
647 for (
int x = 0; x < width; x++) {
648 row[x/factor] += im->
buf[(y+dy)*im->
stride + x];
652 for (
int x = 0; x < swidth; x++)
653 decim->
buf[(y/factor)*decim->
stride + x] = row[x] /
sq(factor);
665 float max_dist = sqrt(max_dist2);
668 double theta = atan2(xy1[1]-xy0[1], xy1[0]-xy0[0]);
669 double v = sin(theta), u = cos(theta);
671 int ix0 =
iclamp(fmin(xy0[0], xy1[0]) - max_dist, 0, im->
width-1);
672 int ix1 =
iclamp(fmax(xy0[0], xy1[0]) + max_dist, 0, im->
width-1);
674 int iy0 =
iclamp(fmin(xy0[1], xy1[1]) - max_dist, 0, im->
height-1);
675 int iy1 =
iclamp(fmax(xy0[1], xy1[1]) + max_dist, 0, im->
height-1);
679 float xy1_line_coord = (xy1[0]-xy0[0])*u + (xy1[1]-xy0[1])*v;
681 float min_line_coord = fmin(0, xy1_line_coord);
682 float max_line_coord = fmax(0, xy1_line_coord);
684 for (
int iy = iy0; iy <= iy1; iy++) {
687 for (
int ix = ix0; ix <= ix1; ix++) {
691 float line_coord = (x - xy0[0])*u + (y - xy0[1])*v;
694 if (line_coord < min_line_coord)
695 line_coord = min_line_coord;
696 else if (line_coord > max_line_coord)
697 line_coord = max_line_coord;
699 float px = xy0[0] + line_coord*u;
700 float py = xy0[1] + line_coord*v;
702 double dist2 = (x-px)*(x-px) + (y-py)*(y-py);
705 int idx = dist2 * lut->
scale;
709 uint8_t lut_value = lut->
values[idx];
710 uint8_t old_value = im->
buf[iy*im->
stride + ix];
711 if (lut_value > old_value)
static int iclamp(int v, int minv, int maxv)
void image_u8_draw_circle(image_u8_t *im, float x0, float y0, float r, int v)
static void convolve(const uint8_t *x, uint8_t *y, int sz, const uint8_t *k, int ksz)
void image_u8_darken(image_u8_t *im)
image_u8_t * image_u8_decimate(image_u8_t *im, float ffactor)
#define PNM_FORMAT_BINARY
image_u8_t * image_u8_create_from_f32(image_f32_t *fim)
image_u8_t * image_u8_create_stride(unsigned int width, unsigned int height, unsigned int stride)
image_u8_t * image_u8_rotate(const image_u8_t *in, double rad, uint8_t pad)
image_u8_t * image_u8_copy(const image_u8_t *in)
image_u8_t * image_u8_create_alignment(unsigned int width, unsigned int height, unsigned int alignment)
int image_u8_write_pnm(const image_u8_t *im, const char *path)
static double sq(double v)
image_u8_t * image_u8_create_from_pnm(const char *path)
void image_u8_gaussian_blur(image_u8_t *im, double sigma, int ksz)
void image_u8_convolve_2D(image_u8_t *im, const uint8_t *k, int ksz)
void image_u8_draw_annulus(image_u8_t *im, float x0, float y0, float r0, float r1, int v)
#define DEFAULT_ALIGNMENT_U8
image_u8_t * image_u8_create(unsigned int width, unsigned int height)
void image_u8_destroy(image_u8_t *im)
image_u8_t * image_u8_create_from_pnm_alignment(const char *path, int alignment)
pnm_t * pnm_create_from_file(const char *path)
void pnm_destroy(pnm_t *pnm)
static TTYPENAME *TFN() copy(TTYPENAME *hash)
void image_u8_fill_line_max(image_u8_t *im, const image_u8_lut_t *lut, const float *xy0, const float *xy1)
void image_u8_draw_line(image_u8_t *im, float x0, float y0, float x1, float y1, int v, int width)