Paparazzi UAS  v5.14.0_stable-0-g3f680d1
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
image.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Freek van Tienen <freek.v.tienen@gmail.com>
3  *
4  * This file is part of Paparazzi.
5  *
6  * Paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * Paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Paparazzi; see the file COPYING. If not, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
27 #include "image.h"
28 #include <stdlib.h>
29 #include <string.h>
30 #include "lucas_kanade.h"
31 
39 void image_create(struct image_t *img, uint16_t width, uint16_t height, enum image_type type)
40 {
41  // Set the variables
42  img->type = type;
43  img->w = width;
44  img->h = height;
45 
46  // Depending on the type the size differs
47  if (type == IMAGE_YUV422) {
48  img->buf_size = sizeof(uint8_t) * 2 * width * height;
49  } else if (type == IMAGE_JPEG) {
50  img->buf_size = sizeof(uint8_t) * 2 * width * height; // At maximum quality this is enough
51  } else if (type == IMAGE_GRADIENT) {
52  img->buf_size = sizeof(int16_t) * width * height;
53  } else {
54  img->buf_size = sizeof(uint8_t) * width * height;
55  }
56 
57  img->buf = malloc(img->buf_size);
58 }
59 
64 void image_free(struct image_t *img)
65 {
66  if (img->buf != NULL) {
67  free(img->buf);
68  img->buf = NULL;
69  }
70 }
71 
78 void image_copy(struct image_t *input, struct image_t *output)
79 {
80  if (input->type != output->type) {
81  return;
82  }
83 
84  output->w = input->w;
85  output->h = input->h;
86  output->buf_size = input->buf_size;
87  output->ts = input->ts;
88  output->eulers = input->eulers;
89  output->pprz_ts = input->pprz_ts;
90  memcpy(output->buf, input->buf, input->buf_size);
91 }
92 
100 void image_switch(struct image_t *a, struct image_t *b)
101 {
102  /* Remember everything from image a */
103  struct image_t old_a;
104  memcpy(&old_a, a, sizeof(struct image_t));
105 
106  /* Copy everything from b to a */
107  memcpy(a, b, sizeof(struct image_t));
108 
109  /* Copy everything from the remembered a to b */
110  memcpy(b, &old_a, sizeof(struct image_t));
111 }
112 
119 void image_to_grayscale(struct image_t *input, struct image_t *output)
120 {
121  uint8_t *source = input->buf;
122  uint8_t *dest = output->buf;
123  source++;
124 
125  // Copy the creation timestamp (stays the same)
126  output->ts = input->ts;
127  output->eulers = input->eulers;
128  output->pprz_ts = input->pprz_ts;
129 
130  // Copy the pixels
131  for (int y = 0; y < output->h; y++) {
132  for (int x = 0; x < output->w; x++) {
133  if (output->type == IMAGE_YUV422) {
134  *dest++ = 127; // U / V
135  }
136  *dest++ = *source; // Y
137  source += 2;
138  }
139  }
140 }
141 
154 uint16_t image_yuv422_colorfilt(struct image_t *input, struct image_t *output, uint8_t y_m, uint8_t y_M, uint8_t u_m,
155  uint8_t u_M, uint8_t v_m, uint8_t v_M)
156 {
157  uint16_t cnt = 0;
158  uint8_t *source = (uint8_t *)input->buf;
159  uint8_t *dest = (uint8_t *)output->buf;
160 
161  // Copy the creation timestamp (stays the same)
162  output->ts = input->ts;
163 
164  // Go trough all the pixels
165  for (uint16_t y = 0; y < output->h; y++) {
166  for (uint16_t x = 0; x < output->w; x += 2) {
167  // Check if the color is inside the specified values
168  if (
169  (dest[1] >= y_m)
170  && (dest[1] <= y_M)
171  && (dest[0] >= u_m)
172  && (dest[0] <= u_M)
173  && (dest[2] >= v_m)
174  && (dest[2] <= v_M)
175  ) {
176  cnt ++;
177  // UYVY
178  dest[0] = 64; // U
179  dest[1] = source[1]; // Y
180  dest[2] = 255; // V
181  dest[3] = source[3]; // Y
182  } else {
183  // UYVY
184  char u = source[0] - 127;
185  u /= 4;
186  dest[0] = 127; // U
187  dest[1] = source[1]; // Y
188  u = source[2] - 127;
189  u /= 4;
190  dest[2] = 127; // V
191  dest[3] = source[3]; // Y
192  }
193 
194  // Go to the next 2 pixels
195  dest += 4;
196  source += 4;
197  }
198  }
199  return cnt;
200 }
201 
218 int check_color_yuv422(struct image_t *im, int x, int y, uint8_t y_m, uint8_t y_M, uint8_t u_m, uint8_t u_M, uint8_t v_m, uint8_t v_M)
219 {
220  // odd pixels are uy
221  // even pixels are vy
222  // adapt x, so that we always have u-channel in index 0:
223  if (x % 2 == 1) { x--; }
224 
225  // Is the pixel inside the image?
226  if (x < 0 || x >= im->w || y < 0 || y >= im->h) {
227  return 0;
228  }
229 
230  // Take the right place in the buffer:
231  uint8_t *buf = im->buf;
232  buf += 2 * (y * (im->w) + x); // each pixel has two bytes
233 
234  if (
235  (buf[1] >= y_m)
236  && (buf[1] <= y_M)
237  && (buf[0] >= u_m)
238  && (buf[0] <= u_M)
239  && (buf[2] >= v_m)
240  && (buf[2] <= v_M)
241  ) {
242  // the pixel passes:
243  return 1;
244  } else {
245  // the pixel does not:
246  return 0;
247  }
248 }
249 
260 void set_color_yuv422(struct image_t *im, int x, int y, uint8_t Y, uint8_t U, uint8_t V) {
261 
262  // odd pixels are uy
263  // even pixels are vy
264  // adapt x, so that we always have u-channel in index 0:
265  if (x % 2 == 1) { x--; }
266 
267  // Is the pixel inside the image?
268  if (x < 0 || x >= im->w || y < 0 || y >= im->h) {
269  return;
270  }
271 
272  // Take the right place in the buffer:
273  uint8_t *buf = im->buf;
274  buf += 2 * (y * (im->w) + x); // each pixel has two bytes
275 
276  buf[0] = U;
277  buf[1] = Y;
278  buf[2] = V;
279  buf[3] = Y;
280 }
281 
282 
299 void image_yuv422_downsample(struct image_t *input, struct image_t *output, uint16_t downsample)
300 {
301  uint8_t *source = input->buf;
302  uint8_t *dest = output->buf;
303  uint16_t pixelskip = (downsample - 1) * 2;
304 
305  // Copy the creation timestamp (stays the same)
306  output->ts = input->ts;
307 
308  // Go trough all the pixels
309  for (uint16_t y = 0; y < output->h; y++) {
310  for (uint16_t x = 0; x < output->w; x += 2) {
311  // YUYV
312  *dest++ = *source++; // U
313  *dest++ = *source++; // Y
314  *dest++ = *source++; // V
315  source += pixelskip;
316  *dest++ = *source++; // Y
317  source += pixelskip;
318  }
319  // read 1 in every 'downsample' rows, so skip (downsample-1) rows after reading the first
320  source += (downsample - 1) * input->w * 2;
321  }
322 }
323 
331 void image_add_border(struct image_t *input, struct image_t *output, uint8_t border_size)
332 {
333  // Create padded image based on input
334  image_create(output, input->w + 2 * border_size, input->h + 2 * border_size, input->type);
335 
336  uint8_t *input_buf = (uint8_t *)input->buf;
337  uint8_t *output_buf = (uint8_t *)output->buf;
338 
339  // Skip first `border_size` rows, iterate through next input->h rows
340  for (uint16_t i = border_size; i != (output->h - border_size); i++) {
341 
342  // Mirror first `border_size` columns
343  for (uint8_t j = 0; j != border_size; j++) {
344  output_buf[i * output->w + (border_size - 1 - j)] = input_buf[(i - border_size) * input->w + j];
345  }
346 
347  // Copy corresponding row values from input image
348  memcpy(&output_buf[i * output->w + border_size], &input_buf[(i - border_size) * input->w], sizeof(uint8_t) * input->w);
349 
350  // Mirror last `border_size` columns
351  for (uint8_t j = 0; j != border_size; j++) {
352  output_buf[i * output->w + output->w - border_size + j] = output_buf[i * output->w + output->w - border_size - 1 - j];
353  }
354  }
355 
356  // Mirror first `border_size` and last `border_size` rows
357  for (uint8_t i = 0; i != border_size; i++) {
358  memcpy(&output_buf[(border_size - 1) * output->w - i * output->w], &output_buf[border_size * output->w + i * output->w],
359  sizeof(uint8_t) * output->w);
360  memcpy(&output_buf[(output->h - border_size) * output->w + i * output->w],
361  &output_buf[(output->h - border_size - 1) * output->w - i * output->w], sizeof(uint8_t) * output->w);
362  }
363 }
364 
376 void pyramid_next_level(struct image_t *input, struct image_t *output, uint8_t border_size)
377 {
378  // Create output image, new image size is half the size of input image without padding (border)
379  image_create(output, (input->w + 1 - 2 * border_size) / 2, (input->h + 1 - 2 * border_size) / 2, input->type);
380 
381  uint8_t *input_buf = (uint8_t *)input->buf;
382  uint8_t *output_buf = (uint8_t *)output->buf;
383 
384  uint16_t row, col; // coordinates of the central pixel; pixel being calculated in input matrix; center of filer matrix
385  uint16_t w = input->w;
386  int32_t sum = 0;
387 
388  for (uint16_t i = 0; i != output->h; i++) {
389 
390  for (uint16_t j = 0; j != output->w; j++) {
391  row = border_size + 2 * i; // First skip border, then every second pixel
392  col = border_size + 2 * j;
393 
394  sum = 39 * (input_buf[(row - 2) * w + (col - 2)] + input_buf[(row - 2) * w + (col + 2)] +
395  input_buf[(row + 2) * w + (col - 2)] + input_buf[(row + 2) * w + (col + 2)]);
396  sum += 156 * (input_buf[(row - 2) * w + (col - 1)] + input_buf[(row - 2) * w + (col + 1)] +
397  input_buf[(row - 1) * w + (col + 2)] + input_buf[(row + 1) * w + (col - 2)]
398  + input_buf[(row + 1) * w + (col + 2)] + input_buf[(row + 2) * w + (col - 1)] + input_buf[(row + 2) * w + (col + 1)] +
399  input_buf[(row - 1) * w + (col - 2)]);
400  sum += 234 * (input_buf[(row - 2) * w + (col)] + input_buf[(row) * w + (col - 2)] +
401  input_buf[(row) * w + (col + 2)] + input_buf[(row + 2) * w + (col)]);
402  sum += 625 * (input_buf[(row - 1) * w + (col - 1)] + input_buf[(row - 1) * w + (col + 1)] +
403  input_buf[(row + 1) * w + (col - 1)] + input_buf[(row + 1) * w + (col + 1)]);
404  sum += 938 * (input_buf[(row - 1) * w + (col)] + input_buf[(row) * w + (col - 1)] +
405  input_buf[(row) * w + (col + 1)] + input_buf[(row + 1) * w + (col)]);
406  sum += 1406 * input_buf[(row) * w + (col)];
407 
408  output_buf[i * output->w + j] = sum / 10000;
409  }
410  }
411 }
412 
413 
423 void pyramid_build(struct image_t *input, struct image_t *output_array, uint8_t pyr_level, uint16_t border_size)
424 {
425  // Pad input image and save it as '0' pyramid level
426  image_add_border(input, &output_array[0], border_size);
427 
428  // Temporary holds 'i' level version of original image to be padded and saved as 'i' pyramid level
429  struct image_t temp;
430 
431  for (uint8_t i = 1; i != pyr_level + 1; i++) {
432  pyramid_next_level(&output_array[i - 1], &temp, border_size);
433  image_add_border(&temp, &output_array[i], border_size);
434  image_free(&temp);
435  }
436 }
437 
450 void image_subpixel_window(struct image_t *input, struct image_t *output, struct point_t *center,
451  uint32_t subpixel_factor, uint8_t border_size)
452 {
453  uint8_t *input_buf = (uint8_t *)input->buf;
454  uint8_t *output_buf = (uint8_t *)output->buf;
455 
456  // Calculate the window size
457  uint16_t half_window = output->w / 2;
458 
459  uint32_t subpixel_w = (input->w - 2) * subpixel_factor;
460  uint32_t subpixel_h = (input->h - 2) * subpixel_factor;
461 
462  // Go through the whole window size in normal coordinates
463  for (uint16_t i = 0; i < output->w; i++) {
464  for (uint16_t j = 0; j < output->h; j++) {
465  // Calculate the subpixel coordinate
466  uint32_t x = center->x + border_size * subpixel_factor + (i - half_window) * subpixel_factor;
467  uint32_t y = center->y + border_size * subpixel_factor + (j - half_window) * subpixel_factor;
468 
469  BoundUpper(x, subpixel_w);
470  BoundUpper(y, subpixel_h);
471 
472  // Calculate the original pixel coordinate
473  uint16_t orig_x = x / subpixel_factor;
474  uint16_t orig_y = y / subpixel_factor;
475 
476  // Calculate top left (in subpixel coordinates)
477  uint32_t tl_x = orig_x * subpixel_factor;
478  uint32_t tl_y = orig_y * subpixel_factor;
479 
480  // Check if it is the top left pixel
481  if (tl_x == x && tl_y == y) {
482  output_buf[output->w * j + i] = input_buf[input->w * orig_y + orig_x];
483  } else {
484  // Calculate the difference from the top left
485  uint32_t alpha_x = (x - tl_x);
486  uint32_t alpha_y = (y - tl_y);
487 
488  // Blend from the 4 surrounding pixels
489  uint32_t blend = (subpixel_factor - alpha_x) * (subpixel_factor - alpha_y) * input_buf[input->w * orig_y + orig_x];
490  blend += alpha_x * (subpixel_factor - alpha_y) * input_buf[input->w * orig_y + (orig_x + 1)];
491  blend += (subpixel_factor - alpha_x) * alpha_y * input_buf[input->w * (orig_y + 1) + orig_x];
492  blend += alpha_x * alpha_y * input_buf[input->w * (orig_y + 1) + (orig_x + 1)];
493 
494  // Set the normalized pixel blend
495  output_buf[output->w * j + i] = blend / (subpixel_factor * subpixel_factor);
496  }
497  }
498  }
499 }
500 
508 void image_gradients(struct image_t *input, struct image_t *dx, struct image_t *dy)
509 {
510  // Fetch the buffers in the correct format
511  uint8_t *input_buf = (uint8_t *)input->buf;
512  int16_t *dx_buf = (int16_t *)dx->buf;
513  int16_t *dy_buf = (int16_t *)dy->buf;
514 
515  // Go trough all pixels except the borders
516  for (uint16_t x = 1; x < input->w - 1; x++) {
517  for (uint16_t y = 1; y < input->h - 1; y++) {
518  dx_buf[(y - 1)*dx->w + (x - 1)] = (int16_t)input_buf[y * input->w + x + 1] - (int16_t)input_buf[y * input->w + x - 1];
519  dy_buf[(y - 1)*dy->w + (x - 1)] = (int16_t)input_buf[(y + 1) * input->w + x] - (int16_t)
520  input_buf[(y - 1) * input->w + x];
521  }
522  }
523 }
524 
532 void image_calculate_g(struct image_t *dx, struct image_t *dy, int32_t *g)
533 {
534  int32_t sum_dxx = 0, sum_dxy = 0, sum_dyy = 0;
535 
536  // Fetch the buffers in the correct format
537  int16_t *dx_buf = (int16_t *)dx->buf;
538  int16_t *dy_buf = (int16_t *)dy->buf;
539 
540  // Calculate the different sums
541  for (uint16_t x = 0; x < dx->w; x++) {
542  for (uint16_t y = 0; y < dy->h; y++) {
543  sum_dxx += ((int32_t)dx_buf[y * dx->w + x] * dx_buf[y * dx->w + x]);
544  sum_dxy += ((int32_t)dx_buf[y * dx->w + x] * dy_buf[y * dy->w + x]);
545  sum_dyy += ((int32_t)dy_buf[y * dy->w + x] * dy_buf[y * dy->w + x]);
546  }
547  }
548 
549  // output the G vector
550  g[0] = sum_dxx / 255;
551  g[1] = sum_dxy / 255;
552  g[2] = g[1];
553  g[3] = sum_dyy / 255;
554 }
555 
564 uint32_t image_difference(struct image_t *img_a, struct image_t *img_b, struct image_t *diff)
565 {
566  uint32_t sum_diff2 = 0;
567  int16_t *diff_buf = NULL;
568 
569  // Fetch the buffers in the correct format
570  uint8_t *img_a_buf = (uint8_t *)img_a->buf;
571  uint8_t *img_b_buf = (uint8_t *)img_b->buf;
572 
573  // If we want the difference image back
574  if (diff != NULL) {
575  diff_buf = (int16_t *)diff->buf;
576  }
577 
578  // Go trough the imagge pixels and calculate the difference
579  for (uint16_t x = 0; x < img_b->w; x++) {
580  for (uint16_t y = 0; y < img_b->h; y++) {
581  int16_t diff_c = img_a_buf[(y + 1) * img_a->w + (x + 1)] - img_b_buf[y * img_b->w + x];
582  sum_diff2 += diff_c * diff_c;
583 
584  // Set the difference image
585  if (diff_buf != NULL) {
586  diff_buf[y * diff->w + x] = diff_c;
587  }
588  }
589  }
590 
591  return sum_diff2;
592 }
593 
602 int32_t image_multiply(struct image_t *img_a, struct image_t *img_b, struct image_t *mult)
603 {
604  int32_t sum = 0;
605  int16_t *img_a_buf = (int16_t *)img_a->buf;
606  int16_t *img_b_buf = (int16_t *)img_b->buf;
607  int16_t *mult_buf = NULL;
608 
609  // When we want an output
610  if (mult != NULL) {
611  mult_buf = (int16_t *)mult->buf;
612  }
613 
614  // Calculate the multiplication
615  for (uint16_t x = 0; x < img_a->w; x++) {
616  for (uint16_t y = 0; y < img_a->h; y++) {
617  int32_t mult_c = img_a_buf[y * img_a->w + x] * img_b_buf[y * img_b->w + x];
618  sum += mult_c;
619 
620  // Set the difference image
621  if (mult_buf != NULL) {
622  mult_buf[y * mult->w + x] = mult_c;
623  }
624  }
625  }
626 
627  return sum;
628 }
629 
638 void image_show_points(struct image_t *img, struct point_t *points, uint16_t points_cnt)
639 {
640  uint8_t color[4];
641  color[0] = 255;
642  color[1] = 255;
643  color[2] = 255;
644  color[3] = 255;
645 
646  image_show_points_color(img, points, points_cnt, color);
647 
648 }
649 
660 void image_show_points_color(struct image_t *img, struct point_t *points, uint16_t points_cnt, uint8_t *color)
661 {
662  uint8_t *img_buf = (uint8_t *)img->buf;
663  uint8_t pixel_width = (img->type == IMAGE_YUV422) ? 2 : 1;
664 
665  int cross_hair = 1;
666  int size_crosshair = 5;
667 
668  // Go trough all points and color them
669  for (int i = 0; i < points_cnt; i++) {
670  if (!cross_hair) {
671  uint32_t idx = pixel_width * points[i].y * img->w + points[i].x * pixel_width;
672  img_buf[idx] = 255;
673 
674  // YUV422 consists of 2 pixels
675  if (img->type == IMAGE_YUV422) {
676  idx++;
677  img_buf[idx] = 255;
678  }
679  } else {
680  image_draw_crosshair(img, &(points[i]), color, size_crosshair);
681  }
682  }
683 }
684 
685 void image_show_flow(struct image_t *img, struct flow_t *vectors, uint16_t points_cnt, uint8_t subpixel_factor)
686 {
687  static uint8_t color[4] = {255, 255, 255, 255};
688  static uint8_t bad_color[4] = {0, 0, 0, 0};
689  image_show_flow_color(img, vectors, points_cnt, subpixel_factor, color, bad_color);
690 }
691 
702 void image_show_flow_color(struct image_t *img, struct flow_t *vectors, uint16_t points_cnt, uint8_t subpixel_factor,
703  const uint8_t *color, const uint8_t *bad_color)
704 {
705  static int size_crosshair = 5;
706 
707  // Go through all the points
708  for (uint16_t i = 0; i < points_cnt; i++) {
709  // Draw a line from the original position with the flow vector
710  struct point_t from = {
711  .x = vectors[i].pos.x / subpixel_factor,
712  .y = vectors[i].pos.y / subpixel_factor
713  };
714  struct point_t to = {
715  .x = (vectors[i].pos.x + vectors[i].flow_x) / subpixel_factor,
716  .y = (vectors[i].pos.y + vectors[i].flow_y) / subpixel_factor
717  };
718 
719  if (vectors[i].error >= LARGE_FLOW_ERROR) {
720  image_draw_crosshair(img, &to, bad_color, size_crosshair);
721  image_draw_line_color(img, &from, &to, bad_color);
722  } else {
723  image_draw_crosshair(img, &to, color, size_crosshair);
724  image_draw_line_color(img, &from, &to, color);
725  }
726  }
727 }
736 void image_gradient_pixel(struct image_t *img, struct point_t *loc, int method, int *dx, int *dy)
737 {
738  // create the simple and sobel filter only once:
739 
740  int gradient_x, gradient_y, index;
741  gradient_x = 0;
742  gradient_y = 0;
743 
744  // get image buffer and take into account YUV vs. grayscale:
745  uint8_t *img_buf = (uint8_t *)img->buf;
746  uint8_t pixel_width = (img->type == IMAGE_YUV422) ? 2 : 1;
747  uint8_t add_ind = pixel_width - 1;
748 
749  // check if all pixels will fall in the image:
750  if (loc->x >= 1 && (loc->x + 1) < img->w && loc->y >= 1 && (loc->y + 1) < img->h) {
751  if (method == 0) {
752 
753  // *************
754  // Simple method
755  // *************
756 
757  // dx:
758  index = loc->y * img->w * pixel_width + (loc->x - 1) * pixel_width;
759  gradient_x -= (int) img_buf[index + add_ind];
760  index = loc->y * img->w * pixel_width + (loc->x + 1) * pixel_width;
761  gradient_x += (int) img_buf[index + add_ind];
762  // dy:
763  index = (loc->y - 1) * img->w * pixel_width + loc->x * pixel_width;
764  gradient_y -= (int) img_buf[index + add_ind];
765  index = (loc->y + 1) * img->w * pixel_width + loc->x * pixel_width;
766  gradient_y += (int) img_buf[index + add_ind];
767  } else {
768 
769  // *****
770  // Sobel
771  // *****
772  static int Sobel[9] = { -1, 0, 1, -2, 0, 2, -1, 0, 1};
773  static int total_sobel = 8;
774 
775  int filt_ind_y = 0;
776  int filt_ind_x;
777  for (int x = -1; x <= 1; x++) {
778  for (int y = -1; y <= 1; y++) {
779  index = (loc->y + y) * img->w * pixel_width + (loc->x + x) * pixel_width;
780  if (x != 0) {
781  filt_ind_x = (x + 1) % 3 + (y + 1) * 3;
782  gradient_x += Sobel[filt_ind_x] * (int) img_buf[index + add_ind];
783  }
784  if (y != 0) {
785  gradient_y += Sobel[filt_ind_y] * (int) img_buf[index + add_ind];
786  }
787  filt_ind_y++;
788  }
789  }
790  gradient_x /= total_sobel;
791  }
792  }
793 
794  // TODO: more efficient would be to use dx, dy directly:
795  (*dx) = gradient_x;
796  (*dy) = gradient_y;
797 }
798 
808 void image_draw_rectangle(struct image_t *img, int x_min, int x_max, int y_min, int y_max, uint8_t *color)
809 {
810  struct point_t from, to;
811 
812  // bottom from left to right:
813  from.x = x_min;
814  from.y = y_min;
815  to.x = x_max;
816  to.y = y_min;
817  image_draw_line_color(img, &from, &to, color);
818 
819  // from bottom right to top right:
820  from.x = x_max;
821  from.y = y_min;
822  to.x = x_max;
823  to.y = y_max;
824  image_draw_line_color(img, &from, &to, color);
825 
826  // from top right to top left:
827  from.x = x_max;
828  from.y = y_max;
829  to.x = x_min;
830  to.y = y_max;
831  image_draw_line_color(img, &from, &to, color);
832 
833  // from top left to bottom left:
834  from.x = x_min;
835  from.y = y_max;
836  to.x = x_min;
837  to.y = y_min;
838  image_draw_line_color(img, &from, &to, color);
839 
840 }
841 
850 void image_draw_crosshair(struct image_t *img, struct point_t *loc, const uint8_t *color, uint32_t size_crosshair)
851 {
852  struct point_t from, to;
853 
854  if (loc->x >= size_crosshair && loc->x < img->w - size_crosshair
855  && loc->y >= size_crosshair && loc->y < img->h - size_crosshair) {
856  // draw the lines:
857  from.x = loc->x - size_crosshair;
858  from.y = loc->y;
859  to.x = loc->x + size_crosshair;
860  to.y = loc->y;
861  image_draw_line_color(img, &from, &to, color);
862  from.x = loc->x;
863  from.y = loc->y - size_crosshair;
864  to.x = loc->x;
865  to.y = loc->y + size_crosshair;
866  image_draw_line_color(img, &from, &to, color);
867  }
868 }
869 
876 void image_draw_line(struct image_t *img, struct point_t *from, struct point_t *to)
877 {
878  static uint8_t color[4] = {255, 255, 255, 255};
879  image_draw_line_color(img, from, to, color);
880 }
881 
882 
891 void image_draw_line_color(struct image_t *img, struct point_t *from, struct point_t *to, const uint8_t *color)
892 {
893  int xerr = 0, yerr = 0;
894  uint8_t *img_buf = (uint8_t *)img->buf;
895  uint8_t pixel_width = (img->type == IMAGE_YUV422) ? 2 : 1;
896  uint16_t startx = from->x;
897  uint16_t starty = from->y;
898 
899  uint8_t temp_color[4] = {color[0], color[1], color[2], color[3]};
900 
901  /* compute the distances in both directions */
902  int32_t delta_x = to->x - from->x;
903  int32_t delta_y = to->y - from->y;
904 
905  /* Compute the direction of the increment,
906  an increment of 0 means either a horizontal or vertical
907  line.
908  */
909  int8_t incx, incy;
910  if (delta_x > 0) { incx = 1; }
911  else if (delta_x == 0) { incx = 0; }
912  else { incx = -1; }
913 
914  if (delta_y > 0) { incy = 1; }
915  else if (delta_y == 0) { incy = 0; }
916  else { incy = -1; }
917 
918  /* determine which distance is greater */
919  uint16_t distance = 0;
920  delta_x = abs(delta_x);
921  delta_y = abs(delta_y);
922  if (delta_x > delta_y) { distance = delta_x * 20; }
923  else { distance = delta_y * 20; }
924 
925  /* draw the line */
926  for (uint16_t t = 0; /* starty >= 0 && */ starty < img->h && /* startx >= 0 && */ startx < img->w
927  && t <= distance + 1; t++) {
928 
929  // depending on startx being odd or even, we first have to set U or V
930  if (startx % 2 == 1) {
931  temp_color[0] = color[2];
932  temp_color[2] = color[0];
933  } else {
934  temp_color[0] = color[0];
935  temp_color[2] = color[2];
936  }
937  uint32_t buf_loc = img->w * pixel_width * starty + startx * pixel_width;
938  img_buf[buf_loc] = temp_color[0]; // u (when startx even)
939 
940  if (img->type == IMAGE_YUV422) {
941  img_buf[buf_loc + 1] = temp_color[1]; // y1
942 
943  if (startx + 1 < img->w) {
944  img_buf[buf_loc + 2] = temp_color[2]; // v (when startx even)
945  img_buf[buf_loc + 3] = temp_color[3]; // y2
946  }
947  }
948 
949  xerr += delta_x;
950  yerr += delta_y;
951  if (xerr > distance) {
952  xerr -= distance;
953  startx += incx;
954  }
955  if (yerr > distance) {
956  yerr -= distance;
957  starty += incy;
958  }
959  }
960 }
unsigned short uint16_t
Definition: types.h:16
void image_gradients(struct image_t *input, struct image_t *dx, struct image_t *dy)
Calculate the gradients using the following matrix: [0 -1 0; -1 0 1; 0 1 0].
Definition: image.c:508
static uint32_t idx
static uint8_t dest[]
Definition: w5100.c:99
void set_color_yuv422(struct image_t *im, int x, int y, uint8_t Y, uint8_t U, uint8_t V)
Sets Y,U,V for a single pixel.
Definition: image.c:260
uint32_t buf_size
The buffer size.
Definition: image.h:52
image_type
Definition: image.h:35
void image_yuv422_downsample(struct image_t *input, struct image_t *output, uint16_t downsample)
Simplified high-speed low CPU downsample function without averaging downsample factor must be 1...
Definition: image.c:299
uint32_t image_difference(struct image_t *img_a, struct image_t *img_b, struct image_t *diff)
Calculate the difference between two images and return the error This will only work with grayscale i...
Definition: image.c:564
void image_switch(struct image_t *a, struct image_t *b)
This will switch image *a and *b This is faster as image_copy because it doesn't copy the whole image...
Definition: image.c:100
void image_free(struct image_t *img)
Free the image.
Definition: image.c:64
void image_draw_line_color(struct image_t *img, struct point_t *from, struct point_t *to, const uint8_t *color)
Draw a line on the image.
Definition: image.c:891
#define LARGE_FLOW_ERROR
Definition: lucas_kanade.h:37
void image_create(struct image_t *img, uint16_t width, uint16_t height, enum image_type type)
Create a new image.
Definition: image.c:39
Definition: image.h:43
Definition: image.h:66
void image_draw_line(struct image_t *img, struct point_t *from, struct point_t *to)
Draw a pink line on the image.
Definition: image.c:876
void image_show_flow_color(struct image_t *img, struct flow_t *vectors, uint16_t points_cnt, uint8_t subpixel_factor, const uint8_t *color, const uint8_t *bad_color)
Shows the flow from a specific point to a new point This works on YUV422 and Grayscale images...
Definition: image.c:702
void image_copy(struct image_t *input, struct image_t *output)
Copy an image from inut to output This will only work if the formats are the same.
Definition: image.c:78
void image_show_points(struct image_t *img, struct point_t *points, uint16_t points_cnt)
Show points in an image by coloring them through giving the pixels the maximum value.
Definition: image.c:638
uint32_t x
The x coordinate of the point.
Definition: image.h:58
uint32_t pprz_ts
The timestamp in us since system startup.
Definition: image.h:49
void image_show_flow(struct image_t *img, struct flow_t *vectors, uint16_t points_cnt, uint8_t subpixel_factor)
Definition: image.c:685
void image_draw_rectangle(struct image_t *img, int x_min, int x_max, int y_min, int y_max, uint8_t *color)
Draw a rectangle on the image.
Definition: image.c:808
void pyramid_build(struct image_t *input, struct image_t *output_array, uint8_t pyr_level, uint16_t border_size)
This function populates given array of image_t structs with wanted number of padded pyramids based on...
Definition: image.c:423
void pyramid_next_level(struct image_t *input, struct image_t *output, uint8_t border_size)
This function takes previous padded pyramid level and outputs next level of pyramid without padding...
Definition: image.c:376
Image helper functions like resizing, color filter, converters...
int16_t flow_x
The x direction flow in subpixels.
Definition: image.h:68
void image_gradient_pixel(struct image_t *img, struct point_t *loc, int method, int *dx, int *dy)
Get the gradient at a pixel location.
Definition: image.c:736
uint16_t w
Image width.
Definition: image.h:45
unsigned long uint32_t
Definition: types.h:18
uint16_t h
Image height.
Definition: image.h:46
signed short int16_t
Definition: types.h:17
void image_add_border(struct image_t *input, struct image_t *output, uint8_t border_size)
This function adds padding to input image by mirroring the edge image elements.
Definition: image.c:331
void * buf
Image buffer (depending on the image_type)
Definition: image.h:53
void image_draw_crosshair(struct image_t *img, struct point_t *loc, const uint8_t *color, uint32_t size_crosshair)
Draw a cross-hair on the image.
Definition: image.c:850
struct point_t pos
The original position the flow comes from.
Definition: image.h:67
uint32_t y
The y coordinate of the point.
Definition: image.h:59
void image_to_grayscale(struct image_t *input, struct image_t *output)
Convert an image to grayscale.
Definition: image.c:119
Definition: image.h:57
signed long int32_t
Definition: types.h:19
unsigned char uint8_t
Definition: types.h:14
efficient fixed-point optical-flow calculation
struct timeval ts
The timestamp of creation.
Definition: image.h:47
UYVY format (uint16 per pixel)
Definition: image.h:36
void image_calculate_g(struct image_t *dx, struct image_t *dy, int32_t *g)
Calculate the G vector of an image gradient This is used for optical flow calculation.
Definition: image.c:532
signed char int8_t
Definition: types.h:15
An image gradient (int16 per pixel)
Definition: image.h:39
uint16_t image_yuv422_colorfilt(struct image_t *input, struct image_t *output, uint8_t y_m, uint8_t y_M, uint8_t u_m, uint8_t u_M, uint8_t v_m, uint8_t v_M)
Filter colors in an YUV422 image.
Definition: image.c:154
struct FloatEulers eulers
Euler Angles at time of image.
Definition: image.h:48
int16_t flow_y
The y direction flow in subpixels.
Definition: image.h:69
int32_t image_multiply(struct image_t *img_a, struct image_t *img_b, struct image_t *mult)
Calculate the multiplication between two images and return the error This will only work with image g...
Definition: image.c:602
int check_color_yuv422(struct image_t *im, int x, int y, uint8_t y_m, uint8_t y_M, uint8_t u_m, uint8_t u_M, uint8_t v_m, uint8_t v_M)
Checks the color of a single pixel in a YUV422 image.
Definition: image.c:218
void image_subpixel_window(struct image_t *input, struct image_t *output, struct point_t *center, uint32_t subpixel_factor, uint8_t border_size)
This outputs a subpixel window image in grayscale Currently only works with Grayscale images as input...
Definition: image.c:450
An JPEG encoded image (not per pixel encoded)
Definition: image.h:38
enum image_type type
The image type.
Definition: image.h:44
void image_show_points_color(struct image_t *img, struct point_t *points, uint16_t points_cnt, uint8_t *color)
Show points in an image by coloring them through giving the pixels the maximum value.
Definition: image.c:660