image_u8.c
Go to the documentation of this file.
1 /* Copyright (C) 2013-2016, The Regents of The University of Michigan.
2 All rights reserved.
3 
4 This software was developed in the APRIL Robotics Lab under the
5 direction of Edwin Olson, ebolson@umich.edu. This software may be
6 available under alternative licensing terms; contact the address above.
7 
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 
11 1. Redistributions of source code must retain the above copyright notice, this
12  list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 The views and conclusions contained in the software and documentation are those
29 of the authors and should not be interpreted as representing official policies,
30 either expressed or implied, of the Regents of The University of Michigan.
31 */
32 
33 #include <assert.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <math.h>
38 
39 #include "common/image_u8.h"
40 #include "common/pnm.h"
41 #include "common/math_util.h"
42 
43 // least common multiple of 64 (sandy bridge cache line) and 24 (stride
44 // needed for RGB in 8-wide vector processing)
45 #define DEFAULT_ALIGNMENT_U8 96
46 
47 image_u8_t *image_u8_create_stride(unsigned int width, unsigned int height, unsigned int stride)
48 {
49  uint8_t *buf = calloc(height*stride, sizeof(uint8_t));
50 
51  // const initializer
52  image_u8_t tmp = { .width = width, .height = height, .stride = stride, .buf = buf };
53 
54  image_u8_t *im = calloc(1, sizeof(image_u8_t));
55  memcpy(im, &tmp, sizeof(image_u8_t));
56  return im;
57 }
58 
59 image_u8_t *image_u8_create(unsigned int width, unsigned int height)
60 {
61  return image_u8_create_alignment(width, height, DEFAULT_ALIGNMENT_U8);
62 }
63 
64 image_u8_t *image_u8_create_alignment(unsigned int width, unsigned int height, unsigned int alignment)
65 {
66  int stride = width;
67 
68  if ((stride % alignment) != 0)
69  stride += alignment - (stride % alignment);
70 
71  return image_u8_create_stride(width, height, stride);
72 }
73 
75 {
76  uint8_t *buf = malloc(in->height*in->stride*sizeof(uint8_t));
77  memcpy(buf, in->buf, in->height*in->stride*sizeof(uint8_t));
78 
79  // const initializer
80  image_u8_t tmp = { .width = in->width, .height = in->height, .stride = in->stride, .buf = buf };
81 
82  image_u8_t *copy = calloc(1, sizeof(image_u8_t));
83  memcpy(copy, &tmp, sizeof(image_u8_t));
84  return copy;
85 }
86 
88 {
89  if (!im)
90  return;
91 
92  free(im->buf);
93  free(im);
94 }
95 
97 // PNM file i/o
99 {
101 }
102 
103 image_u8_t *image_u8_create_from_pnm_alignment(const char *path, int alignment)
104 {
105  pnm_t *pnm = pnm_create_from_file(path);
106  if (pnm == NULL)
107  return NULL;
108 
109  image_u8_t *im = NULL;
110 
111  switch (pnm->format) {
112  case PNM_FORMAT_GRAY: {
113  im = image_u8_create_alignment(pnm->width, pnm->height, alignment);
114 
115  if (pnm->max == 255) {
116  for (int y = 0; y < im->height; y++)
117  memcpy(&im->buf[y*im->stride], &pnm->buf[y*im->width], im->width);
118  } else if (pnm->max == 65535) {
119  for (int y = 0; y < im->height; y++)
120  for (int x = 0; x < im->width; x++)
121  im->buf[y*im->stride + x] = pnm->buf[2*(y*im->width + x)];
122  } else {
123  assert(0);
124  }
125 
126  break;
127  }
128 
129  case PNM_FORMAT_RGB: {
130  im = image_u8_create_alignment(pnm->width, pnm->height, alignment);
131 
132  if (pnm->max == 255) {
133  // Gray conversion for RGB is gray = (r + g + g + b)/4
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] + // r
137  pnm->buf[y*im->width*3 + 3*x+1] + // g
138  pnm->buf[y*im->width*3 + 3*x+1] + // g
139  pnm->buf[y*im->width*3 + 3*x+2]) // b
140  / 4;
141 
142  im->buf[y*im->stride + x] = gray;
143  }
144  }
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];
151 
152  im->buf[y*im->stride + x] = (r + g + g + b) / 4;
153  }
154  }
155  } else {
156  assert(0);
157  }
158 
159  break;
160  }
161 
162  case PNM_FORMAT_BINARY: {
163  im = image_u8_create_alignment(pnm->width, pnm->height, alignment);
164 
165  // image is padded to be whole bytes on each row.
166 
167  // how many bytes per row on the input?
168  int pbmstride = (im->width + 7) / 8;
169 
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);
174 
175  // ack, black is one according to pbm docs!
176  if ((pnm->buf[byteidx] >> bitidx) & 1)
177  im->buf[y*im->stride + x] = 0;
178  else
179  im->buf[y*im->stride + x] = 255;
180  }
181  }
182  break;
183  }
184  }
185 
186  pnm_destroy(pnm);
187  return im;
188 }
189 
191 {
192  image_u8_t *im = image_u8_create(fim->width, fim->height);
193 
194  for (int y = 0; y < fim->height; y++) {
195  for (int x = 0; x < fim->width; x++) {
196  float v = fim->buf[y*fim->stride + x];
197  im->buf[y*im->stride + x] = (int) (255 * v);
198  }
199  }
200 
201  return im;
202 }
203 
204 
205 int image_u8_write_pnm(const image_u8_t *im, const char *path)
206 {
207  FILE *f = fopen(path, "wb");
208  int res = 0;
209 
210  if (f == NULL) {
211  res = -1;
212  goto finish;
213  }
214 
215  // Only outputs to grayscale
216  fprintf(f, "P5\n%d %d\n255\n", im->width, im->height);
217 
218  for (int y = 0; y < im->height; y++) {
219  if (im->width != fwrite(&im->buf[y*im->stride], 1, im->width, f)) {
220  res = -2;
221  goto finish;
222  }
223  }
224 
225  finish:
226  if (f != NULL)
227  fclose(f);
228 
229  return res;
230 }
231 
232 void image_u8_draw_circle(image_u8_t *im, float x0, float y0, float r, int v)
233 {
234  r = r*r;
235 
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);
239  if (d > r)
240  continue;
241 
242  if (x >= 0 && x < im->width && y >= 0 && y < im->height) {
243  int idx = y*im->stride + x;
244  im->buf[idx] = v;
245  }
246  }
247  }
248 }
249 
250 void image_u8_draw_annulus(image_u8_t *im, float x0, float y0, float r0, float r1, int v)
251 {
252  r0 = r0*r0;
253  r1 = r1*r1;
254 
255  assert(r0 < r1);
256 
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)
261  continue;
262 
263  int idx = y*im->stride + x;
264  im->buf[idx] = v;
265  }
266  }
267 }
268 
269 // only widths 1 and 3 supported (and 3 only badly)
270 void image_u8_draw_line(image_u8_t *im, float x0, float y0, float x1, float y1, int v, int width)
271 {
272  double dist = sqrtf((y1-y0)*(y1-y0) + (x1-x0)*(x1-x0));
273  double delta = 0.5 / dist;
274 
275  // terrible line drawing code
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));
279 
280  if (x < 0 || y < 0 || x >= im->width || y >= im->height)
281  continue;
282 
283  int idx = y*im->stride + x;
284  im->buf[idx] = v;
285  if (width > 1) {
286  im->buf[idx+1] = v;
287  im->buf[idx+im->stride] = v;
288  im->buf[idx+1+im->stride] = v;
289  }
290  }
291 }
292 
294 {
295  for (int y = 0; y < im->height; y++) {
296  for (int x = 0; x < im->width; x++) {
297  im->buf[im->stride*y+x] /= 2;
298  }
299  }
300 }
301 
302 static void convolve(const uint8_t *x, uint8_t *y, int sz, const uint8_t *k, int ksz)
303 {
304  assert((ksz&1)==1);
305 
306  for (int i = 0; i < ksz/2 && i < sz; i++)
307  y[i] = x[i];
308 
309  for (int i = 0; i < sz - ksz; i++) {
310  uint32_t acc = 0;
311 
312  for (int j = 0; j < ksz; j++)
313  acc += k[j]*x[i+j];
314 
315  y[ksz/2 + i] = acc >> 8;
316  }
317 
318  for (int i = sz - ksz + ksz/2; i < sz; i++)
319  y[i] = x[i];
320 }
321 
322 void image_u8_convolve_2D(image_u8_t *im, const uint8_t *k, int ksz)
323 {
324  assert((ksz & 1) == 1); // ksz must be odd.
325 
326  for (int y = 0; y < im->height; y++) {
327 
328  uint8_t x[im->stride];
329  memcpy(x, &im->buf[y*im->stride], im->stride);
330 
331  convolve(x, &im->buf[y*im->stride], im->width, k, ksz);
332  }
333 
334  for (int x = 0; x < im->width; x++) {
335  uint8_t xb[im->height];
336  uint8_t yb[im->height];
337 
338  for (int y = 0; y < im->height; y++)
339  xb[y] = im->buf[y*im->stride + x];
340 
341  convolve(xb, yb, im->height, k, ksz);
342 
343  for (int y = 0; y < im->height; y++)
344  im->buf[y*im->stride + x] = yb[y];
345  }
346 }
347 
348 void image_u8_gaussian_blur(image_u8_t *im, double sigma, int ksz)
349 {
350  if (sigma == 0)
351  return;
352 
353  assert((ksz & 1) == 1); // ksz must be odd.
354 
355  // build the kernel.
356  double dk[ksz];
357 
358  // for kernel of length 5:
359  // dk[0] = f(-2), dk[1] = f(-1), dk[2] = f(0), dk[3] = f(1), dk[4] = f(2)
360  for (int i = 0; i < ksz; i++) {
361  int x = -ksz/2 + i;
362  double v = exp(-.5*sq(x / sigma));
363  dk[i] = v;
364  }
365 
366  // normalize
367  double acc = 0;
368  for (int i = 0; i < ksz; i++)
369  acc += dk[i];
370 
371  for (int i = 0; i < ksz; i++)
372  dk[i] /= acc;
373 
374  uint8_t k[ksz];
375  for (int i = 0; i < ksz; i++)
376  k[i] = dk[i]*255;
377 
378  if (0) {
379  for (int i = 0; i < ksz; i++)
380  printf("%d %15f %5d\n", i, dk[i], k[i]);
381  }
382 
383  image_u8_convolve_2D(im, k, ksz);
384 }
385 
386 image_u8_t *image_u8_rotate(const image_u8_t *in, double rad, uint8_t pad)
387 {
388  int iwidth = in->width, iheight = in->height;
389  rad = -rad; // interpret y as being "down"
390 
391  float c = cos(rad), s = sin(rad);
392 
393  float p[][2] = { { 0, 0}, { iwidth, 0 }, { iwidth, iheight }, { 0, iheight} };
394 
395  float xmin = HUGE_VALF, xmax = -HUGE_VALF, ymin = HUGE_VALF, ymax = -HUGE_VALF;
396  float icx = iwidth / 2.0, icy = iheight / 2.0;
397 
398  for (int i = 0; i < 4; i++) {
399  float px = p[i][0] - icx;
400  float py = p[i][1] - icy;
401 
402  float nx = px*c - py*s;
403  float ny = px*s + py*c;
404 
405  xmin = fmin(xmin, nx);
406  xmax = fmax(xmax, nx);
407  ymin = fmin(ymin, ny);
408  ymax = fmax(ymax, ny);
409  }
410 
411  int owidth = ceil(xmax-xmin), oheight = ceil(ymax - ymin);
412  image_u8_t *out = image_u8_create(owidth, oheight);
413 
414  // iterate over output pixels.
415  for (int oy = 0; oy < oheight; oy++) {
416  for (int ox = 0; ox < owidth; ox++) {
417  // work backwards from destination coordinates...
418  // sample pixel centers.
419  float sx = ox - owidth / 2.0 + .5;
420  float sy = oy - oheight / 2.0 + .5;
421 
422  // project into input-image space
423  int ix = floor(sx*c + sy*s + icx);
424  int iy = floor(-sx*s + sy*c + icy);
425 
426  if (ix >= 0 && iy >= 0 && ix < iwidth && iy < iheight)
427  out->buf[oy*out->stride+ox] = in->buf[iy*in->stride + ix];
428  else
429  out->buf[oy*out->stride+ox] = pad;
430  }
431  }
432 
433  return out;
434 }
435 
436 #ifdef __ARM_NEON__
437 #include <arm_neon.h>
438 
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)
441 {
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);
450  }
451  src += 2*srcstride;
452  dest += deststride;
453  }
454 }
455 
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)
458 {
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);
464 
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]);
469 
470  uint8x16_t suma = vhaddq_u8(sum0, sum1);
471  uint8x16_t sumb = vhaddq_u8(sum2, sum3);
472  uint8x16_t sum = vhaddq_u8(suma, sumb);
473 
474  vst1q_u8(dest + x, sum);
475  }
476  src += 3*srcstride;
477  dest += deststride;
478  }
479 }
480 
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)
483 {
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);
490 
491  uint8x16_t sum0, sum1;
492 
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);
496 
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);
500 
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);
504 
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);
508 
509  uint8x16_t sumx = vhaddq_u8(suma, sumd);
510  uint8x16_t sumy = vhaddq_u8(sumc, sumb);
511 
512  uint8x16_t sum = vhaddq_u8(sumx, sumy);
513 
514  vst1q_u8(dest + x, sum);
515  }
516  src += 4*srcstride;
517  dest += deststride;
518  }
519 }
520 
521 #endif
522 
524 {
525  int width = im->width, height = im->height;
526 
527  if (ffactor == 1.5) {
528  int swidth = width / 3 * 2, sheight = height / 3 * 2;
529 
530  image_u8_t *decim = image_u8_create(swidth, sheight);
531 
532  int y = 0, sy = 0;
533  while (sy < sheight) {
534  int x = 0, sx = 0;
535  while (sx < swidth) {
536 
537  // a b c
538  // d e f
539  // g h i
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)];
543 
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)];
547 
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)];
551 
552  decim->buf[(sy+0)*decim->stride + (sx + 0)] =
553  (4*a+2*b+2*d+e)/9;
554  decim->buf[(sy+0)*decim->stride + (sx + 1)] =
555  (4*c+2*b+2*f+e)/9;
556 
557  decim->buf[(sy+1)*decim->stride + (sx + 0)] =
558  (4*g+2*d+2*h+e)/9;
559  decim->buf[(sy+1)*decim->stride + (sx + 1)] =
560  (4*i+2*f+2*h+e)/9;
561 
562  x += 3;
563  sx += 2;
564  }
565 
566  y += 3;
567  sy += 2;
568  }
569 
570  return decim;
571  }
572 
573  int factor = (int) ffactor;
574 
575  int swidth = width / factor, sheight = height / factor;
576 
577  image_u8_t *decim = image_u8_create(swidth, sheight);
578 
579 #ifdef __ARM_NEON__
580  if (factor == 2) {
581  neon_decimate2(decim->buf, decim->width, decim->height, decim->stride,
582  im->buf, im->width, im->height, im->stride);
583  return decim;
584  } else if (factor == 3) {
585  neon_decimate3(decim->buf, decim->width, decim->height, decim->stride,
586  im->buf, im->width, im->height, im->stride);
587  return decim;
588  } else if (factor == 4) {
589  neon_decimate4(decim->buf, decim->width, decim->height, decim->stride,
590  im->buf, im->width, im->height, im->stride);
591  return decim;
592  }
593 #endif
594 
595  if (factor == 2) {
596  for (int sy = 0; sy < sheight; sy++) {
597  int sidx = sy * decim->stride;
598  int idx = (sy*2)*im->stride;
599 
600  for (int sx = 0; sx < swidth; sx++) {
601  uint32_t v = im->buf[idx] + im->buf[idx+1] +
602  im->buf[idx+im->stride] + im->buf[idx+im->stride + 1];
603  decim->buf[sidx] = (v>>2);
604  idx+=2;
605  sidx++;
606  }
607  }
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;
612 
613  for (int sx = 0; sx < swidth; sx++) {
614  uint32_t v = im->buf[idx] + im->buf[idx+1] + im->buf[idx+2] +
615  im->buf[idx+im->stride] + im->buf[idx+im->stride + 1] + im->buf[idx+im->stride + 2] +
616  im->buf[idx+2*im->stride] + im->buf[idx+2*im->stride + 1];
617  // + im->buf[idx+2*im->stride + 1];
618  // deliberately omit lower right corner so there are exactly 8 samples...
619  decim->buf[sidx] = (v>>3);
620  idx+=3;
621  sidx++;
622  }
623  }
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;
628 
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] +
631  im->buf[idx+im->stride] + im->buf[idx+im->stride + 1] + im->buf[idx+im->stride + 1] + im->buf[idx+im->stride + 2] +
632  im->buf[idx+2*im->stride] + im->buf[idx+2*im->stride + 1] + im->buf[idx+2*im->stride + 2] + im->buf[idx+2*im->stride + 3];
633 
634  decim->buf[sidx] = (v>>4);
635  idx+=4;
636  sidx++;
637  }
638  }
639  } else {
640  // XXX this isn't a very good decimation code.
641  uint32_t row[swidth];
642 
643  for (int y = 0; y < height; y+= factor) {
644  memset(row, 0, sizeof(row));
645 
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];
649  }
650  }
651 
652  for (int x = 0; x < swidth; x++)
653  decim->buf[(y/factor)*decim->stride + x] = row[x] / sq(factor);
654 
655  }
656  }
657 
658  return decim;
659 }
660 
661 void image_u8_fill_line_max(image_u8_t *im, const image_u8_lut_t *lut, const float *xy0, const float *xy1)
662 {
663  // what is the maximum distance that will result in drawing into our LUT?
664  float max_dist2 = (lut->nvalues-1)/lut->scale;
665  float max_dist = sqrt(max_dist2);
666 
667  // the orientation of the line
668  double theta = atan2(xy1[1]-xy0[1], xy1[0]-xy0[0]);
669  double v = sin(theta), u = cos(theta);
670 
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);
673 
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);
676 
677  // the line segment xy0---xy1 can be parameterized in terms of line coordinates.
678  // We fix xy0 to be at line coordinate 0.
679  float xy1_line_coord = (xy1[0]-xy0[0])*u + (xy1[1]-xy0[1])*v;
680 
681  float min_line_coord = fmin(0, xy1_line_coord);
682  float max_line_coord = fmax(0, xy1_line_coord);
683 
684  for (int iy = iy0; iy <= iy1; iy++) {
685  float y = iy+.5;
686 
687  for (int ix = ix0; ix <= ix1; ix++) {
688  float x = ix+.5;
689 
690  // compute line coordinate of this pixel.
691  float line_coord = (x - xy0[0])*u + (y - xy0[1])*v;
692 
693  // find point on line segment closest to our current pixel.
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;
698 
699  float px = xy0[0] + line_coord*u;
700  float py = xy0[1] + line_coord*v;
701 
702  double dist2 = (x-px)*(x-px) + (y-py)*(y-py);
703 
704  // not in our LUT?
705  int idx = dist2 * lut->scale;
706  if (idx >= lut->nvalues)
707  continue;
708 
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)
712  im->buf[iy*im->stride + ix] = lut_value;
713  }
714  }
715 }
int height
Definition: pnm.h:51
static int iclamp(int v, int minv, int maxv)
Definition: math_util.h:180
void image_u8_draw_circle(image_u8_t *im, float x0, float y0, float r, int v)
Definition: image_u8.c:232
static void convolve(const uint8_t *x, uint8_t *y, int sz, const uint8_t *k, int ksz)
Definition: image_u8.c:302
void image_u8_darken(image_u8_t *im)
Definition: image_u8.c:293
int format
Definition: pnm.h:52
image_u8_t * image_u8_decimate(image_u8_t *im, float ffactor)
Definition: image_u8.c:523
#define PNM_FORMAT_RGB
Definition: pnm.h:44
const int32_t height
Definition: image_types.h:44
#define PNM_FORMAT_BINARY
Definition: pnm.h:42
image_u8_t * image_u8_create_from_f32(image_f32_t *fim)
Definition: image_u8.c:190
uint8_t * buf
Definition: pnm.h:56
image_u8_t * image_u8_create_stride(unsigned int width, unsigned int height, unsigned int stride)
Definition: image_u8.c:47
image_u8_t * image_u8_rotate(const image_u8_t *in, double rad, uint8_t pad)
Definition: image_u8.c:386
float scale
Definition: image_u8.h:50
image_u8_t * image_u8_copy(const image_u8_t *in)
Definition: image_u8.c:74
const int32_t height
Definition: image_types.h:14
Definition: pnm.h:49
image_u8_t * image_u8_create_alignment(unsigned int width, unsigned int height, unsigned int alignment)
Definition: image_u8.c:64
const int32_t width
Definition: image_types.h:13
const int32_t stride
Definition: image_types.h:15
int width
Definition: pnm.h:51
int max
Definition: pnm.h:53
int image_u8_write_pnm(const image_u8_t *im, const char *path)
Definition: image_u8.c:205
static double sq(double v)
Definition: math_util.h:84
image_u8_t * image_u8_create_from_pnm(const char *path)
Definition: image_u8.c:98
void image_u8_gaussian_blur(image_u8_t *im, double sigma, int ksz)
Definition: image_u8.c:348
uint8_t * values
Definition: image_u8.h:53
void image_u8_convolve_2D(image_u8_t *im, const uint8_t *k, int ksz)
Definition: image_u8.c:322
void image_u8_draw_annulus(image_u8_t *im, float x0, float y0, float r0, float r1, int v)
Definition: image_u8.c:250
uint8_t * buf
Definition: image_types.h:17
#define DEFAULT_ALIGNMENT_U8
Definition: image_u8.c:45
image_u8_t * image_u8_create(unsigned int width, unsigned int height)
Definition: image_u8.c:59
void image_u8_destroy(image_u8_t *im)
Definition: image_u8.c:87
float * buf
Definition: image_types.h:47
int nvalues
Definition: image_u8.h:52
image_u8_t * image_u8_create_from_pnm_alignment(const char *path, int alignment)
Definition: image_u8.c:103
pnm_t * pnm_create_from_file(const char *path)
Definition: pnm.c:40
const int32_t stride
Definition: image_types.h:45
void pnm_destroy(pnm_t *pnm)
Definition: pnm.c:153
static TTYPENAME *TFN() copy(TTYPENAME *hash)
Definition: thash_impl.h:322
void image_u8_fill_line_max(image_u8_t *im, const image_u8_lut_t *lut, const float *xy0, const float *xy1)
Definition: image_u8.c:661
#define PNM_FORMAT_GRAY
Definition: pnm.h:43
const int32_t width
Definition: image_types.h:43
void image_u8_draw_line(image_u8_t *im, float x0, float y0, float x1, float y1, int v, int width)
Definition: image_u8.c:270


apriltags2
Author(s): Danylo Malyuta
autogenerated on Fri Oct 19 2018 04:02:32