2 * @file shape_detect.cc
14 #include "shape_detect.h"
17 void Shape_detect::plot_line(std::vector<Shape_detect::Line> &lines)
19 fprintf(gnuplot, "set style line 1 pt 1 lc rgb \"green\"\n");
20 fprintf(gnuplot, "set style line 2 lt 2 lc rgb \"red\" lw 2\n");
21 fprintf(gnuplot, "set style line 3 pt 2 lc rgb \"blue\"\n");
24 fprintf(gnuplot, "plot");
26 fprintf(gnuplot, "plot [-1000:+3000] [-3000:+3000]");
28 fprintf(gnuplot, "'-' with points ls 1, "); // points
29 fprintf(gnuplot, "'-' with linespoints ls 2,"); // lines
30 fprintf(gnuplot, "'-' with points ls 3"); //arc point
31 fprintf(gnuplot, "\n");
34 for (int i = 0; i < (int) cartes.size(); i++) {
35 fprintf(gnuplot, "%g %g\n", cartes[i].x, cartes[i].y);
37 fprintf(gnuplot, "e\n");
40 for (int i = 0; i < (int) lines.size(); i++) {
41 fprintf(gnuplot, "%f %f\n%f %f\n\n",
42 lines[i].a.x, lines[i].a.y, lines[i].b.x, lines[i].b.y);
44 fprintf(gnuplot, "e\n");
47 void Shape_detect::plot_arc(std::vector<Shape_detect::Arc> &arcs)
50 for (int i = 0; i < (int) arcs.size(); i++) {
51 fprintf(gnuplot, "%g %g\n", arcs[i].begin.x, arcs[i].begin.y);
52 fprintf(gnuplot, "%g %g\n", arcs[i].end.x, arcs[i].end.y);
54 fprintf(gnuplot, "e\n");
59 void Shape_detect::plot_close()
66 void Shape_detect::plot_init()
68 gnuplot = popen("gnuplot", "w");
69 fprintf(gnuplot, "set grid\n");
70 fprintf(gnuplot, "set nokey\n");
72 fprintf(gnuplot, "set size ratio 1\n"); //1.3333
77 Shape_detect::Shape_detect()
79 Shape_detect::Line_min_points = 7;
80 Shape_detect::Line_error_threshold = 20;
81 Shape_detect::Max_distance_point = 300;
83 Shape_detect::Arc_std_max = 0.2;//0.15
84 Shape_detect::Arc_min_aperture = 1.57; //90 degrees
85 Shape_detect::Arc_max_aperture = 2.365; //2.365 #135 degrees
88 Shape_detect::Shape_detect(int line_min_points, int line_error_threshold, int max_distance_point)
90 Shape_detect::Line_min_points = line_min_points;
91 Shape_detect::Line_error_threshold = line_error_threshold;
92 Shape_detect::Max_distance_point = max_distance_point;
95 inline Shape_detect::Point Shape_detect::intersection_line(const Shape_detect::Point point, const General_form gen)
97 Shape_detect::Point tmp;
99 tmp.x = (gen.b*gen.b*point.x - gen.a*gen.b*point.y - gen.a*gen.c) / (gen.a*gen.a + gen.b*gen.b);
100 tmp.y = (gen.b*tmp.x - gen.b*point.x + gen.a*point.y) / gen.a;
105 inline Shape_detect::Point Shape_detect::rotate(Shape_detect::Point input_point, float rad)
107 Shape_detect::Point tmp;
108 tmp.x = input_point.x * cos(rad) - input_point.y * sin(rad);
109 tmp.y = input_point.x * sin(rad) + input_point.y * cos(rad);
114 inline float Shape_detect::point_distance(Shape_detect::Point a, Shape_detect::Point b)
116 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
119 bool Shape_detect::fit_arc(int begin, int end, std::vector<Shape_detect::Arc> &arcs)
121 //std::cout << "rozsah: " << begin << " - " << end << " -> ";
124 //std::cout << "mensi nez 4" << std::endl;
128 Point rotated_point = cartes[(end + begin) / 2];
129 Point right = cartes[begin];
130 Point left = cartes[end];
131 rotated_point.x = rotated_point.x - left.x;
132 rotated_point.y = rotated_point.y - left.y;
133 float angle_to_rotate = atan2((left.x - right.x) / (left.y - right.y),1);
134 rotated_point = rotate(rotated_point, angle_to_rotate);
136 //std::cout << "rotacni bod: " << rotated_point.x << ", " << rotated_point.y << "; vzdalenost: " << Shape_detect::point_distance(left, right) << "; ";
138 if (-rotated_point.x < .1 * Shape_detect::point_distance(left, right) &&
139 -rotated_point.x > Shape_detect::point_distance(left, right)) {
140 //std::cout << "rotacni bod" << "; ";
144 int segment_size = end - begin + 1;
145 int slopes_size = segment_size - 3;
147 float ma, mb, slopes[slopes_size];
149 for (int i = 0; i < slopes_size; i++) {
150 Shape_detect::Point tmp = cartes[begin + i + 1];
151 ma = atan2(left.y - tmp.y, left.x - tmp.x);
152 mb = atan2(right.y - tmp.y, right.x - tmp.x);
158 for (int i = 0; i < slopes_size; i++)
159 sum = sum + slopes[i];
161 float average = sum / slopes_size;
164 int count = slopes_size;
168 totalvar = totalvar + ((slopes[count] - average) * (slopes[count] - average));
171 float standard_deviation = sqrt(totalvar / --slopes_size);
173 //std::cout << "std: " << standard_deviation << ", Average: " << average << ": ";
175 if (standard_deviation < Arc_std_max && Arc_max_aperture > abs(average) && abs(average) > Arc_min_aperture) {
176 Shape_detect::Point tmp;
177 tmp.x = right.x - left.x;
178 tmp.y = right.y - left.y;
180 angle_to_rotate = atan2(tmp.y, tmp.x);
182 tmp = Shape_detect::rotate(tmp, -angle_to_rotate);
184 float middle = tmp.x / 2.0;
185 float height = middle * tan(average - M_PI / 2.0);
187 Shape_detect::Point center;
191 center = Shape_detect::rotate(center, angle_to_rotate);
192 center.x = center.x + left.x;
193 center.y = center.y + left.y;
195 Shape_detect::Arc arc;
197 arc.begin = cartes[begin];
198 arc.end = cartes[end];
201 for (int i = 0; i < segment_size; i++) {
202 tmp.x = cartes[begin + i].x;
203 tmp.y = cartes[begin + i].y;
204 arc.radius = arc.radius + float(sqrt((tmp.x - center.x)*(tmp.x - center.x)+(tmp.y - center.y)*(tmp.y - center.y)));
207 arc.radius = arc.radius / segment_size;
211 //std::cout << "center: " << center.x << "; " << center.y << " >> ";
213 //std::cout << "Detekovan" << std::endl;
217 //fit_arc(begin + 1, end - 1, arcs);
219 //std::cout << "Nic" << std::endl;
224 int Shape_detect::perpendicular_regression(float &r, const int begin, const int end, General_form &gen)
226 int number_points = abs(end-begin) + 1;
228 if (number_points <= 0) return 1;
233 for (int i = begin; i <= end; i++) {
234 sum_x = sum_x + cartes[i].x;
235 sum_y = sum_y + cartes[i].y;
238 float med_x = sum_x / number_points;
239 float med_y = sum_y / number_points;
241 Shape_detect::Point tmp;
246 for (int i = begin; i <= end; i++) {
247 tmp.x = cartes[i].x - med_x;
248 tmp.y = cartes[i].y - med_y;
249 A = A + (tmp.x*tmp.x - tmp.y*tmp.y);
250 sum_xy = sum_xy + tmp.x * tmp.y;
253 if (sum_xy == 0) sum_xy = 1e-8;
257 // tan(q)^2 + A*tan(q) - 1 = 0 ( tan(q) sign as m ) -> quadratic equation
258 float m1 = (-A + sqrt(A*A + 4)) / 2;
259 float m2 = (-A - sqrt(A*A + 4)) / 2;
261 float b1 = med_y - m1*med_x;
262 float b2 = med_y - m2*med_x;
273 for (int i = begin; i < end; i++) {
274 // distance point from the line (A = m1, B = -1, C = b1)
275 dist = fabs( (cartes[i].x*m1 - cartes[i].y + b1) / sqrt(m1*m1 + 1) );
276 dist1 = fabs( (cartes[i].x*m2 - cartes[i].y + b2) / sqrt(m2*m2 + 1) );
303 // line recursive fitting
304 void Shape_detect::line_fitting(int begin, int end, std::vector<Shape_detect::Line> &lines)
306 if ((end - begin) < Shape_detect::Line_min_points) return;
311 if (perpendicular_regression(r, begin, end, gen)) return; // r = 0
313 if (r < Shape_detect::Line_error_threshold) {
314 Shape_detect::Line tmp;
316 tmp.a = intersection_line(cartes[begin], gen);
317 tmp.b = intersection_line(cartes[end], gen);
319 lines.push_back(tmp);
322 // normal vector: n[n_x, -n_y]
324 float n_x = cartes[begin].y - cartes[end].y;
325 float n_y = cartes[begin].x - cartes[end].x;
329 float C = n_y*cartes[end].y - n_x*cartes[end].x;
331 int line_break_point = 0;
332 float dist, dist_max = 0;
334 for (int i = begin; i < end; i++) {
335 // distance point from the line
336 dist = fabs( (cartes[i].x*A + cartes[i].y*B + C) / sqrt(A*A + B*B));
338 if (dist > dist_max) {
340 line_break_point = i;
344 if (dist_max > Shape_detect::Line_error_threshold) {
345 line_fitting(begin, line_break_point, lines);
346 line_fitting(line_break_point, end, lines);
349 } // end if (r <= Line_error_threshold)
354 // polar to cartesian coordinates
355 void Shape_detect::polar_to_cartes(const unsigned short laser_scan[])
357 Shape_detect::Point point;
362 for (int i = 0; i < (int) HOKUYO_ARRAY_SIZE; i++) {
363 r = (laser_scan[i] <= 19) ? 0 : laser_scan[i];
366 fi = HOKUYO_INDEX_TO_RAD(i);
367 point.x = r * cos(fi);
368 point.y = r * sin(fi);
369 cartes.push_back(point);
373 //std::cout << "velikost cartes: " << cartes.size() << std::endl;
377 void Shape_detect::prepare(const unsigned short laser_scan[])
382 polar_to_cartes(laser_scan);
385 void Shape_detect::arc_detect(std::vector<Shape_detect::Arc> &arcs)
387 int cartes_size = cartes.size();
390 while (start < cartes_size) {
393 while (point_distance(cartes[end-1], cartes[end]) < 50 && end < cartes_size)
398 fit_arc(start, end, arcs);
406 void Shape_detect::line_detect(std::vector<Shape_detect::Line> &lines)
408 int cartes_size = cartes.size();
411 while (start < cartes_size) {
414 while (point_distance(cartes[end-1], cartes[end]) < Shape_detect::Max_distance_point && end < cartes_size)
419 line_fitting(start, end, lines);