image_u8x3.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 This software was developed in the APRIL Robotics Lab under the
4 direction of Edwin Olson, ebolson@umich.edu. This software may be
5 available under alternative licensing terms; contact the address above.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice, this
9  list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11  this list of conditions and the following disclaimer in the documentation
12  and/or other materials provided with the distribution.
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 The views and conclusions contained in the software and documentation are those
24 of the authors and should not be interpreted as representing official policies,
25 either expressed or implied, of the Regents of The University of Michigan.
26 */
27 
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33 
34 #include "math_util.h"
35 #include "pnm.h"
36 
37 #include "image_u8x3.h"
38 
39 // least common multiple of 64 (sandy bridge cache line) and 48 (stride needed
40 // for 16byte-wide RGB processing). (It's possible that 48 would be enough).
41 #define DEFAULT_ALIGNMENT_U8X3 192
42 
43 image_u8x3_t *image_u8x3_create(unsigned int width, unsigned int height)
44 {
46 }
47 
48 image_u8x3_t *image_u8x3_create_alignment(unsigned int width, unsigned int height, unsigned int alignment)
49 {
50  int stride = 3*width;
51 
52  if ((stride % alignment) != 0)
53  stride += alignment - (stride % alignment);
54 
55  uint8_t *buf = calloc(height*stride, sizeof(uint8_t));
56 
57  // const initializer
58  image_u8x3_t tmp = { .width = width, .height = height, .stride = stride, .buf = buf };
59 
60  image_u8x3_t *im = calloc(1, sizeof(image_u8x3_t));
61  memcpy(im, &tmp, sizeof(image_u8x3_t));
62  return im;
63 }
64 
66 {
67  uint8_t *buf = malloc(in->height*in->stride*sizeof(uint8_t));
68  memcpy(buf, in->buf, in->height*in->stride*sizeof(uint8_t));
69 
70  // const initializer
71  image_u8x3_t tmp = { .width = in->width, .height = in->height, .stride = in->stride, .buf = buf };
72 
73  image_u8x3_t *copy = calloc(1, sizeof(image_u8x3_t));
74  memcpy(copy, &tmp, sizeof(image_u8x3_t));
75  return copy;
76 }
77 
79 {
80  if (!im)
81  return;
82 
83  free(im->buf);
84  free(im);
85 }
86 
88 // PNM file i/o
89 
90 // Create an RGB image from PNM
92 {
94  if (pnm == NULL)
95  return NULL;
96 
97  image_u8x3_t *im = NULL;
98 
99  switch (pnm->format) {
100  case PNM_FORMAT_GRAY: {
101  im = image_u8x3_create(pnm->width, pnm->height);
102 
103  for (int y = 0; y < im->height; y++) {
104  for (int x = 0; x < im->width; x++) {
105  uint8_t gray = pnm->buf[y*im->width + x];
106  im->buf[y*im->stride + x*3 + 0] = gray;
107  im->buf[y*im->stride + x*3 + 1] = gray;
108  im->buf[y*im->stride + x*3 + 2] = gray;
109  }
110  }
111 
112  break;
113  }
114 
115  case PNM_FORMAT_RGB: {
116  im = image_u8x3_create(pnm->width, pnm->height);
117 
118  for (int y = 0; y < im->height; y++) {
119  for (int x = 0; x < im->width; x++) {
120  uint8_t r = pnm->buf[y*im->width*3 + 3*x];
121  uint8_t g = pnm->buf[y*im->width*3 + 3*x+1];
122  uint8_t b = pnm->buf[y*im->width*3 + 3*x+2];
123 
124  im->buf[y*im->stride + x*3 + 0] = r;
125  im->buf[y*im->stride + x*3 + 1] = g;
126  im->buf[y*im->stride + x*3 + 2] = b;
127  }
128  }
129 
130  break;
131  }
132  }
133 
134  pnm_destroy(pnm);
135  return im;
136 }
137 
138 int image_u8x3_write_pnm(const image_u8x3_t *im, const char *path)
139 {
140  FILE *f = fopen(path, "wb");
141  int res = 0;
142 
143  if (f == NULL) {
144  res = -1;
145  goto finish;
146  }
147 
148  // Only outputs to RGB
149  fprintf(f, "P6\n%d %d\n255\n", im->width, im->height);
150  int linesz = im->width * 3;
151  for (int y = 0; y < im->height; y++) {
152  if (linesz != fwrite(&im->buf[y*im->stride], 1, linesz, f)) {
153  res = -1;
154  goto finish;
155  }
156  }
157 
158 finish:
159  if (f != NULL)
160  fclose(f);
161 
162  return res;
163 }
164 
165 // only width 1 supported
166 void image_u8x3_draw_line(image_u8x3_t *im, float x0, float y0, float x1, float y1, uint8_t rgb[3], int width)
167 {
168  double dist = sqrtf((y1-y0)*(y1-y0) + (x1-x0)*(x1-x0));
169  double delta = 0.5 / dist;
170 
171  // terrible line drawing code
172  for (float f = 0; f <= 1; f += delta) {
173  int x = ((int) (x1 + (x0 - x1) * f));
174  int y = ((int) (y1 + (y0 - y1) * f));
175 
176  if (x < 0 || y < 0 || x >= im->width || y >= im->height)
177  continue;
178 
179  int idx = y*im->stride + 3*x;
180  for (int i = 0; i < 3; i++)
181  im->buf[idx + i] = rgb[i];
182  }
183 }
184 
185 static void convolve(const uint8_t *x, uint8_t *y, int sz, const uint8_t *k, int ksz)
186 {
187  assert((ksz&1)==1);
188 
189  for (int i = 0; i < ksz/2 && i < sz; i++)
190  y[i] = x[i];
191 
192  for (int i = 0; i < sz - ksz; i++) {
193  uint32_t acc = 0;
194 
195  for (int j = 0; j < ksz; j++)
196  acc += k[j]*x[i+j];
197 
198  y[ksz/2 + i] = acc >> 8;
199  }
200 
201  for (int i = sz - ksz + ksz/2; i < sz; i++)
202  y[i] = x[i];
203 }
204 
205 void image_u8x3_gaussian_blur(image_u8x3_t *im, double sigma, int ksz)
206 {
207  if (sigma == 0)
208  return;
209 
210  assert((ksz & 1) == 1); // ksz must be odd.
211 
212  // build the kernel.
213  double *dk = malloc(sizeof(double)*ksz);
214 
215  // for kernel of length 5:
216  // dk[0] = f(-2), dk[1] = f(-1), dk[2] = f(0), dk[3] = f(1), dk[4] = f(2)
217  for (int i = 0; i < ksz; i++) {
218  int x = -ksz/2 + i;
219  double v = exp(-.5*sq(x / sigma));
220  dk[i] = v;
221  }
222 
223  // normalize
224  double acc = 0;
225  for (int i = 0; i < ksz; i++)
226  acc += dk[i];
227 
228  for (int i = 0; i < ksz; i++)
229  dk[i] /= acc;
230 
231  uint8_t *k = malloc(sizeof(uint8_t)*ksz);
232  for (int i = 0; i < ksz; i++)
233  k[i] = dk[i]*255;
234 
235  if (0) {
236  for (int i = 0; i < ksz; i++)
237  printf("%d %15f %5d\n", i, dk[i], k[i]);
238  }
239  free(dk);
240 
241  for (int c = 0; c < 3; c++) {
242  for (int y = 0; y < im->height; y++) {
243 
244  uint8_t *in = malloc(sizeof(uint8_t)*im->stride);
245  uint8_t *out = malloc(sizeof(uint8_t)*im->stride);
246 
247  for (int x = 0; x < im->width; x++)
248  in[x] = im->buf[y*im->stride + 3 * x + c];
249 
250  convolve(in, out, im->width, k, ksz);
251  free(in);
252 
253  for (int x = 0; x < im->width; x++)
254  im->buf[y*im->stride + 3 * x + c] = out[x];
255  free(out);
256  }
257 
258  for (int x = 0; x < im->width; x++) {
259  uint8_t *in = malloc(sizeof(uint8_t)*im->height);
260  uint8_t *out = malloc(sizeof(uint8_t)*im->height);
261 
262  for (int y = 0; y < im->height; y++)
263  in[y] = im->buf[y*im->stride + 3*x + c];
264 
265  convolve(in, out, im->height, k, ksz);
266  free(in);
267 
268  for (int y = 0; y < im->height; y++)
269  im->buf[y*im->stride + 3*x + c] = out[y];
270  free(out);
271  }
272  }
273  free(k);
274 }
int height
Definition: pnm.h:45
int format
Definition: pnm.h:46
static void convolve(const uint8_t *x, uint8_t *y, int sz, const uint8_t *k, int ksz)
Definition: image_u8x3.c:185
const int32_t height
Definition: image_types.h:50
#define PNM_FORMAT_RGB
Definition: pnm.h:38
int image_u8x3_write_pnm(const image_u8x3_t *im, const char *path)
Definition: image_u8x3.c:138
uint8_t * buf
Definition: pnm.h:50
Definition: pnm.h:43
image_u8x3_t * image_u8x3_create_alignment(unsigned int width, unsigned int height, unsigned int alignment)
Definition: image_u8x3.c:48
uint8_t * buf
Definition: image_types.h:53
image_u8x3_t * image_u8x3_create(unsigned int width, unsigned int height)
Definition: image_u8x3.c:43
int width
Definition: pnm.h:45
static double sq(double v)
Definition: math_util.h:78
void image_u8x3_gaussian_blur(image_u8x3_t *im, double sigma, int ksz)
Definition: image_u8x3.c:205
const int32_t stride
Definition: image_types.h:51
void image_u8x3_draw_line(image_u8x3_t *im, float x0, float y0, float x1, float y1, uint8_t rgb[3], int width)
Definition: image_u8x3.c:166
#define DEFAULT_ALIGNMENT_U8X3
Definition: image_u8x3.c:41
pnm_t * pnm_create_from_file(const char *path)
Definition: pnm.c:34
const int32_t width
Definition: image_types.h:49
image_u8x3_t * image_u8x3_copy(const image_u8x3_t *in)
Definition: image_u8x3.c:65
#define PNM_FORMAT_GRAY
Definition: pnm.h:37
image_u8x3_t * image_u8x3_create_from_pnm(const char *path)
Definition: image_u8x3.c:91
void image_u8x3_destroy(image_u8x3_t *im)
Definition: image_u8x3.c:78
void pnm_destroy(pnm_t *pnm)
Definition: pnm.c:147


apriltag
Author(s): Edwin Olson , Max Krogius
autogenerated on Mon Jun 26 2023 02:26:12