Paparazzi UAS  v5.12_stable-4-g9b43e9b
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
detect_window.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015
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, see
18  * <http://www.gnu.org/licenses/>.
19  *
20  */
21 
27 #define RES 100
28 #define N_WINDOW_SIZES 1
29 
30 #ifndef DETECT_WINDOW_FPS
31 #define DETECT_WINDOW_FPS 0
32 #endif
33 PRINT_CONFIG_VAR(DETECT_WINDOW_FPS)
34 
35 #include "cv.h"
36 #include "detect_window.h"
37 #include <stdio.h>
38 
40 {
41  cv_add_to_device(&DETECT_WINDOW_CAMERA, detect_window, DETECT_WINDOW_FPS);
42 }
43 
44 struct image_t *detect_window(struct image_t *img)
45 {
46 
47  uint16_t coordinate[2];
48  coordinate[0] = 0; coordinate[1] = 0;
49  uint16_t response = 0;
50  uint32_t integral_image[img->w * img->h];
51  struct image_t gray;
52  image_create(&gray, img->w, img->h, IMAGE_GRAYSCALE);
53  image_to_grayscale(img, &gray);
54 
55  response = detect_window_sizes((uint8_t *)gray.buf, (uint32_t)img->w, (uint32_t)img->h, coordinate, integral_image,
56  MODE_BRIGHT);
57  printf("Coordinate: %d, %d\n", coordinate[0], coordinate[1]);
58  printf("Response = %d\n", response);
59 
60  image_free(&gray);
61  return NULL; // No new image was created
62 }
63 
64 
65 uint16_t detect_window_sizes(uint8_t *in, uint32_t image_width, uint32_t image_height, uint16_t *coordinate,
66  uint32_t *integral_image, uint8_t MODE)
67 {
68  // whether to calculate the integral image (only do once):
69  uint8_t calculate_integral_image = 1;
70  uint16_t sizes[N_WINDOW_SIZES];
71  uint16_t best_response[N_WINDOW_SIZES];
72  uint16_t best_index = 0;
73  uint16_t best_xc = 0;
74  uint16_t best_yc = 0;
75  uint16_t s = 0;
76  sizes[0] = 100; //sizes[1] = 40; sizes[2] = 50; sizes[3] = 60;
77 
78  for (s = 0; s < N_WINDOW_SIZES; s++) {
79 
80  // coordinate will contain the coordinate, best_response will be the best match * 100
81  calculate_integral_image = (s == 0); // only calculate the integal image for the first window size
82  best_response[s] = detect_window_one_size(in, image_width, image_height, coordinate, &sizes[s],
83  calculate_integral_image, integral_image, MODE);
84  if (s == 0 || best_response[s] < best_response[best_index]) {
85  best_index = s;
86  best_xc = coordinate[0];
87  best_yc = coordinate[1];
88  }
89  }
90 
91  coordinate[0] = best_xc;
92  coordinate[1] = best_yc;
93  return best_response[best_index];
94 }
95 
96 uint16_t detect_window_one_size(uint8_t *in, uint32_t image_width, uint32_t image_height, uint16_t *coordinate,
97  uint16_t *size, uint8_t calculate_integral_image, uint32_t *integral_image, uint8_t MODE)
98 {
99  /*
100  * Steps:
101  * (0) filter out the bad pixels (i.e., those lower than 4) and replace them with a disparity of 6.
102  * (1) get integral image (if calculate_integral_image == 1)
103  * (2) determine responses per location while determining the best-matching location (put it in coordinate)
104  */
105 
106  // output of the function:
107  uint16_t min_response = RES;
108 
109  // parameters:
110  //uint16_t image_border = 10;
111  uint16_t window_size, border_size, feature_size, px_whole, px_inner, px_border, px_outer;
112  uint16_t relative_border = 15; // border in percentage of window size
113 
114  // declaration other vars:
115  uint16_t x, y;
116  uint32_t response;
117 
118  // (1) get integral image (if calculate_integral_image == 1)
119 
120  if (calculate_integral_image) {
121  get_integral_image(in, image_width, image_height, integral_image);
122  }
123 
124  // window size is without border, feature size is with border:
125  window_size = (*size);
126  border_size = (relative_border * window_size) / 100; // percentage
127  feature_size = window_size + 2 * border_size;
128  px_inner = feature_size - 2 * border_size;
129  px_inner = px_inner * px_inner;
130  px_whole = feature_size * feature_size;
131  px_border = px_whole - px_inner;
132  px_outer = border_size * window_size;
133 
134  // (2) determine a response map for that size
135  for (x = 0; x < image_width - feature_size; x++) {
136  for (y = 0; y < image_height - feature_size; y++) {
137  response = get_window_response(x, y, feature_size, border_size, integral_image, image_width, image_height, px_inner,
138  px_border, MODE);
139 
140  if (response < RES) {
141  if (MODE == MODE_DARK) {
142  // the inside is further away than the outside, perform the border test:
143  response = get_border_response(x, y, feature_size, window_size, border_size, integral_image, image_width, image_height,
144  px_inner, px_outer);
145  }
146 
147  if (response < min_response) {
148  coordinate[0] = x;
149  coordinate[1] = y;
150  min_response = response;
151  }
152  } else {
153  //in[x+y*image_width] = 255;
154 
155  }
156  }
157  }
158 
159  // the coordinate is at the top left corner of the feature,
160  // the center of the window is then at:
161  coordinate[0] += feature_size / 2;
162  coordinate[1] += feature_size / 2;
163 
164  return min_response;
165 }
166 
167 // this function can help if the window is not visible anymore:
168 uint16_t detect_escape(uint8_t *in __attribute__((unused)), uint32_t image_width, uint32_t image_height, uint16_t *escape_coordinate,
169  uint32_t *integral_image, uint8_t n_cells)
170 {
171  uint16_t c, r, min_c, min_r;
172  uint16_t cell_width, cell_height;
173  uint32_t min_avg = 10000;
174  uint32_t avg;
175  uint16_t border = 10;
176  cell_width = (image_width - 2 * border) / n_cells;
177  cell_height = (image_height - 2 * border) / n_cells;
178  // Get the average disparities of all cells in a grid:
179  for (c = 0; c < n_cells; c++) {
180  for (r = 0; r < n_cells; r++) {
181  avg = get_avg_disparity(c * cell_width + border, r * cell_height + border, (c + 1) * cell_width + border,
182  (r + 1) * cell_height + border, integral_image, image_width, image_height);
183  if (avg < min_avg) {
184  min_avg = avg;
185  min_c = c;
186  min_r = r;
187  }
188  }
189  }
190  // return coordinates for the best option:
191  if (min_avg == 10000) {
192  escape_coordinate[0] = image_width / 2;
193  escape_coordinate[1] = image_height / 2;
194  } else {
195  escape_coordinate[0] = min_c * cell_width + border + cell_width / 2;
196  escape_coordinate[1] = min_r * cell_height + border + cell_height / 2;
197  }
198 
199  return min_avg;
200 }
201 
202 void get_integral_image(uint8_t *in, uint32_t image_width, uint32_t image_height, uint32_t *integral_image)
203 {
204  uint16_t x, y;
205  for (x = 0; x < image_width; x++) {
206  for (y = 0; y < image_height; y++) {
207  if (x >= 1 && y >= 1) {
208  integral_image[x + y * image_width] = (uint32_t) in[x + y * image_width] + integral_image[x - 1 + y * image_width] +
209  integral_image[x + (y - 1) * image_width] - integral_image[x - 1 + (y - 1) * image_width];
210  } else if (x >= 1) {
211  integral_image[x + y * image_width] = (uint32_t) in[x + y * image_width] + integral_image[x - 1 + y * image_width];
212  } else if (y >= 1) {
213  integral_image[x + y * image_width] = (uint32_t) in[x + y * image_width] + integral_image[x + (y - 1) * image_width];
214  } else {
215  integral_image[x + y * image_width] = (uint32_t) in[x + y * image_width];
216  }
217  }
218  }
219 }
220 
221 uint32_t get_sum_disparities(uint16_t min_x, uint16_t min_y, uint16_t max_x, uint16_t max_y, uint32_t *integral_image,
222  uint32_t image_width, uint32_t image_height)
223 {
224  uint32_t sum;
225  // If variables are not unsigned, then check for negative inputs
226  // if (min_x + min_y * image_width < 0) { return 0; }
227  if (max_x + max_y * image_width >= image_width * image_height) { return 0; }
228  sum = integral_image[min_x + min_y * image_width] + integral_image[max_x + max_y * image_width] -
229  integral_image[max_x + min_y * image_width] - integral_image[min_x + max_y * image_width];
230  return sum;
231 }
232 
233 uint32_t get_avg_disparity(uint16_t min_x, uint16_t min_y, uint16_t max_x, uint16_t max_y, uint32_t *integral_image,
234  uint32_t image_width, uint32_t image_height __attribute__((unused)))
235 {
236  uint16_t w, h;
237  uint32_t sum, avg, n_pix;
238 
239  // width and height of the window
240  w = max_x - min_x + 1;
241  h = max_y - min_y + 1;
242  n_pix = w * h;
243  // sum over the area:
244  sum = integral_image[min_x + min_y * image_width] + integral_image[max_x + max_y * image_width] -
245  integral_image[max_x + min_y * image_width] - integral_image[min_x + max_y * image_width];
246  // take the average, scaled by RES:
247  avg = (sum * RES) / n_pix;
248  return avg;
249 }
250 
251 
252 uint16_t get_window_response(uint16_t x, uint16_t y, uint16_t feature_size, uint16_t border, uint32_t *integral_image,
253  uint16_t image_width, uint16_t image_height, uint16_t px_inner, uint16_t px_border, uint8_t MODE)
254 {
255  uint32_t whole_area, inner_area, resp;
256 
257  whole_area = get_sum_disparities(x, y, x + feature_size, y + feature_size, integral_image, image_width, image_height);
258 
259  inner_area = get_sum_disparities(x + border, y + border, x + feature_size - border, y + feature_size - border,
260  integral_image, image_width, image_height);
261 
262  if (MODE == MODE_DARK) {
263  if (whole_area - inner_area > 0) {
264  resp = (inner_area * RES * px_border) / ((whole_area - inner_area) * px_inner);
265  } else {
266  resp = RES;
267  }
268  } else { //if(MODE == MODE_BRIGHT)
269  if (inner_area > 0 && (inner_area / px_inner) > 0) {
270  resp = (RES * (whole_area - inner_area) / px_border) / (inner_area / px_inner);
271  //printf("%u: %u %u %u %u\n",resp,(RES*RES*(whole_area - inner_area)/px_border), (inner_area/px_inner), px_inner, px_border);
272  } else {
273  resp = RES;
274  }
275  }
276 
277 
278  return resp;
279 }
280 
281 uint16_t get_border_response(uint16_t x, uint16_t y, uint16_t feature_size, uint16_t window_size, uint16_t border,
282  uint32_t *integral_image, uint16_t image_width, uint16_t image_height, uint16_t px_inner, uint16_t px_outer)
283 {
284  uint32_t inner_area, avg_inner, left_area, right_area, up_area, down_area, darkest, avg_dark, resp;
285  // inner area
286  inner_area = get_sum_disparities(x + border, y + border, x + feature_size - border, y + feature_size - border,
287  integral_image, image_width, image_height);
288  avg_inner = (RES * inner_area) / px_inner;
289  // outer areas:
290  left_area = get_sum_disparities(x, y + border, x + border, y + border + window_size, integral_image, image_width,
291  image_height);
292  right_area = get_sum_disparities(x + border + window_size, y + border, x + 2 * border + window_size,
293  y + border + window_size, integral_image, image_width, image_height);
294  up_area = get_sum_disparities(x + border, y, x + border + window_size, y + border, integral_image, image_width,
295  image_height);
296  down_area = get_sum_disparities(x + border, y + border + window_size, x + border + window_size,
297  y + 2 * border + window_size, integral_image, image_width, image_height);
298  // darkest outer area:
299  darkest = (left_area < right_area) ? left_area : right_area;
300  darkest = (darkest < up_area) ? darkest : up_area;
301  darkest = (darkest < down_area) ? darkest : down_area;
302  avg_dark = RES * darkest / px_outer;
303  if (avg_dark < avg_inner) {
304  resp = RES;
305  } else {
306  if (avg_dark == 0) {
307  resp = RES;
308  } else {
309  resp = RES * avg_inner / avg_dark;
310  }
311  }
312 
313  return resp;
314 }
315 
316 void filter_bad_pixels(uint8_t *in, uint32_t image_width, uint32_t image_height)
317 {
318  uint16_t x, y;
319  for (x = 0; x < image_width; x++) {
320  for (y = 0; y < image_height; y++) {
321  if (in[x + y * image_width] < 4) {
322  in[x + y * image_width] = 6;
323  }
324  }
325  }
326 }
327 
328 
329 void transform_illuminance_image(uint8_t *in, uint8_t *out, uint32_t image_width, uint32_t image_height, uint8_t n_bits,
330  uint8_t bright_win)
331 {
332  uint16_t x, y;
333  for (x = 0; x < image_width; x++) {
334  for (y = 0; y < image_height; y++) {
335  // we put the right image entirely in the left image instead of in the even rows:
336  if (!bright_win) {
337  out[x + y * image_width] = in[2 * (x + y * image_width)] >> n_bits;
338  } else {
339  out[x + y * image_width] = (255 - in[2 * (x + y * image_width)]) >> n_bits;
340  }
341  }
342  }
343 }
void filter_bad_pixels(uint8_t *in, uint32_t image_width, uint32_t image_height)
unsigned short uint16_t
Definition: types.h:16
struct image_t * detect_window(struct image_t *img)
Definition: detect_window.c:44
#define N_WINDOW_SIZES
Definition: detect_window.c:28
#define MODE_BRIGHT
Definition: detect_window.h:33
uint16_t detect_window_sizes(uint8_t *in, uint32_t image_width, uint32_t image_height, uint16_t *coordinate, uint32_t *integral_image, uint8_t MODE)
Definition: detect_window.c:65
void image_free(struct image_t *img)
Free the image.
Definition: image.c:63
void image_create(struct image_t *img, uint16_t width, uint16_t height, enum image_type type)
Create a new image.
Definition: image.c:38
Definition: image.h:43
#define RES
Definition: detect_window.c:27
#define MODE_DARK
Definition: detect_window.h:32
uint16_t detect_escape(uint8_t *in, uint32_t image_width, uint32_t image_height, uint16_t *escape_coordinate, uint32_t *integral_image, uint8_t n_cells)
struct video_listener * cv_add_to_device(struct video_config_t *device, cv_function func, uint16_t fps)
Definition: cv.c:46
uint16_t get_border_response(uint16_t x, uint16_t y, uint16_t feature_size, uint16_t window_size, uint16_t border, uint32_t *integral_image, uint16_t image_width, uint16_t image_height, uint16_t px_inner, uint16_t px_outer)
uint16_t get_window_response(uint16_t x, uint16_t y, uint16_t feature_size, uint16_t border, uint32_t *integral_image, uint16_t image_width, uint16_t image_height, uint16_t px_inner, uint16_t px_border, uint8_t MODE)
uint16_t w
Image width.
Definition: image.h:45
uint16_t detect_window_one_size(uint8_t *in, uint32_t image_width, uint32_t image_height, uint16_t *coordinate, uint16_t *size, uint8_t calculate_integral_image, uint32_t *integral_image, uint8_t MODE)
Definition: detect_window.c:96
unsigned long uint32_t
Definition: types.h:18
uint16_t h
Image height.
Definition: image.h:46
void * buf
Image buffer (depending on the image_type)
Definition: image.h:53
void transform_illuminance_image(uint8_t *in, uint8_t *out, uint32_t image_width, uint32_t image_height, uint8_t n_bits, uint8_t bright_win)
void get_integral_image(uint8_t *in, uint32_t image_width, uint32_t image_height, uint32_t *integral_image)
void image_to_grayscale(struct image_t *input, struct image_t *output)
Convert an image to grayscale.
Definition: image.c:116
static void h(const real32_T x[7], const real32_T q[4], real32_T y[6])
unsigned char uint8_t
Definition: types.h:14
#define DETECT_WINDOW_FPS
Default FPS (zero means run at camera fps)
Definition: detect_window.c:31
uint32_t get_sum_disparities(uint16_t min_x, uint16_t min_y, uint16_t max_x, uint16_t max_y, uint32_t *integral_image, uint32_t image_width, uint32_t image_height)
void detect_window_init(void)
Definition: detect_window.c:39
Grayscale image with only the Y part (uint8 per pixel)
Definition: image.h:37
Detect a bright region surrounded by dark or viceversa - sometimes this corresponds to a window...
uint32_t get_avg_disparity(uint16_t min_x, uint16_t min_y, uint16_t max_x, uint16_t max_y, uint32_t *integral_image, uint32_t image_width, uint32_t image_height)