Apollo 11.0
自动驾驶开放平台
common.h
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
17#pragma once
18
19#include <algorithm>
20#include <limits>
21#include <vector>
22
23#include "Eigen/Core"
27
28namespace apollo {
29namespace perception {
30namespace algorithm {
31
32// @brief check a point is in polygon or not
33// old name: is_xy_point_in_2d_xy_polygon
34template <typename PointT>
35bool IsPointXYInPolygon2DXY(const PointT &point,
36 const base::PointCloud<PointT> &polygon) {
37 using Type = typename PointT::Type;
38 bool in_poly = false;
39 Type x1 = 0.0;
40 Type x2 = 0.0;
41 Type y1 = 0.0;
42 Type y2 = 0.0;
43 size_t nr_poly_points = polygon.size();
44 if (nr_poly_points < 3) {
45 AINFO << "Polygon points number is smaller than 3.";
46 return false;
47 }
48
49 // start with the last point to make the check last point<->first point the
50 // first one
51 Type xold = polygon.at(nr_poly_points - 1).x;
52 Type yold = polygon.at(nr_poly_points - 1).y;
53 for (size_t i = 0; i < nr_poly_points; ++i) {
54 Type xnew = polygon.at(i).x;
55 Type ynew = polygon.at(i).y;
56 if (xnew > xold) {
57 x1 = xold;
58 x2 = xnew;
59 y1 = yold;
60 y2 = ynew;
61 } else {
62 x1 = xnew;
63 x2 = xold;
64 y1 = ynew;
65 y2 = yold;
66 }
67 // if the point is on the boundary, then it is defined as in the polygon
68 Type value = (point.y - y1) * (x2 - x1) - (y2 - y1) * (point.x - x1);
69 Type temp = std::sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
70 if (temp < std::numeric_limits<Type>::epsilon()) {
71 continue;
72 }
73 Type distance = std::abs(value) / temp;
74 if (x1 <= point.x && point.x <= x2 &&
75 distance < std::numeric_limits<Type>::epsilon()) {
76 return true;
77 }
78 if ((x1 < point.x) == (point.x <= x2) && value < 0.f) {
79 in_poly = !in_poly;
80 }
81 xold = xnew;
82 yold = ynew;
83 }
84 return in_poly;
85}
86
87// @brief check a point is in bounding-box or not
88// old name: is_point_in_boundingbox
89template <typename PointT>
90bool IsPointInBBox(const Eigen::Matrix<typename PointT::Type, 3, 1> &gnd_c,
91 const Eigen::Matrix<typename PointT::Type, 3, 1> &dir_x,
92 const Eigen::Matrix<typename PointT::Type, 3, 1> &dir_y,
93 const Eigen::Matrix<typename PointT::Type, 3, 1> &dir_z,
94 const Eigen::Matrix<typename PointT::Type, 3, 1> &size,
95 const PointT &point) {
96 using T = typename PointT::Type;
97 Eigen::Matrix<T, 3, 1> eig(point.x, point.y, point.z);
98 Eigen::Matrix<T, 3, 1> diff = eig - gnd_c;
99 T x = diff.dot(dir_x);
100 if (fabs(x) > size[0] * 0.5) {
101 return false;
102 }
103 T y = diff.dot(dir_y);
104 if (fabs(y) > size[1] * 0.5) {
105 return false;
106 }
107 T z = diff.dot(dir_z);
108 if (fabs(z) > size[2] * 0.5) {
109 return false;
110 }
111 return true;
112}
113
114// @brief calculate the size and center of the bounding-box of a point cloud
115// old name: compute_bbox_size_center_xy
116template <typename PointCloudT>
118 const PointCloudT &cloud, const Eigen::Vector3f &dir, Eigen::Vector3f *size,
119 Eigen::Vector3d *center,
120 float minimum_edge_length = std::numeric_limits<float>::epsilon()) {
121 // NOTE: direction should not be (0, 0, 1)
122 Eigen::Matrix3d projection;
123 Eigen::Vector3d dird(dir[0], dir[1], 0.0);
124 dird.normalize();
125 projection << dird[0], dird[1], 0.0, -dird[1], dird[0], 0.0, 0.0, 0.0, 1.0;
126 constexpr double kDoubleMax = std::numeric_limits<double>::max();
127 Eigen::Vector3d min_pt(kDoubleMax, kDoubleMax, kDoubleMax);
128 Eigen::Vector3d max_pt(-kDoubleMax, -kDoubleMax, -kDoubleMax);
129 Eigen::Vector3d loc_pt(0.0, 0.0, 0.0);
130 for (size_t i = 0; i < cloud.size(); i++) {
131 loc_pt = projection * Eigen::Vector3d(cloud[i].x, cloud[i].y, cloud[i].z);
132
133 min_pt(0) = std::min(min_pt(0), loc_pt(0));
134 min_pt(1) = std::min(min_pt(1), loc_pt(1));
135 min_pt(2) = std::min(min_pt(2), loc_pt(2));
136
137 max_pt(0) = std::max(max_pt(0), loc_pt(0));
138 max_pt(1) = std::max(max_pt(1), loc_pt(1));
139 max_pt(2) = std::max(max_pt(2), loc_pt(2));
140 }
141 (*size) = (max_pt - min_pt).cast<float>();
142 Eigen::Vector3d coeff = (max_pt + min_pt) * 0.5;
143 coeff(2) = min_pt(2);
144 *center = projection.transpose() * coeff;
145
146 constexpr float kFloatEpsilon = std::numeric_limits<float>::epsilon();
147 float minimum_size = std::max(minimum_edge_length, kFloatEpsilon);
148
149 (*size)(0) = (*size)(0) <= minimum_size ? minimum_size : (*size)(0);
150 (*size)(1) = (*size)(1) <= minimum_size ? minimum_size : (*size)(1);
151 (*size)(2) = (*size)(2) <= minimum_size ? minimum_size : (*size)(2);
152}
153
154// old name: compute_most_consistent_bbox_direction
155template <typename Type>
157 const Eigen::Matrix<Type, 3, 1> &prev_dir,
158 Eigen::Matrix<Type, 3, 1> *curr_dir) {
159 Type dot_val_00 = prev_dir(0) * (*curr_dir)(0) + prev_dir(1) * (*curr_dir)(1);
160 Type dot_val_01 = prev_dir(0) * (*curr_dir)(1) - prev_dir(1) * (*curr_dir)(0);
161 if (fabs(dot_val_00) >= fabs(dot_val_01)) {
162 if (dot_val_00 < 0) {
163 (*curr_dir) = -(*curr_dir);
164 }
165 } else {
166 if (dot_val_01 < 0) {
167 (*curr_dir) =
168 Eigen::Matrix<Type, 3, 1>((*curr_dir)(1), -(*curr_dir)(0), 0);
169 } else {
170 (*curr_dir) =
171 Eigen::Matrix<Type, 3, 1>(-(*curr_dir)(1), (*curr_dir)(0), 0);
172 }
173 }
174}
175
176// @brief calculate the IOU (intersection-over-union) between two bbox
177// old name:compute_2d_iou_bbox_to_bbox
178template <typename Type>
179Type CalculateIou2DXY(const Eigen::Matrix<Type, 3, 1> &center0,
180 const Eigen::Matrix<Type, 3, 1> &size0,
181 const Eigen::Matrix<Type, 3, 1> &center1,
182 const Eigen::Matrix<Type, 3, 1> &size1) {
183 Type min_x_bbox_0 = center0(0) - size0(0) * static_cast<Type>(0.5);
184 Type min_x_bbox_1 = center1(0) - size1(0) * static_cast<Type>(0.5);
185 Type max_x_bbox_0 = center0(0) + size0(0) * static_cast<Type>(0.5);
186 Type max_x_bbox_1 = center1(0) + size1(0) * static_cast<Type>(0.5);
187 Type start_x = std::max(min_x_bbox_0, min_x_bbox_1);
188 Type end_x = std::min(max_x_bbox_0, max_x_bbox_1);
189 Type length_x = end_x - start_x;
190 if (length_x <= 0) {
191 return 0;
192 }
193 Type min_y_bbox_0 = center0(1) - size0(1) * static_cast<Type>(0.5);
194 Type min_y_bbox_1 = center1(1) - size1(1) * static_cast<Type>(0.5);
195 Type max_y_bbox_0 = center0(1) + size0(1) * static_cast<Type>(0.5);
196 Type max_y_bbox_1 = center1(1) + size1(1) * static_cast<Type>(0.5);
197 Type start_y = std::max(min_y_bbox_0, min_y_bbox_1);
198 Type end_y = std::min(max_y_bbox_0, max_y_bbox_1);
199 Type length_y = end_y - start_y;
200 if (length_y <= 0) {
201 return 0;
202 }
203 Type intersection_area = length_x * length_y;
204 Type bbox_0_area = size0(0) * size0(1);
205 Type bbox_1_area = size1(0) * size1(1);
206 Type iou =
207 intersection_area / (bbox_0_area + bbox_1_area - intersection_area);
208 return iou;
209}
210template <typename Type>
212 const base::BBox2D<Type> &box2) {
213 base::Rect<Type> rect1(box1);
214 base::Rect<Type> rect2(box2);
215 base::Rect<Type> intersection = rect1 & rect2;
216 base::Rect<Type> unionsection = rect1 | rect2;
217 return intersection.Area() / unionsection.Area();
218}
219
220// @brief given a point and segments,
221// calculate the distance and direction to the nearest segment
222// old name: calculate_distance_and_direction_to_segments_xy
223template <typename PointT>
225 const Eigen::Matrix<typename PointT::Type, 3, 1> &pt,
226 const base::PointCloud<PointT> &segs, typename PointT::Type *dist,
227 Eigen::Matrix<typename PointT::Type, 3, 1> *dir) {
228 if (segs.size() < 2) {
229 return false;
230 }
231
232 using Type = typename PointT::Type;
233 Eigen::Matrix<Type, 3, 1> seg_point(segs[0].x, segs[0].y, 0);
234 Type min_dist = (pt - seg_point).head(2).norm();
235
236 Eigen::Matrix<Type, 3, 1> end_point_pre;
237 Eigen::Matrix<Type, 3, 1> end_point_cur;
238 Eigen::Matrix<Type, 3, 1> line_segment_dir;
239 Eigen::Matrix<Type, 3, 1> line_segment_dir_pre;
240 Eigen::Matrix<Type, 3, 1> end_point_to_pt_vec;
241
242 line_segment_dir_pre << 0, 0, 0;
243
244 Type line_segment_len = 0;
245 Type projected_len = 0;
246 Type point_to_line_dist = 0;
247 Type point_to_end_point_dist = 0;
248
249 for (size_t i = 1; i < segs.size(); ++i) {
250 end_point_pre << segs[i - 1].x, segs[i - 1].y, 0;
251 end_point_cur << segs[i].x, segs[i].y, 0;
252 line_segment_dir = end_point_pre - end_point_cur;
253 end_point_to_pt_vec = pt - end_point_cur;
254 end_point_to_pt_vec(2) = 0;
255 line_segment_len = line_segment_dir.head(2).norm();
256 line_segment_dir = line_segment_dir / line_segment_len;
257 if (i == 1) {
258 *dir = line_segment_dir;
259 }
260 projected_len = end_point_to_pt_vec.dot(line_segment_dir);
261 // case 1. pt is in the range of current line segment, compute
262 // the point to line distance
263 if (projected_len >= 0 && projected_len <= line_segment_len) {
264 point_to_line_dist = end_point_to_pt_vec.cross(line_segment_dir).norm();
265 if (min_dist > point_to_line_dist) {
266 min_dist = point_to_line_dist;
267 *dir = line_segment_dir;
268 }
269 } else {
270 // case 2. pt is out of range of current line segment, compute
271 // the point to end point distance
272 point_to_end_point_dist = end_point_to_pt_vec.head(2).norm();
273 if (min_dist > point_to_end_point_dist) {
274 min_dist = point_to_end_point_dist;
275 *dir = line_segment_dir + line_segment_dir_pre;
276 dir->normalize();
277 }
278 }
279 line_segment_dir_pre = line_segment_dir;
280 }
281 *dist = min_dist;
282
283 return true;
284}
285
286// @brief given a point and two boundaries,
287// calculate the distance and direction to the nearer boundary
288// old name: calculate_distance_and_direction_to_boundary_xy
289template <typename PointT>
291 const Eigen::Matrix<typename PointT::Type, 3, 1> &pt,
292 const base::PointCloud<PointT> &left_boundary,
293 const base::PointCloud<PointT> &right_boundary, typename PointT::Type *dist,
294 Eigen::Matrix<typename PointT::Type, 3, 1> *dir) {
295 using Type = typename PointT::Type;
296 Type dist_to_left = std::numeric_limits<Type>::max();
297 Eigen::Matrix<Type, 3, 1> direction_left;
298 Type dist_to_right = std::numeric_limits<Type>::max();
299 Eigen::Matrix<Type, 3, 1> direction_right;
300
301 CalculateDistAndDirToSegs(pt, left_boundary, &dist_to_left, &direction_left);
302
303 CalculateDistAndDirToSegs(pt, right_boundary, &dist_to_right,
304 &direction_right);
305
306 if (dist_to_left < dist_to_right) {
307 (*dist) = dist_to_left;
308 (*dir) = direction_left;
309 } else {
310 (*dist) = dist_to_right;
311 (*dir) = direction_right;
312 }
313}
314
315// @brief given a point and two boundaries sets,
316// calculate the distance and direction to the nearest boundary
317// old name: calculate_distance_and_direction_to_boundary_xy
318template <typename PointT>
320 const Eigen::Matrix<typename PointT::Type, 3, 1> &pt,
323 typename PointT::Type *dist,
324 Eigen::Matrix<typename PointT::Type, 3, 1> *dir) {
325 using Type = typename PointT::Type;
326 Type dist_to_left = std::numeric_limits<Type>::max();
327 Eigen::Matrix<Type, 3, 1> direction_left;
328 Type dist_to_right = std::numeric_limits<Type>::max();
329 Eigen::Matrix<Type, 3, 1> direction_right;
330
331 for (size_t i = 0; i < left_boundary.size(); i++) {
332 Type dist_temp = std::numeric_limits<Type>::max();
333 Eigen::Matrix<Type, 3, 1> dir_temp;
334 if (CalculateDistAndDirToSegs(pt, left_boundary[i], &dist_temp,
335 &dir_temp)) {
336 if (dist_to_left > dist_temp) {
337 dist_to_left = dist_temp;
338 direction_left = dir_temp;
339 }
340 }
341 }
342
343 for (size_t i = 0; i < right_boundary.size(); i++) {
344 Type dist_temp = std::numeric_limits<Type>::max();
345 Eigen::Matrix<Type, 3, 1> dir_temp;
346 if (CalculateDistAndDirToSegs(pt, right_boundary[i], &dist_temp,
347 &dir_temp)) {
348 if (dist_to_right > dist_temp) {
349 dist_to_right = dist_temp;
350 direction_right = dir_temp;
351 }
352 }
353 }
354 if (dist_to_left < dist_to_right) {
355 (*dist) = dist_to_left;
356 (*dir) = direction_left;
357 } else {
358 (*dist) = dist_to_right;
359 (*dir) = direction_right;
360 }
361}
362
363// @brief given center size and dir
364// calculate the other-four corners
365template <typename Type>
366void CalculateCornersFromCenter(Type center_x, Type center_y, Type center_z,
367 Type size_x, Type size_y, Type size_z, Type theta,
368 Eigen::Matrix<Type, 8, 1> *corners) {
369 Type cos_theta = cos(theta);
370 Type sin_theta = sin(theta);
371 Type hx = size_x * 0.5;
372 Type hy = size_y * 0.5;
373
374 Type left_up_x = (-hx) * cos_theta + (-hy) * sin_theta + center_x;
375 Type left_up_y = (-hx) * (-sin_theta) + (-hy) * cos_theta + center_y;
376 Type right_up_x = (-hx) * cos_theta + hy * sin_theta + center_x;
377 Type right_up_y = (-hx) * (-sin_theta) + hy * cos_theta + center_y;
378 Type right_down_x = hx * cos_theta + hy * sin_theta + center_x;
379 Type right_down_y = hx * (-sin_theta) + hy * cos_theta + center_y;
380 Type left_down_x = hx * cos_theta + (-hy) * sin_theta + center_x;
381 Type left_down_y = hx * (-sin_theta) + (-hy) * cos_theta + center_y;
382
383 (*corners)(0) = left_up_x;
384 (*corners)(1) = left_up_y;
385 (*corners)(2) = right_up_x;
386 (*corners)(3) = right_up_y;
387 (*corners)(4) = right_down_x;
388 (*corners)(5) = right_down_y;
389 (*corners)(6) = left_down_x;
390 (*corners)(7) = left_down_y;
391}
392
393// @brief return true if two 2D line segment `(p1, q1)` and
394// `(p2, q2)` intersect
395template <typename T>
397 const Eigen::Matrix<T, 2, 1> &p1,
398 const Eigen::Matrix<T, 2, 1> &q1,
399 const Eigen::Matrix<T, 2, 1> &p2,
400 const Eigen::Matrix<T, 2, 1> &q2) {
401 // find orientation of ordered triplet (p, q, r).
402 // returns values:
403 // 0 --> p, q and r are collinear
404 // 1 --> Clockwise
405 // 2 --> Counterclockwise
406 auto find_orientation = [](const Eigen::Matrix<T, 2, 1> &p,
407 const Eigen::Matrix<T, 2, 1> &q,
408 const Eigen::Matrix<T, 2, 1> &r) -> int {
409 // comparing slopes of line segments (p, q) and (q, r)
410 // k1 = (q[1] - p[1]) / (q[0] - p[0])
411 // k2 = (r[1] - q[1]) / (r[0] - q[0])
412 // if k1 < k2, -> counterclockwise
413 // if k1 > k2, -> clockwise
414 // if k1 == k2, -> collinear
415 float ret = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
416 // collinear
417 if (std::fabs(ret) < std::numeric_limits<float>::epsilon()) {
418 return 0;
419 }
420 // clock or counterclock wise
421 return (ret > 0.f) ? 1 : 2;
422 };
423
424 // given three 'collinear' points p, q, r
425 // check whether point p is on line segment (q, r)
426 auto is_on_segment = [](const Eigen::Matrix<T, 2, 1> &p,
427 const Eigen::Matrix<T, 2, 1> &q,
428 const Eigen::Matrix<T, 2, 1> &r) -> bool {
429 return p[0] <= std::max(q[0], r[0])
430 && p[0] >= std::min(q[0], r[0])
431 && p[1] <= std::max(q[1], r[1])
432 && p[1] >= std::min(q[1], r[1]);
433 };
434
435 // Two line segments (p1, q1) and (p2, q2) intersect <=>
436 // (p1, q1, p2) and (p1, q1, q2) have different orientations and
437 // (p2, q2, p1) and (p2, q2, q1) have different orientations.
438 int orientation_p1_q1_p2 = find_orientation(p1, q1, p2);
439 int orientation_p1_q1_q2 = find_orientation(p1, q1, q2);
440 int orientation_p2_q2_p1 = find_orientation(p2, q2, p1);
441 int orientation_p2_q2_q1 = find_orientation(p2, q2, q1);
442 if (orientation_p1_q1_p2 != orientation_p1_q1_q2
443 && orientation_p2_q2_p1 != orientation_p2_q2_q1) {
444 return true;
445 }
446
447 // Special cases, two line segments are collinear
448 if (orientation_p1_q1_p2 == 0 && is_on_segment(p2, p1, q1)) {
449 return true;
450 }
451 if (orientation_p1_q1_q2 == 0 && is_on_segment(q2, p1, q1)) {
452 return true;
453 }
454 if (orientation_p2_q2_p1 == 0 && is_on_segment(p1, p2, q2)) {
455 return true;
456 }
457 if (orientation_p2_q2_q1 == 0 && is_on_segment(q1, p2, q2)) {
458 return true;
459 }
460 return false;
461}
462
463} // namespace algorithm
464} // namespace perception
465} // namespace apollo
const PointT * at(size_t col, size_t row) const
Definition point_cloud.h:63
#define AINFO
Definition log.h:42
std::vector< EigenType, Eigen::aligned_allocator< EigenType > > EigenVector
Definition eigen_defs.h:33
void CalculateMostConsistentBBoxDir2DXY(const Eigen::Matrix< Type, 3, 1 > &prev_dir, Eigen::Matrix< Type, 3, 1 > *curr_dir)
Definition common.h:156
void CalculateBBoxSizeCenter2DXY(const PointCloudT &cloud, const Eigen::Vector3f &dir, Eigen::Vector3f *size, Eigen::Vector3d *center, float minimum_edge_length=std::numeric_limits< float >::epsilon())
Definition common.h:117
Type CalculateIOUBBox(const base::BBox2D< Type > &box1, const base::BBox2D< Type > &box2)
Definition common.h:211
bool IsPointInBBox(const Eigen::Matrix< typename PointT::Type, 3, 1 > &gnd_c, const Eigen::Matrix< typename PointT::Type, 3, 1 > &dir_x, const Eigen::Matrix< typename PointT::Type, 3, 1 > &dir_y, const Eigen::Matrix< typename PointT::Type, 3, 1 > &dir_z, const Eigen::Matrix< typename PointT::Type, 3, 1 > &size, const PointT &point)
Definition common.h:90
bool IsPointXYInPolygon2DXY(const PointT &point, const base::PointCloud< PointT > &polygon)
Definition common.h:35
void CalculateCornersFromCenter(Type center_x, Type center_y, Type center_z, Type size_x, Type size_y, Type size_z, Type theta, Eigen::Matrix< Type, 8, 1 > *corners)
Definition common.h:366
void CalculateDistAndDirToBoundary(const Eigen::Matrix< typename PointT::Type, 3, 1 > &pt, const base::PointCloud< PointT > &left_boundary, const base::PointCloud< PointT > &right_boundary, typename PointT::Type *dist, Eigen::Matrix< typename PointT::Type, 3, 1 > *dir)
Definition common.h:290
bool CalculateDistAndDirToSegs(const Eigen::Matrix< typename PointT::Type, 3, 1 > &pt, const base::PointCloud< PointT > &segs, typename PointT::Type *dist, Eigen::Matrix< typename PointT::Type, 3, 1 > *dir)
Definition common.h:224
Type CalculateIou2DXY(const Eigen::Matrix< Type, 3, 1 > &center0, const Eigen::Matrix< Type, 3, 1 > &size0, const Eigen::Matrix< Type, 3, 1 > &center1, const Eigen::Matrix< Type, 3, 1 > &size1)
Definition common.h:179
bool IsLineSegments2DIntersect(const Eigen::Matrix< T, 2, 1 > &p1, const Eigen::Matrix< T, 2, 1 > &q1, const Eigen::Matrix< T, 2, 1 > &p2, const Eigen::Matrix< T, 2, 1 > &q2)
Definition common.h:396
constexpr float kFloatEpsilon
Definition lane_object.h:32
class register implement
Definition arena_queue.h:37