52 #define SUCCESS_DETECT 1
56 #define FILTER_IMAGE 0
86 int cmpfunc(
const void *a,
const void *b);
87 int cmp_i(
const void *a,
const void *b);
92 return (*(
const int *)a - * (
const int *)b);
96 int cmp_i(
const void *a,
const void *b)
98 int ia = *(
const int *)a;
99 int ib = *(
const int *)b;
141 static int last_frame_detection = 0;
142 static int repeat_gate = 0;
143 static struct gate_img previous_best_gate = {0};
146 bool check_initial_square =
false;
147 float iou_threshold = 0.7;
206 y = (y_high + y_low) / 2;
220 szx1 = (x_high1 - x_low1);
221 szx2 = (x_high2 - x_low2);
226 x = (x_high1 + x_low1) / 2;
228 sz = (sz > szx1) ? sz : szx1;
231 x = (x_high2 + x_low2) / 2;
233 sz = (sz > szx2) ? sz : szx2;
238 gates_c[(*n_gates)].
x =
x;
239 gates_c[(*n_gates)].
y =
y;
241 gates_c[(*n_gates)].
sz = sz / 2;
243 if (check_initial_square) {
251 gates_c[(*n_gates)].
x_corners[0] = x_low2;
253 gates_c[(*n_gates)].
x_corners[1] = x_high2;
257 gates_c[(*n_gates)].
x_corners[2] = x_high1;
259 gates_c[(*n_gates)].
x_corners[3] = x_low1;
274 bool add_gate =
true;
276 for (
int g = 0; g < (*n_gates); g++) {
278 gates_c[(*n_gates)].y_corners);
279 if (iou > iou_threshold) {
290 gates_c[g].
x = gates_c[(*n_gates)].
x;
291 gates_c[g].
y = gates_c[(*n_gates)].
y;
292 gates_c[g].
sz = gates_c[(*n_gates)].
sz;
294 memcpy(gates_c[g].x_corners, gates_c[(*n_gates)].x_corners,
sizeof(
int) * 4);
295 memcpy(gates_c[g].y_corners, gates_c[(*n_gates)].y_corners,
sizeof(
int) * 4);
312 #ifdef DEBUG_SNAKE_GATE
314 printf(
"(*n_gates):%d\n", (*n_gates));
315 for (
int i = 0; i < (*n_gates); i++) {
329 if ((
best_quality > min_gate_quality && (*n_gates) > 0) || last_frame_detection) {
332 for (
int gate_nr = 0; gate_nr < (*n_gates); gate_nr++) {
342 sz1g = (float) (gates_c[gate_nr].x_corners[1] - gates_c[gate_nr].x_corners[0]);
343 sz2g = (float) (gates_c[gate_nr].y_corners[1] - gates_c[gate_nr].y_corners[2]);
347 static float limit_ratio = 1.5;
348 if(sz1g > 0.1 && sz2g > 0.1) {
349 ratio = (sz1g >= sz2g) ? sz1g / sz2g : sz2g / sz1g;
352 ratio = limit_ratio + 0.1;
359 if (sz1g*sz2g > sz1*sz2 && gates_c[gate_nr].quality > min_gate_quality * 2 && gates_c[gate_nr].n_sides >= min_n_sides && ratio <= limit_ratio) {
361 best_gate->
x = gates_c[gate_nr].
x;
362 best_gate->
y = gates_c[gate_nr].
y;
363 best_gate->
sz = gates_c[gate_nr].
sz;
377 if ((best_gate->
quality == 0 && best_gate->
n_sides == 0) && last_frame_detection == 1) {
383 memcpy(x_values, last_gate.
x_corners,
sizeof(x_values));
384 memcpy(y_values, last_gate.
y_corners,
sizeof(y_values));
386 qsort(x_values, 4,
sizeof(
int),
cmpfunc);
387 qsort(y_values, 4,
sizeof(
int),
cmpfunc);
389 int radius_p = x_values[3] - x_values[0];
406 #ifdef DEBUG_SNAKE_GATE
413 previous_best_gate.
x = best_gate->
x;
414 previous_best_gate.
y = best_gate->
y;
415 previous_best_gate.
sz = best_gate->
sz;
428 if (best_gate->
quality > (min_gate_quality * 2) && best_gate->
n_sides >= min_n_sides) {
430 last_frame_detection = 1;
434 for (
int gate_nr = 0; gate_nr < (*n_gates); gate_nr++) {
435 if (gates_c[gate_nr].
n_sides >= min_n_sides && gates_c[gate_nr].
quality > 2 * min_gate_quality) {
442 int size_crosshair = 10;
443 if (repeat_gate == 0) {
445 }
else if (repeat_gate == 1) {
447 for (
int i = 0; i < 3; i++) {
457 last_gate.
x = best_gate->
x;
458 last_gate.
y = best_gate->
y;
459 last_gate.
sz = best_gate->
sz;
466 last_frame_detection = 0;
552 from.
y = gate.
x - gate.
sz;
554 to.
y = gate.
x - gate.
sz;
557 from.
y = gate.
x - gate.
sz;
559 to.
y = gate.
x + gate.
sz;
562 from.
y = gate.
x + gate.
sz;
564 to.
y = gate.
x + gate.
sz;
567 from.
y = gate.
x + gate.
sz;
569 to.
y = gate.
x - gate.
sz;
583 int n_points, n_colored_points;
585 n_colored_points = 0;
590 float min_ratio_side = 0.4;
603 if ((
float) nc / (
float) np >= min_ratio_side &&
segment_length(from, to) > min_segment_length) {
607 n_colored_points += nc;
614 if ((
float) nc / (
float) np >= min_ratio_side &&
segment_length(from, to) > min_segment_length) {
618 n_colored_points += nc;
625 if ((
float) nc / (
float) np >= min_ratio_side &&
segment_length(from, to) > min_segment_length) {
629 n_colored_points += nc;
636 if ((
float) nc / (
float) np >= min_ratio_side &&
segment_length(from, to) > min_segment_length) {
641 n_colored_points += nc;
647 (*quality) = ((float) n_colored_points) / ((float) n_points);
652 static int n_samples_in = 100;
653 static float center_discard_threshold = 0.25;
655 float center_factor =
check_inside(im, gate.
x, gate.
y, gate.
sz, n_samples_in);
656 if (center_factor > center_discard_threshold) {
675 int n_points, n_colored_points;
677 n_colored_points = 0;
681 float min_ratio_side = 0.30;
687 from.
x = gate.
x - gate.
sz;
689 to.
x = gate.
x - gate.
sz;
692 if ((
float) nc / (
float) np >= min_ratio_side) {
696 n_colored_points += nc;
698 from.
x = gate.
x - gate.
sz;
700 to.
x = gate.
x + gate.
sz;
703 if ((
float) nc / (
float) np >= min_ratio_side) {
707 n_colored_points += nc;
709 from.
x = gate.
x + gate.
sz;
711 to.
x = gate.
x + gate.
sz;
714 if ((
float) nc / (
float) np >= min_ratio_side) {
718 n_colored_points += nc;
720 from.
x = gate.
x + gate.
sz;
722 to.
x = gate.
x - gate.
sz;
725 if ((
float) nc / (
float) np >= min_ratio_side) {
730 n_colored_points += nc;
737 (*quality) = ((float) n_colored_points) / ((float) n_points);
741 int n_samples_in = 100;
742 float center_discard_threshold = 0.25;
743 float center_factor =
check_inside(im, gate.
x, gate.
y, gate.
sz, n_samples_in);
744 if (center_factor > center_discard_threshold) {
763 int num_color_center = 0;
770 for (
int i = 0; i < n_samples_in; i++) {
772 int x_in = x + (rand() % sz) - (0.5 * sz);
773 int y_in = y + (rand() % sz) - (0.5 * sz);
775 if (y_in >= 0 && y_in < im->w && x_in >= 0 && x_in < im->
h) {
785 if (n_samples == 0) {
789 float center_factor = 0;
790 if (n_samples != 0) {
791 center_factor = num_color_center / (float)n_samples;
793 return center_factor;
805 float r = sqrtf((Q1.
x - Q2.
x) * (Q1.
x - Q2.
x) + (Q1.
y - Q2.
y) * (Q1.
y - Q2.
y));
822 (*n_colored_points) = 0;
829 for (t = 0.0f; t < 1.0f; t += t_step) {
831 x = (int)(t * Q1.
x + (1.0f - t) * Q2.
x);
832 y = (int)(t * Q1.
y + (1.0f - t) * Q2.
y);
835 if (x >= 0 && x < im->
h && y >= 0 && y < im->w) {
841 (*n_colored_points)++;
867 while ((*y_low) > 0 && !done) {
888 while ((*y_high) < im->
w - 1 && !done) {
926 while ((*x_low) > 0 && !done) {
947 while ((*x_high) < im->
h - 1 && !done) {
997 float corner_area = 0.3f;
1016 float x_corner_f = (float)(*corner_x);
1017 float y_corner_f = (float)(*corner_y);
1018 float size_f = (float)size;
1021 int x_l = (int)(x_corner_f - size_f * size_factor);
1022 Bound(x_l, 0, im->
h);
1023 int x_r = (int)(x_corner_f + size_f * size_factor);
1024 Bound(x_r, 0, im->
h);
1025 int y_h = (int)(y_corner_f + size_f * size_factor);
1026 Bound(y_h, 0, im->
w);
1027 int y_l = (int)(y_corner_f - size_f * size_factor);
1028 Bound(y_l, 0, im->
w);
1031 #ifdef DEBUG_SNAKE_GATE
1045 int x_size = x_r - x_l + 1;
1046 int y_size = y_h - y_l + 1;
1050 memset(x_hist, 0,
sizeof(
int)*x_size);
1051 memset(y_hist, 0,
sizeof(
int)*y_size);
1055 int best_x_loc = x_l;
1056 int x_best_start = x_l;
1058 int best_y_loc = y_l;
1059 int y_best_start = y_l;
1062 for (
int y_pix = y_l; y_pix < y_h; y_pix++) {
1063 for (
int x_pix = x_l; x_pix < x_r; x_pix++) {
1066 int cur_x = x_hist[x_pix - x_l];
1067 int cur_y = y_hist[y_pix - y_l];
1068 x_hist[x_pix - x_l] = cur_x + 1;
1069 y_hist[y_pix - y_l] = cur_y + 1;
1071 if (x_hist[x_pix - x_l] > best_x) {
1072 best_x = x_hist[x_pix - x_l];
1074 x_best_start = x_pix;
1075 }
else if (cur_x == best_x) {
1076 best_x_loc = (x_pix + x_best_start) / 2;
1078 if (y_hist[y_pix - y_l] > best_y) {
1079 best_y = y_hist[y_pix - y_l];
1081 y_best_start = y_pix;
1082 }
else if (cur_y == best_y) {
1083 best_y_loc = (y_pix + y_best_start) / 2;
1091 *corner_x = best_x_loc;
1092 *corner_y = best_y_loc;
1142 int w1, h1, w2, h2, un;
1143 w1 = x_box_1[1] - x_box_1[0];
1144 h1 = y_box_1[0] - y_box_1[2];
1145 w2 = x_box_2[1] - x_box_2[0];
1146 h2 = y_box_2[0] - y_box_2[2];
1147 un = w1 * h1 + w2 * h2 - intersection;
1153 iou = (float) intersection / (
float) un;
1173 return width * height;
1188 if (val_low_2 < val_low_1) {
1189 if (val_high_2 < val_low_1) {
1192 min_val = (val_high_1 > val_high_2) ? val_high_2 : val_high_1;
1193 overlap = min_val - val_low_1;
1196 if (val_high_1 < val_low_2) {
1199 min_val = (val_high_1 > val_high_2) ? val_high_2 : val_high_1;
1200 overlap = min_val - val_low_2;
struct image_t img_result
void check_gate_outline(struct image_t *im, struct gate_img gate, float *quality, int *n_sides)
Check only the outline of the gate.
int intersection_boxes(int x_box_1[4], int y_box_1[4], int x_box_2[4], int y_box_2[4])
struct gate_img best_gate
int cmp_i(const void *a, const void *b)
struct gate_img gates_c[MAX_GATES]
int overlap_intervals(int val_low_1, int val_high_1, int val_low_2, int val_high_2)
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.
void snake_left_and_right(struct image_t *im, int x, int y, int *x_low, int *y_low, int *x_high, int *y_high)
The actual snaking.
float sz_right
Half the image size of the right side.
void check_line(struct image_t *im, struct point_t Q1, struct point_t Q2, int *n_points, int *n_colored_points)
Checks whether points on a line between two 2D-points are of a given color.
int cmpfunc(const void *a, const void *b)
uint32_t x
The x coordinate of the point.
float intersection_over_union(int x_box_1[4], int y_box_1[4], int x_box_2[4], int y_box_2[4])
void draw_gate_color_polygon(struct image_t *im, struct gate_img gate, uint8_t *color)
Draw the gate on an image, using the corner points, possibly resulting in a polygon.
void check_gate_initial(struct image_t *im, struct gate_img gate, float *quality, int *n_sides)
Check the outline and the center of the gate.
Image helper functions like resizing, color filter, converters...
Detects gates as used in the IROS drone races, i.e., square colored gates.
int snake_gate_detection(struct image_t *img, int n_samples, int min_px_size, float min_gate_quality, float gate_thickness, int min_n_sides, uint8_t color_Ym, uint8_t color_YM, uint8_t color_Um, uint8_t color_UM, uint8_t color_Vm, uint8_t color_VM, struct gate_img *best_gate, struct gate_img *gates_c, int *n_gates, int exclude_top, int exclude_bottom)
Run snake gate detection on an image.
int n_sides
How many sides are orange (to prevent detecting a small gate in the corner of a big one partially out...
void draw_gate_color_square(struct image_t *im, struct gate_img gate, uint8_t *color)
Draw the gate on an image, using only the center coordinate and sizes - resulting in a square gate...
void set_gate_points(struct gate_img *gate)
Determine and set the corner locations in gate.x_corners, g.y_corners, based on the center of the gat...
int y
The image y coordinate of the gate center.
float quality
gate quality
void gate_refine_corners(struct image_t *color_image, int *x_points, int *y_points, int size)
Refine the four corners of the gate, based on the color around the supposed corner locations...
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.
void draw_gate(struct image_t *im, struct gate_img gate)
Draw the gate on an image.
uint32_t y
The y coordinate of the point.
int x
The image x coordinate of the gate center.
struct gate_img temp_check_gate
void refine_single_corner(struct image_t *im, int *corner_x, int *corner_y, int size, float size_factor)
Refine a single corner, based on the color around the coordinate.
static void h(const real32_T x[7], const real32_T q[4], real32_T y[6])
int x_corners[4]
Array of corner x coordinates.
float sz_left
Half the image size of the left side.
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.
int y_corners[4]
Array of corner y coordinates.
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.
void snake_up_and_down(struct image_t *im, int x, int y, int *x_low, int *y_low, int *x_high, int *y_high)
The actual snaking.
int check_color_snake_gate_detection(struct image_t *im, int x, int y)
float check_inside(struct image_t *im, int x, int y, int sz, int n_samples_in)
float segment_length(struct point_t Q1, struct point_t Q2)
Determine the segment length between two 2D-points.
int sz
Half the image size of the gate.