Apollo  6.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"
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>
113  const PointCloudT &cloud, const Eigen::Vector3f &dir, Eigen::Vector3f *size,
114  Eigen::Vector3d *center,
115  float minimum_edge_length = std::numeric_limits<float>::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  constexpr double kDoubleMax = std::numeric_limits<double>::max();
122  Eigen::Vector3d min_pt(kDoubleMax, kDoubleMax, kDoubleMax);
123  Eigen::Vector3d max_pt(-kDoubleMax, -kDoubleMax, -kDoubleMax);
124  Eigen::Vector3d loc_pt(0.0, 0.0, 0.0);
125  for (size_t i = 0; i < cloud.size(); i++) {
126  loc_pt = projection * Eigen::Vector3d(cloud[i].x, cloud[i].y, cloud[i].z);
127 
128  min_pt(0) = std::min(min_pt(0), loc_pt(0));
129  min_pt(1) = std::min(min_pt(1), loc_pt(1));
130  min_pt(2) = std::min(min_pt(2), loc_pt(2));
131 
132  max_pt(0) = std::max(max_pt(0), loc_pt(0));
133  max_pt(1) = std::max(max_pt(1), loc_pt(1));
134  max_pt(2) = std::max(max_pt(2), loc_pt(2));
135  }
136  (*size) = (max_pt - min_pt).cast<float>();
137  Eigen::Vector3d coeff = (max_pt + min_pt) * 0.5;
138  coeff(2) = min_pt(2);
139  *center = projection.transpose() * coeff;
140 
141  constexpr float kFloatEpsilon = std::numeric_limits<float>::epsilon();
142  float minimum_size = std::max(minimum_edge_length, kFloatEpsilon);
143 
144  (*size)(0) = (*size)(0) <= minimum_size ? minimum_size : (*size)(0);
145  (*size)(1) = (*size)(1) <= minimum_size ? minimum_size : (*size)(1);
146  (*size)(2) = (*size)(2) <= minimum_size ? minimum_size : (*size)(2);
147 }
148 
149 // old name: compute_most_consistent_bbox_direction
150 template <typename Type>
152  const Eigen::Matrix<Type, 3, 1> &prev_dir,
153  Eigen::Matrix<Type, 3, 1> *curr_dir) {
154  Type dot_val_00 = prev_dir(0) * (*curr_dir)(0) + prev_dir(1) * (*curr_dir)(1);
155  Type dot_val_01 = prev_dir(0) * (*curr_dir)(1) - prev_dir(1) * (*curr_dir)(0);
156  if (fabs(dot_val_00) >= fabs(dot_val_01)) {
157  if (dot_val_00 < 0) {
158  (*curr_dir) = -(*curr_dir);
159  }
160  } else {
161  if (dot_val_01 < 0) {
162  (*curr_dir) =
163  Eigen::Matrix<Type, 3, 1>((*curr_dir)(1), -(*curr_dir)(0), 0);
164  } else {
165  (*curr_dir) =
166  Eigen::Matrix<Type, 3, 1>(-(*curr_dir)(1), (*curr_dir)(0), 0);
167  }
168  }
169 }
170 
171 // @brief calculate the IOU (intersection-over-union) between two bbox
172 // old name:compute_2d_iou_bbox_to_bbox
173 template <typename Type>
174 Type CalculateIou2DXY(const Eigen::Matrix<Type, 3, 1> &center0,
175  const Eigen::Matrix<Type, 3, 1> &size0,
176  const Eigen::Matrix<Type, 3, 1> &center1,
177  const Eigen::Matrix<Type, 3, 1> &size1) {
178  Type min_x_bbox_0 = center0(0) - size0(0) * static_cast<Type>(0.5);
179  Type min_x_bbox_1 = center1(0) - size1(0) * static_cast<Type>(0.5);
180  Type max_x_bbox_0 = center0(0) + size0(0) * static_cast<Type>(0.5);
181  Type max_x_bbox_1 = center1(0) + size1(0) * static_cast<Type>(0.5);
182  Type start_x = std::max(min_x_bbox_0, min_x_bbox_1);
183  Type end_x = std::min(max_x_bbox_0, max_x_bbox_1);
184  Type length_x = end_x - start_x;
185  if (length_x <= 0) {
186  return 0;
187  }
188  Type min_y_bbox_0 = center0(1) - size0(1) * static_cast<Type>(0.5);
189  Type min_y_bbox_1 = center1(1) - size1(1) * static_cast<Type>(0.5);
190  Type max_y_bbox_0 = center0(1) + size0(1) * static_cast<Type>(0.5);
191  Type max_y_bbox_1 = center1(1) + size1(1) * static_cast<Type>(0.5);
192  Type start_y = std::max(min_y_bbox_0, min_y_bbox_1);
193  Type end_y = std::min(max_y_bbox_0, max_y_bbox_1);
194  Type length_y = end_y - start_y;
195  if (length_y <= 0) {
196  return 0;
197  }
198  Type intersection_area = length_x * length_y;
199  Type bbox_0_area = size0(0) * size0(1);
200  Type bbox_1_area = size1(0) * size1(1);
201  Type iou =
202  intersection_area / (bbox_0_area + bbox_1_area - intersection_area);
203  return iou;
204 }
205 template <typename Type>
207  const base::BBox2D<Type> &box2) {
208  base::Rect<Type> rect1(box1);
209  base::Rect<Type> rect2(box2);
210  base::Rect<Type> intersection = rect1 & rect2;
211  base::Rect<Type> unionsection = rect1 | rect2;
212  return intersection.Area() / unionsection.Area();
213 }
214 
215 // @brief given a point and segments,
216 // calculate the distance and direction to the nearest segment
217 // old name: calculate_distance_and_direction_to_segments_xy
218 template <typename PointT>
220  const Eigen::Matrix<typename PointT::Type, 3, 1> &pt,
221  const base::PointCloud<PointT> &segs, typename PointT::Type *dist,
222  Eigen::Matrix<typename PointT::Type, 3, 1> *dir) {
223  if (segs.size() < 2) {
224  return false;
225  }
226 
227  using Type = typename PointT::Type;
228  Eigen::Matrix<Type, 3, 1> seg_point(segs[0].x, segs[0].y, 0);
229  Type min_dist = (pt - seg_point).head(2).norm();
230 
231  Eigen::Matrix<Type, 3, 1> end_point_pre;
232  Eigen::Matrix<Type, 3, 1> end_point_cur;
233  Eigen::Matrix<Type, 3, 1> line_segment_dir;
234  Eigen::Matrix<Type, 3, 1> line_segment_dir_pre;
235  Eigen::Matrix<Type, 3, 1> end_point_to_pt_vec;
236 
237  line_segment_dir_pre << 0, 0, 0;
238 
239  Type line_segment_len = 0;
240  Type projected_len = 0;
241  Type point_to_line_dist = 0;
242  Type point_to_end_point_dist = 0;
243 
244  for (size_t i = 1; i < segs.size(); ++i) {
245  end_point_pre << segs[i - 1].x, segs[i - 1].y, 0;
246  end_point_cur << segs[i].x, segs[i].y, 0;
247  line_segment_dir = end_point_pre - end_point_cur;
248  end_point_to_pt_vec = pt - end_point_cur;
249  end_point_to_pt_vec(2) = 0;
250  line_segment_len = line_segment_dir.head(2).norm();
251  line_segment_dir = line_segment_dir / line_segment_len;
252  if (i == 1) {
253  *dir = line_segment_dir;
254  }
255  projected_len = end_point_to_pt_vec.dot(line_segment_dir);
256  // case 1. pt is in the range of current line segment, compute
257  // the point to line distance
258  if (projected_len >= 0 && projected_len <= line_segment_len) {
259  point_to_line_dist = end_point_to_pt_vec.cross(line_segment_dir).norm();
260  if (min_dist > point_to_line_dist) {
261  min_dist = point_to_line_dist;
262  *dir = line_segment_dir;
263  }
264  } else {
265  // case 2. pt is out of range of current line segment, compute
266  // the point to end point distance
267  point_to_end_point_dist = end_point_to_pt_vec.head(2).norm();
268  if (min_dist > point_to_end_point_dist) {
269  min_dist = point_to_end_point_dist;
270  *dir = line_segment_dir + line_segment_dir_pre;
271  dir->normalize();
272  }
273  }
274  line_segment_dir_pre = line_segment_dir;
275  }
276  *dist = min_dist;
277 
278  return true;
279 }
280 
281 // @brief given a point and two boundaries,
282 // calculate the distance and direction to the nearer boundary
283 // old name: calculate_distance_and_direction_to_boundary_xy
284 template <typename PointT>
286  const Eigen::Matrix<typename PointT::Type, 3, 1> &pt,
287  const base::PointCloud<PointT> &left_boundary,
288  const base::PointCloud<PointT> &right_boundary, typename PointT::Type *dist,
289  Eigen::Matrix<typename PointT::Type, 3, 1> *dir) {
290  using Type = typename PointT::Type;
291  Type dist_to_left = std::numeric_limits<Type>::max();
292  Eigen::Matrix<Type, 3, 1> direction_left;
293  Type dist_to_right = std::numeric_limits<Type>::max();
294  Eigen::Matrix<Type, 3, 1> direction_right;
295 
296  CalculateDistAndDirToSegs(pt, left_boundary, &dist_to_left, &direction_left);
297 
298  CalculateDistAndDirToSegs(pt, right_boundary, &dist_to_right,
299  &direction_right);
300 
301  if (dist_to_left < dist_to_right) {
302  (*dist) = dist_to_left;
303  (*dir) = direction_left;
304  } else {
305  (*dist) = dist_to_right;
306  (*dir) = direction_right;
307  }
308 }
309 
310 // @brief given a point and two boundaries sets,
311 // calculate the distance and direction to the nearest boundary
312 // old name: calculate_distance_and_direction_to_boundary_xy
313 template <typename PointT>
315  const Eigen::Matrix<typename PointT::Type, 3, 1> &pt,
318  typename PointT::Type *dist,
319  Eigen::Matrix<typename PointT::Type, 3, 1> *dir) {
320  using Type = typename PointT::Type;
321  Type dist_to_left = std::numeric_limits<Type>::max();
322  Eigen::Matrix<Type, 3, 1> direction_left;
323  Type dist_to_right = std::numeric_limits<Type>::max();
324  Eigen::Matrix<Type, 3, 1> direction_right;
325 
326  for (size_t i = 0; i < left_boundary.size(); i++) {
327  Type dist_temp = std::numeric_limits<Type>::max();
328  Eigen::Matrix<Type, 3, 1> dir_temp;
329  if (CalculateDistAndDirToSegs(pt, left_boundary[i], &dist_temp,
330  &dir_temp)) {
331  if (dist_to_left > dist_temp) {
332  dist_to_left = dist_temp;
333  direction_left = dir_temp;
334  }
335  }
336  }
337 
338  for (size_t i = 0; i < right_boundary.size(); i++) {
339  Type dist_temp = std::numeric_limits<Type>::max();
340  Eigen::Matrix<Type, 3, 1> dir_temp;
341  if (CalculateDistAndDirToSegs(pt, right_boundary[i], &dist_temp,
342  &dir_temp)) {
343  if (dist_to_right > dist_temp) {
344  dist_to_right = dist_temp;
345  direction_right = dir_temp;
346  }
347  }
348  }
349  if (dist_to_left < dist_to_right) {
350  (*dist) = dist_to_left;
351  (*dir) = direction_left;
352  } else {
353  (*dist) = dist_to_right;
354  (*dir) = direction_right;
355  }
356 }
357 
358 } // namespace common
359 } // namespace perception
360 } // namespace apollo
std::vector< EigenType, Eigen::aligned_allocator< EigenType > > EigenVector
Definition: eigen_defs.h:32
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:285
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
Eigen::Vector3f Vector3f
Definition: base_map_fwd.h:29
PlanningContext is the runtime context in planning. It is persistent across multiple frames...
Definition: atomic_hash_map.h:25
bool IsPointXYInPolygon2DXY(const PointT &point, const base::PointCloud< PointT > &polygon)
Definition: common.h:35
Eigen::Vector3d Vector3d
Definition: frame_transform.h:27
T abs(const T &x)
Definition: misc.h:48
size_t size() const
Definition: point_cloud.h:83
Type CalculateIOUBBox(const base::BBox2D< Type > &box1, const base::BBox2D< Type > &box2)
Definition: common.h:206
Definition: point_cloud.h:37
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:112
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:219
constexpr float kFloatEpsilon
Definition: lane_object.h:30
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:174
apollo::cyber::base::std value
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
Eigen::Matrix3d Matrix3d
Definition: base_map_fwd.h:33
void CalculateMostConsistentBBoxDir2DXY(const Eigen::Matrix< Type, 3, 1 > &prev_dir, Eigen::Matrix< Type, 3, 1 > *curr_dir)
Definition: common.h:151
const PointT * at(size_t col, size_t row) const
Definition: point_cloud.h:64