Apollo  v5.5.0
Open source self driving car software
common.h
Go to the documentation of this file.
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"
24 
27 
28 namespace apollo {
29 namespace perception {
30 namespace common {
31 
32 // @brief check a point is in polygon or not
33 // old name: is_xy_point_in_2d_xy_polygon
34 template <typename PointT>
35 bool 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  // start with the last point to make the check last point<->first point the
45  // first one
46  Type xold = polygon.at(nr_poly_points - 1).x;
47  Type yold = polygon.at(nr_poly_points - 1).y;
48  for (size_t i = 0; i < nr_poly_points; ++i) {
49  Type xnew = polygon.at(i).x;
50  Type ynew = polygon.at(i).y;
51  if (xnew > xold) {
52  x1 = xold;
53  x2 = xnew;
54  y1 = yold;
55  y2 = ynew;
56  } else {
57  x1 = xnew;
58  x2 = xold;
59  y1 = ynew;
60  y2 = yold;
61  }
62  // if the point is on the boundary, then it is defined as in the polygon
63  Type value = (point.y - y1) * (x2 - x1) - (y2 - y1) * (point.x - x1);
64  Type temp = std::sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
65  if (temp < std::numeric_limits<Type>::epsilon()) {
66  continue;
67  }
68  Type distance = std::abs(value) / temp;
69  if (x1 <= point.x && point.x <= x2 &&
70  distance < std::numeric_limits<Type>::epsilon()) {
71  return true;
72  }
73  if ((x1 < point.x) == (point.x <= x2) && value < 0.f) {
74  in_poly = !in_poly;
75  }
76  xold = xnew;
77  yold = ynew;
78  }
79  return in_poly;
80 }
81 
82 // @brief check a point is in bounding-box or not
83 // old name: is_point_in_boundingbox
84 template <typename PointT>
85 bool IsPointInBBox(const Eigen::Matrix<typename PointT::Type, 3, 1> &gnd_c,
86  const Eigen::Matrix<typename PointT::Type, 3, 1> &dir_x,
87  const Eigen::Matrix<typename PointT::Type, 3, 1> &dir_y,
88  const Eigen::Matrix<typename PointT::Type, 3, 1> &dir_z,
89  const Eigen::Matrix<typename PointT::Type, 3, 1> &size,
90  const PointT &point) {
91  using T = typename PointT::Type;
92  Eigen::Matrix<T, 3, 1> eig(point.x, point.y, point.z);
93  Eigen::Matrix<T, 3, 1> diff = eig - gnd_c;
94  T x = diff.dot(dir_x);
95  if (fabs(x) > size[0] * 0.5) {
96  return false;
97  }
98  T y = diff.dot(dir_y);
99  if (fabs(y) > size[1] * 0.5) {
100  return false;
101  }
102  T z = diff.dot(dir_z);
103  if (fabs(z) > size[2] * 0.5) {
104  return false;
105  }
106  return true;
107 }
108 
109 // @brief calculate the size and center of the bounding-box of a point cloud
110 // old name: compute_bbox_size_center_xy
111 template <typename PointCloudT>
112 void CalculateBBoxSizeCenter2DXY(const PointCloudT &cloud,
113  const Eigen::Vector3f &dir,
114  Eigen::Vector3f *size, Eigen::Vector3d *center,
115  float minimum_edge_length = FLT_EPSILON) {
116  // NOTE: direction should not be (0, 0, 1)
117  Eigen::Matrix3d projection;
118  Eigen::Vector3d dird(dir[0], dir[1], 0.0);
119  dird.normalize();
120  projection << dird[0], dird[1], 0.0, -dird[1], dird[0], 0.0, 0.0, 0.0, 1.0;
121  Eigen::Vector3d min_pt(DBL_MAX, DBL_MAX, DBL_MAX);
122  Eigen::Vector3d max_pt(-DBL_MAX, -DBL_MAX, -DBL_MAX);
123  Eigen::Vector3d loc_pt(0.0, 0.0, 0.0);
124  for (int i = 0; i < cloud.size(); i++) {
125  loc_pt = projection * Eigen::Vector3d(cloud[i].x, cloud[i].y, cloud[i].z);
126 
127  min_pt(0) = std::min(min_pt(0), loc_pt(0));
128  min_pt(1) = std::min(min_pt(1), loc_pt(1));
129  min_pt(2) = std::min(min_pt(2), loc_pt(2));
130 
131  max_pt(0) = std::max(max_pt(0), loc_pt(0));
132  max_pt(1) = std::max(max_pt(1), loc_pt(1));
133  max_pt(2) = std::max(max_pt(2), loc_pt(2));
134  }
135  (*size) = (max_pt - min_pt).cast<float>();
136  Eigen::Vector3d coeff = (max_pt + min_pt) * 0.5;
137  coeff(2) = min_pt(2);
138  *center = projection.transpose() * coeff;
139 
140  float minimum_size =
141  minimum_edge_length > FLT_EPSILON ? minimum_edge_length : FLT_EPSILON;
142  (*size)(0) = (*size)(0) <= minimum_size ? minimum_size : (*size)(0);
143  (*size)(1) = (*size)(1) <= minimum_size ? minimum_size : (*size)(1);
144  (*size)(2) = (*size)(2) <= minimum_size ? minimum_size : (*size)(2);
145 }
146 
147 // old name: compute_most_consistent_bbox_direction
148 template <typename Type>
150  const Eigen::Matrix<Type, 3, 1> &prev_dir,
151  Eigen::Matrix<Type, 3, 1> *curr_dir) {
152  Type dot_val_00 = prev_dir(0) * (*curr_dir)(0) + prev_dir(1) * (*curr_dir)(1);
153  Type dot_val_01 = prev_dir(0) * (*curr_dir)(1) - prev_dir(1) * (*curr_dir)(0);
154  if (fabs(dot_val_00) >= fabs(dot_val_01)) {
155  if (dot_val_00 < 0) {
156  (*curr_dir) = -(*curr_dir);
157  }
158  } else {
159  if (dot_val_01 < 0) {
160  (*curr_dir) =
161  Eigen::Matrix<Type, 3, 1>((*curr_dir)(1), -(*curr_dir)(0), 0);
162  } else {
163  (*curr_dir) =
164  Eigen::Matrix<Type, 3, 1>(-(*curr_dir)(1), (*curr_dir)(0), 0);
165  }
166  }
167 }
168 
169 // @brief calculate the IOU (intersection-over-union) between two bbox
170 // old name:compute_2d_iou_bbox_to_bbox
171 template <typename Type>
172 Type CalculateIou2DXY(const Eigen::Matrix<Type, 3, 1> &center0,
173  const Eigen::Matrix<Type, 3, 1> &size0,
174  const Eigen::Matrix<Type, 3, 1> &center1,
175  const Eigen::Matrix<Type, 3, 1> &size1) {
176  Type min_x_bbox_0 = center0(0) - size0(0) * static_cast<Type>(0.5);
177  Type min_x_bbox_1 = center1(0) - size1(0) * static_cast<Type>(0.5);
178  Type max_x_bbox_0 = center0(0) + size0(0) * static_cast<Type>(0.5);
179  Type max_x_bbox_1 = center1(0) + size1(0) * static_cast<Type>(0.5);
180  Type start_x = std::max(min_x_bbox_0, min_x_bbox_1);
181  Type end_x = std::min(max_x_bbox_0, max_x_bbox_1);
182  Type length_x = end_x - start_x;
183  if (length_x <= 0) {
184  return 0;
185  }
186  Type min_y_bbox_0 = center0(1) - size0(1) * static_cast<Type>(0.5);
187  Type min_y_bbox_1 = center1(1) - size1(1) * static_cast<Type>(0.5);
188  Type max_y_bbox_0 = center0(1) + size0(1) * static_cast<Type>(0.5);
189  Type max_y_bbox_1 = center1(1) + size1(1) * static_cast<Type>(0.5);
190  Type start_y = std::max(min_y_bbox_0, min_y_bbox_1);
191  Type end_y = std::min(max_y_bbox_0, max_y_bbox_1);
192  Type length_y = end_y - start_y;
193  if (length_y <= 0) {
194  return 0;
195  }
196  Type intersection_area = length_x * length_y;
197  Type bbox_0_area = size0(0) * size0(1);
198  Type bbox_1_area = size1(0) * size1(1);
199  Type iou =
200  intersection_area / (bbox_0_area + bbox_1_area - intersection_area);
201  return iou;
202 }
203 template <typename Type>
205  const base::BBox2D<Type> &box2) {
206  base::Rect<Type> rect1(box1);
207  base::Rect<Type> rect2(box2);
208  base::Rect<Type> intersection = rect1 & rect2;
209  base::Rect<Type> unionsection = rect1 | rect2;
210  return intersection.Area() / unionsection.Area();
211 }
212 
213 // @brief given a point and segments,
214 // calculate the distance and direction to the nearest segment
215 // old name: calculate_distance_and_direction_to_segments_xy
216 template <typename PointT>
218  const Eigen::Matrix<typename PointT::Type, 3, 1> &pt,
219  const base::PointCloud<PointT> &segs, typename PointT::Type *dist,
220  Eigen::Matrix<typename PointT::Type, 3, 1> *dir) {
221  if (segs.size() < 2) {
222  return false;
223  }
224 
225  using Type = typename PointT::Type;
226  Eigen::Matrix<Type, 3, 1> seg_point(segs[0].x, segs[0].y, 0);
227  Type min_dist = (pt - seg_point).head(2).norm();
228 
229  Eigen::Matrix<Type, 3, 1> end_point_pre;
230  Eigen::Matrix<Type, 3, 1> end_point_cur;
231  Eigen::Matrix<Type, 3, 1> line_segment_dir;
232  Eigen::Matrix<Type, 3, 1> line_segment_dir_pre;
233  Eigen::Matrix<Type, 3, 1> end_point_to_pt_vec;
234 
235  line_segment_dir_pre << 0, 0, 0;
236 
237  Type line_segment_len = 0;
238  Type projected_len = 0;
239  Type point_to_line_dist = 0;
240  Type point_to_end_point_dist = 0;
241 
242  for (size_t i = 1; i < segs.size(); ++i) {
243  end_point_pre << segs[i - 1].x, segs[i - 1].y, 0;
244  end_point_cur << segs[i].x, segs[i].y, 0;
245  line_segment_dir = end_point_pre - end_point_cur;
246  end_point_to_pt_vec = pt - end_point_cur;
247  end_point_to_pt_vec(2) = 0;
248  line_segment_len = line_segment_dir.head(2).norm();
249  line_segment_dir = line_segment_dir / line_segment_len;
250  if (i == 1) {
251  *dir = line_segment_dir;
252  }
253  projected_len = end_point_to_pt_vec.dot(line_segment_dir);
254  // case 1. pt is in the range of current line segment, compute
255  // the point to line distance
256  if (projected_len >= 0 && projected_len <= line_segment_len) {
257  point_to_line_dist = end_point_to_pt_vec.cross(line_segment_dir).norm();
258  if (min_dist > point_to_line_dist) {
259  min_dist = point_to_line_dist;
260  *dir = line_segment_dir;
261  }
262  } else {
263  // case 2. pt is out of range of current line segment, compute
264  // the point to end point distance
265  point_to_end_point_dist = end_point_to_pt_vec.head(2).norm();
266  if (min_dist > point_to_end_point_dist) {
267  min_dist = point_to_end_point_dist;
268  *dir = line_segment_dir + line_segment_dir_pre;
269  dir->normalize();
270  }
271  }
272  line_segment_dir_pre = line_segment_dir;
273  }
274  *dist = min_dist;
275 
276  return true;
277 }
278 
279 // @brief given a point and two boundaries,
280 // calculate the distance and direction to the nearer boundary
281 // old name: calculate_distance_and_direction_to_boundary_xy
282 template <typename PointT>
284  const Eigen::Matrix<typename PointT::Type, 3, 1> &pt,
285  const base::PointCloud<PointT> &left_boundary,
286  const base::PointCloud<PointT> &right_boundary, typename PointT::Type *dist,
287  Eigen::Matrix<typename PointT::Type, 3, 1> *dir) {
288  using Type = typename PointT::Type;
289  Type dist_to_left = std::numeric_limits<Type>::max();
290  Eigen::Matrix<Type, 3, 1> direction_left;
291  Type dist_to_right = std::numeric_limits<Type>::max();
292  Eigen::Matrix<Type, 3, 1> direction_right;
293 
294  CalculateDistAndDirToSegs(pt, left_boundary, &dist_to_left, &direction_left);
295 
296  CalculateDistAndDirToSegs(pt, right_boundary, &dist_to_right,
297  &direction_right);
298 
299  if (dist_to_left < dist_to_right) {
300  (*dist) = dist_to_left;
301  (*dir) = direction_left;
302  } else {
303  (*dist) = dist_to_right;
304  (*dir) = direction_right;
305  }
306 }
307 
308 // @brief given a point and two boundaries sets,
309 // calculate the distance and direction to the nearest boundary
310 // old name: calculate_distance_and_direction_to_boundary_xy
311 template <typename PointT>
313  const Eigen::Matrix<typename PointT::Type, 3, 1> &pt,
314  const std::vector<base::PointCloud<PointT>> &left_boundary,
315  const std::vector<base::PointCloud<PointT>> &right_boundary,
316  typename PointT::Type *dist,
317  Eigen::Matrix<typename PointT::Type, 3, 1> *dir) {
318  using Type = typename PointT::Type;
319  Type dist_to_left = std::numeric_limits<Type>::max();
320  Eigen::Matrix<Type, 3, 1> direction_left;
321  Type dist_to_right = std::numeric_limits<Type>::max();
322  Eigen::Matrix<Type, 3, 1> direction_right;
323 
324  for (size_t i = 0; i < left_boundary.size(); i++) {
325  Type dist_temp = std::numeric_limits<Type>::max();
326  Eigen::Matrix<Type, 3, 1> dir_temp;
327  if (CalculateDistAndDirToSegs(pt, left_boundary[i], &dist_temp,
328  &dir_temp)) {
329  if (dist_to_left > dist_temp) {
330  dist_to_left = dist_temp;
331  direction_left = dir_temp;
332  }
333  }
334  }
335 
336  for (size_t i = 0; i < right_boundary.size(); i++) {
337  Type dist_temp = std::numeric_limits<Type>::max();
338  Eigen::Matrix<Type, 3, 1> dir_temp;
339  if (CalculateDistAndDirToSegs(pt, right_boundary[i], &dist_temp,
340  &dir_temp)) {
341  if (dist_to_right > dist_temp) {
342  dist_to_right = dist_temp;
343  direction_right = dir_temp;
344  }
345  }
346  }
347  if (dist_to_left < dist_to_right) {
348  (*dist) = dist_to_left;
349  (*dir) = direction_left;
350  } else {
351  (*dist) = dist_to_right;
352  (*dir) = direction_right;
353  }
354 }
355 
356 } // namespace common
357 } // namespace perception
358 } // namespace apollo
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:283
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:85
Definition: blob.h:72
bool IsPointXYInPolygon2DXY(const PointT &point, const base::PointCloud< PointT > &polygon)
Definition: common.h:35
T abs(const T &x)
Definition: misc.h:48
size_t size() const
Definition: point_cloud.h:76
Type CalculateIOUBBox(const base::BBox2D< Type > &box1, const base::BBox2D< Type > &box2)
Definition: common.h:204
Definition: point_cloud.h:33
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:217
void CalculateBBoxSizeCenter2DXY(const PointCloudT &cloud, const Eigen::Vector3f &dir, Eigen::Vector3f *size, Eigen::Vector3d *center, float minimum_edge_length=FLT_EPSILON)
Definition: common.h:112
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:172
Definition: box.h:33
float diff(Image< float > *I, int x1, int y1, int x2, int y2)
Definition: segment_image.h:44
T Area() const
Definition: box.h:66
void CalculateMostConsistentBBoxDir2DXY(const Eigen::Matrix< Type, 3, 1 > &prev_dir, Eigen::Matrix< Type, 3, 1 > *curr_dir)
Definition: common.h:149
const PointT * at(size_t col, size_t row) const
Definition: point_cloud.h:57