2 * @file shape_detect.cc
14 #include "shape_detect.h"
17 Shape_detect::Shape_detect()
19 Shape_detect::Line_min_points = 7;
20 Shape_detect::Line_error_threshold = 20;
21 Shape_detect::Max_distance_point = 300;
23 Shape_detect::Arc_std_max = 0.2;//0.15
24 Shape_detect::Arc_min_aperture = 1.57; //90 degrees
25 Shape_detect::Arc_max_aperture = 2.365; //2.365 #135 degrees
28 Shape_detect::Shape_detect(int line_min_points, int line_error_threshold, int max_distance_point)
30 Shape_detect::Line_min_points = line_min_points;
31 Shape_detect::Line_error_threshold = line_error_threshold;
32 Shape_detect::Max_distance_point = max_distance_point;
35 inline Shape_detect::Point Shape_detect::intersection_line(const Shape_detect::Point point, const General_form gen)
37 Shape_detect::Point tmp;
39 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);
40 tmp.y = (gen.b*tmp.x - gen.b*point.x + gen.a*point.y) / gen.a;
45 inline Shape_detect::Point Shape_detect::rotate(Shape_detect::Point input_point, float rad)
47 Shape_detect::Point tmp;
48 tmp.x = input_point.x * cos(rad) - input_point.y * sin(rad);
49 tmp.y = input_point.x * sin(rad) + input_point.y * cos(rad);
54 inline float Shape_detect::point_distance(Shape_detect::Point a, Shape_detect::Point b)
56 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
59 bool Shape_detect::fit_arc(int begin, int end, std::vector<Shape_detect::Arc> &arcs)
61 //std::cout << "rozsah: " << begin << " - " << end << " -> ";
64 //std::cout << "mensi nez 4" << std::endl;
68 Point rotated_point = cartes[(end + begin) / 2];
69 Point right = cartes[begin];
70 Point left = cartes[end];
71 rotated_point.x = rotated_point.x - left.x;
72 rotated_point.y = rotated_point.y - left.y;
73 float angle_to_rotate = atan2((left.x - right.x) / (left.y - right.y),1);
74 rotated_point = rotate(rotated_point, angle_to_rotate);
76 //std::cout << "rotacni bod: " << rotated_point.x << ", " << rotated_point.y << "; vzdalenost: " << Shape_detect::point_distance(left, right) << "; ";
78 if (-rotated_point.x < .1 * Shape_detect::point_distance(left, right) &&
79 -rotated_point.x > Shape_detect::point_distance(left, right)) {
80 //std::cout << "rotacni bod" << "; ";
84 int segment_size = end - begin + 1;
85 int slopes_size = segment_size - 3;
87 float ma, mb, slopes[slopes_size];
89 for (int i = 0; i < slopes_size; i++) {
90 Shape_detect::Point tmp = cartes[begin + i + 1];
91 ma = atan2(left.y - tmp.y, left.x - tmp.x);
92 mb = atan2(right.y - tmp.y, right.x - tmp.x);
98 for (int i = 0; i < slopes_size; i++)
99 sum = sum + slopes[i];
101 float average = sum / slopes_size;
104 int count = slopes_size;
108 totalvar = totalvar + ((slopes[count] - average) * (slopes[count] - average));
111 float standard_deviation = sqrt(totalvar / --slopes_size);
113 //std::cout << "std: " << standard_deviation << ", Average: " << average << ": ";
115 if (standard_deviation < Arc_std_max && Arc_max_aperture > abs(average) && abs(average) > Arc_min_aperture) {
116 Shape_detect::Point tmp;
117 tmp.x = right.x - left.x;
118 tmp.y = right.y - left.y;
120 angle_to_rotate = atan2(tmp.y, tmp.x);
122 tmp = Shape_detect::rotate(tmp, -angle_to_rotate);
124 float middle = tmp.x / 2.0;
125 float height = middle * tan(average - M_PI / 2.0);
127 Shape_detect::Point center;
131 center = Shape_detect::rotate(center, angle_to_rotate);
132 center.x = center.x + left.x;
133 center.y = center.y + left.y;
135 Shape_detect::Arc arc;
137 arc.begin = cartes[begin];
138 arc.end = cartes[end];
141 for (int i = 0; i < segment_size; i++) {
142 tmp.x = cartes[begin + i].x;
143 tmp.y = cartes[begin + i].y;
144 arc.radius = arc.radius + float(sqrt((tmp.x - center.x)*(tmp.x - center.x)+(tmp.y - center.y)*(tmp.y - center.y)));
147 arc.radius = arc.radius / segment_size;
151 //std::cout << "center: " << center.x << "; " << center.y << " >> ";
153 //std::cout << "Detekovan" << std::endl;
157 //fit_arc(begin + 1, end - 1, arcs);
159 //std::cout << "Nic" << std::endl;
164 int Shape_detect::perpendicular_regression(float &r, const int begin, const int end, General_form &gen)
166 int number_points = abs(end-begin) + 1;
168 if (number_points <= 0) return 1;
173 for (int i = begin; i <= end; i++) {
174 sum_x = sum_x + cartes[i].x;
175 sum_y = sum_y + cartes[i].y;
178 float med_x = sum_x / number_points;
179 float med_y = sum_y / number_points;
181 Shape_detect::Point tmp;
186 for (int i = begin; i <= end; i++) {
187 tmp.x = cartes[i].x - med_x;
188 tmp.y = cartes[i].y - med_y;
189 A = A + (tmp.x*tmp.x - tmp.y*tmp.y);
190 sum_xy = sum_xy + tmp.x * tmp.y;
193 if (sum_xy == 0) sum_xy = 1e-8;
197 // tan(q)^2 + A*tan(q) - 1 = 0 ( tan(q) sign as m ) -> quadratic equation
198 float m1 = (-A + sqrt(A*A + 4)) / 2;
199 float m2 = (-A - sqrt(A*A + 4)) / 2;
201 float b1 = med_y - m1*med_x;
202 float b2 = med_y - m2*med_x;
213 for (int i = begin; i < end; i++) {
214 // distance point from the line (A = m1, B = -1, C = b1)
215 dist = fabs( (cartes[i].x*m1 - cartes[i].y + b1) / sqrt(m1*m1 + 1) );
216 dist1 = fabs( (cartes[i].x*m2 - cartes[i].y + b2) / sqrt(m2*m2 + 1) );
243 // line recursive fitting
244 void Shape_detect::line_fitting(int begin, int end, std::vector<Shape_detect::Line> &lines)
246 if ((end - begin) < Shape_detect::Line_min_points) return;
251 if (perpendicular_regression(r, begin, end, gen)) return; // r = 0
253 if (r < Shape_detect::Line_error_threshold) {
254 Shape_detect::Line tmp;
256 tmp.a = intersection_line(cartes[begin], gen);
257 tmp.b = intersection_line(cartes[end], gen);
259 lines.push_back(tmp);
262 // normal vector: n[n_x, -n_y]
264 float n_x = cartes[begin].y - cartes[end].y;
265 float n_y = cartes[begin].x - cartes[end].x;
269 float C = n_y*cartes[end].y - n_x*cartes[end].x;
271 int line_break_point = 0;
272 float dist, dist_max = 0;
274 for (int i = begin; i < end; i++) {
275 // distance point from the line
276 dist = fabs( (cartes[i].x*A + cartes[i].y*B + C) / sqrt(A*A + B*B));
278 if (dist > dist_max) {
280 line_break_point = i;
284 if (dist_max > Shape_detect::Line_error_threshold) {
285 line_fitting(begin, line_break_point, lines);
286 line_fitting(line_break_point, end, lines);
289 } // end if (r <= Line_error_threshold)
294 // polar to cartesian coordinates
295 void Shape_detect::polar_to_cartes(const unsigned short laser_scan[])
297 Shape_detect::Point point;
302 for (int i = 0; i < (int) HOKUYO_ARRAY_SIZE; i++) {
303 r = (laser_scan[i] <= 19) ? 0 : laser_scan[i];
306 fi = HOKUYO_INDEX_TO_RAD(i);
307 point.x = r * cos(fi);
308 point.y = r * sin(fi);
309 cartes.push_back(point);
313 //std::cout << "velikost cartes: " << cartes.size() << std::endl;
317 std::vector<Shape_detect::Point> &Shape_detect::getCartes()
322 void Shape_detect::prepare(const unsigned short laser_scan[])
324 polar_to_cartes(laser_scan);
327 void Shape_detect::arc_detect(std::vector<Shape_detect::Arc> &arcs)
329 int cartes_size = cartes.size();
332 while (start < cartes_size) {
335 while (point_distance(cartes[end-1], cartes[end]) < 50 && end < cartes_size)
340 fit_arc(start, end, arcs);
345 void Shape_detect::line_detect(std::vector<Shape_detect::Line> &lines)
347 int cartes_size = cartes.size();
350 while (start < cartes_size) {
353 while (point_distance(cartes[end-1], cartes[end]) < Shape_detect::Max_distance_point && end < cartes_size)
358 line_fitting(start, end, lines);