Apollo  6.0
Open source self driving car software
common_functions.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 #pragma once
17 
18 #include <vector>
19 
20 #include <limits>
21 
22 #include "Eigen/Core"
23 #include "cyber/common/log.h"
26 
27 namespace apollo {
28 namespace perception {
29 namespace camera {
30 typedef std::vector<base::Point3DF> Point3DSet;
31 typedef std::vector<base::Point2DF> Point2DSet;
32 
33 static const double lane_eps_value = 1e-6;
34 static const int max_poly_order = 3;
35 
36 struct LanePointInfo {
37  int type;
38  // model output score
39  float score;
40  // x coordinate
41  float x;
42  // y coordinate
43  float y;
44 };
45 // fit polynomial function with QR decomposition (using Eigen 3)
46 template <typename Dtype>
47 bool PolyFit(const std::vector<Eigen::Matrix<Dtype, 2, 1>>& pos_vec,
48  const int& order,
49  Eigen::Matrix<Dtype, max_poly_order + 1, 1>* coeff,
50  const bool& is_x_axis = true) {
51  if (coeff == nullptr) {
52  AERROR << "The coefficient pointer is NULL.";
53  return false;
54  }
55 
56  if (order > max_poly_order) {
57  AERROR << "The order of polynomial must be smaller than " << max_poly_order;
58  return false;
59  }
60 
61  int n = static_cast<int>(pos_vec.size());
62  if (n <= order) {
63  AERROR << "The number of points should be larger than the order. #points = "
64  << pos_vec.size();
65  return false;
66  }
67 
68  // create data matrix
69  Eigen::Matrix<Dtype, Eigen::Dynamic, Eigen::Dynamic> A(n, order + 1);
70  Eigen::Matrix<Dtype, Eigen::Dynamic, 1> y(n);
71  Eigen::Matrix<Dtype, Eigen::Dynamic, 1> result;
72  for (int i = 0; i < n; ++i) {
73  for (int j = 0; j <= order; ++j) {
74  A(i, j) = static_cast<Dtype>(
75  std::pow(is_x_axis ? pos_vec[i].x() : pos_vec[i].y(), j));
76  }
77  y(i) = is_x_axis ? pos_vec[i].y() : pos_vec[i].x();
78  }
79 
80  // solve linear least squares
81  result = A.householderQr().solve(y);
82  assert(result.size() == order + 1);
83 
84  for (int j = 0; j <= max_poly_order; ++j) {
85  (*coeff)(j) = (j <= order) ? result(j) : static_cast<Dtype>(0);
86  }
87 
88  return true;
89 }
90 
91 template <typename Dtype>
92 bool PolyEval(const Dtype& x, int order,
93  const Eigen::Matrix<Dtype, max_poly_order + 1, 1>& coeff,
94  Dtype* y) {
95  int poly_order = order;
96  if (order > max_poly_order) {
97  AERROR << "the order of polynomial function must be smaller than "
98  << max_poly_order;
99  return false;
100  }
101 
102  *y = static_cast<Dtype>(0);
103  for (int j = 0; j <= poly_order; ++j) {
104  *y += static_cast<Dtype>(coeff(j) * std::pow(x, j));
105  }
106 
107  return true;
108 }
109 
110 // @brief: ransac fitting to estimate the coefficients of linear system
111 template <typename Dtype>
112 bool RansacFitting(const std::vector<Eigen::Matrix<Dtype, 2, 1>>& pos_vec,
113  std::vector<Eigen::Matrix<Dtype, 2, 1>>* selected_points,
114  Eigen::Matrix<Dtype, 4, 1>* coeff, const int max_iters = 100,
115  const int N = 5,
116  const Dtype inlier_thres = static_cast<Dtype>(0.1)) {
117  if (coeff == nullptr) {
118  AERROR << "The coefficient pointer is NULL.";
119  return false;
120  }
121 
122  selected_points->clear();
123 
124  int n = static_cast<int>(pos_vec.size());
125  int q1 = static_cast<int>(n / 4);
126  int q2 = static_cast<int>(n / 2);
127  int q3 = static_cast<int>(n * 3 / 4);
128  if (n < N) {
129  AERROR << "The number of points should be larger than the order. #points = "
130  << pos_vec.size();
131  return false;
132  }
133 
134  std::vector<int> index(3, 0);
135  int max_inliers = 0;
136  Dtype min_residual = std::numeric_limits<float>::max();
137  Dtype early_stop_ratio = 0.95f;
138  Dtype good_lane_ratio = 0.666f;
139  for (int j = 0; j < max_iters; ++j) {
140  index[0] = std::rand() % q2;
141  index[1] = q2 + std::rand() % q1;
142  index[2] = q3 + std::rand() % q1;
143 
144  Eigen::Matrix<Dtype, 3, 3> matA;
145  matA << pos_vec[index[0]](0) * pos_vec[index[0]](0), pos_vec[index[0]](0),
146  1, pos_vec[index[1]](0) * pos_vec[index[1]](0), pos_vec[index[1]](0), 1,
147  pos_vec[index[2]](0) * pos_vec[index[2]](0), pos_vec[index[2]](0), 1;
148 
149  Eigen::FullPivLU<Eigen::Matrix<Dtype, 3, 3>> mat(matA);
150  mat.setThreshold(1e-5f);
151  if (mat.rank() < 3) {
152  ADEBUG << "matA: " << matA;
153  ADEBUG << "Matrix is not full rank (3). The rank is: " << mat.rank();
154  continue;
155  }
156 
157  // Since Eigen::solver was crashing, simple inverse of 3x3 matrix is used
158  // Note that Eigen::inverse of 3x3 and 4x4 is a closed form solution
159  Eigen::Matrix<Dtype, 3, 1> matB;
160  matB << pos_vec[index[0]](1), pos_vec[index[1]](1), pos_vec[index[2]](1);
161  Eigen::Vector3f c =
162  static_cast<Eigen::Matrix<Dtype, 3, 1>>(matA.inverse() * matB);
163  if (!(matA * c).isApprox(matB)) {
164  ADEBUG << "No solution.";
165  continue;
166  }
167 
168  int num_inliers = 0;
169  Dtype residual = 0;
170  Dtype y = 0;
171  for (int i = 0; i < n; ++i) {
172  y = pos_vec[i](0) * pos_vec[i](0) * c(0) + pos_vec[i](0) * c(1) + c(2);
173  if (std::abs(y - pos_vec[i](1)) <= inlier_thres) ++num_inliers;
174  residual += std::abs(y - pos_vec[i](1));
175  }
176 
177  if (num_inliers > max_inliers ||
178  (num_inliers == max_inliers && residual < min_residual)) {
179  (*coeff)(3) = 0;
180  (*coeff)(2) = c(0);
181  (*coeff)(1) = c(1);
182  (*coeff)(0) = c(2);
183  max_inliers = num_inliers;
184  min_residual = residual;
185  }
186 
187  if (max_inliers > early_stop_ratio * n) break;
188  }
189 
190  if (static_cast<Dtype>(max_inliers) / n < good_lane_ratio) return false;
191 
192  // std::vector<Eigen::Matrix<Dtype, 2, 1>> tmp = *pos_vec;
193  // pos_vec.clear();
194  for (int i = 0; i < n; ++i) {
195  Dtype y = pos_vec[i](0) * pos_vec[i](0) * (*coeff)(2) +
196  pos_vec[i](0) * (*coeff)(1) + (*coeff)(0);
197  if (std::abs(y - pos_vec[i](1)) <= inlier_thres) {
198  selected_points->push_back(pos_vec[i]);
199  }
200  }
201  return true;
202 }
203 
204 class DisjointSet {
205  public:
206  DisjointSet() : disjoint_array_(), subset_num_(0) {}
207  explicit DisjointSet(size_t size) : disjoint_array_(), subset_num_(0) {
208  disjoint_array_.reserve(size);
209  }
211 
212  void Init(size_t size) {
213  disjoint_array_.clear();
214  disjoint_array_.reserve(size);
215  subset_num_ = 0;
216  }
217 
218  void Reset() {
219  disjoint_array_.clear();
220  subset_num_ = 0;
221  }
222 
223  int Add(); // add a new element, which is a subset by itself;
224  int Find(int x); // return the root of x
225  void Unite(int x, int y);
226  int Size() const { return subset_num_; }
227  size_t Num() const { return disjoint_array_.size(); }
228 
229  private:
230  std::vector<int> disjoint_array_;
231  int subset_num_;
232 };
233 
235  public:
236  ConnectedComponent() : pixel_count_(0) {}
237 
238  ConnectedComponent(int x, int y) : pixel_count_(1) {
239  base::Point2DI point;
240  point.x = x;
241  point.y = y;
242  pixels_.push_back(point);
243  bbox_.xmin = x;
244  bbox_.xmax = x;
245  bbox_.ymin = y;
246  bbox_.ymax = y;
247  }
248 
250 
251  // CC pixels
252  void AddPixel(int x, int y);
253  int GetPixelCount() const { return pixel_count_; }
254  base::BBox2DI GetBBox() const { return bbox_; }
255  std::vector<base::Point2DI> GetPixels() const { return pixels_; }
256 
257  private:
258  int pixel_count_;
259  std::vector<base::Point2DI> pixels_;
260  base::BBox2DI bbox_;
261 };
262 
263 bool FindCC(const std::vector<unsigned char>& src, int width, int height,
264  const base::RectI& roi, std::vector<ConnectedComponent>* cc);
265 
266 bool ImagePoint2Camera(const base::Point2DF& img_point, float pitch_angle,
267  float camera_ground_height,
268  const Eigen::Matrix3f& intrinsic_params_inverse,
269  Eigen::Vector3d* camera_point);
270 
271 bool CameraPoint2Image(const Eigen::Vector3d& camera_point,
272  const Eigen::Matrix3f& intrinsic_params,
273  base::Point2DF* img_point);
274 
275 bool ComparePoint2DY(const base::Point2DF& point1,
276  const base::Point2DF& point2);
277 
278 template <class T>
279 void QSwap_(T* a, T* b) {
280  T temp = *a;
281  *a = *b;
282  *b = temp;
283 }
284 
285 template <class T>
286 void QuickSort(int* index, const T* values, int start, int end) {
287  if (start >= end - 1) {
288  return;
289  }
290 
291  const T& pivot = values[index[(start + end - 1) / 2]];
292  // first, split into two parts: less than the pivot
293  // and greater-or-equal
294  int lo = start;
295  int hi = end;
296 
297  for (;;) {
298  while (lo < hi && values[index[lo]] < pivot) {
299  lo++;
300  }
301  while (lo < hi && values[index[hi - 1]] >= pivot) {
302  hi--;
303  }
304  if (lo == hi || lo == hi - 1) {
305  break;
306  }
307  QSwap_(&(index[lo]), &(index[hi - 1]));
308  lo++;
309  hi--;
310  }
311 
312  int split1 = lo;
313  // now split into two parts: equal to the pivot
314  // and strictly greater.
315  hi = end;
316  for (;;) {
317  while (lo < hi && values[index[lo]] == pivot) {
318  lo++;
319  }
320  while (lo < hi && values[index[hi - 1]] > pivot) {
321  hi--;
322  }
323  if (lo == hi || lo == hi - 1) {
324  break;
325  }
326  QSwap_(&(index[lo]), &(index[hi - 1]));
327  lo++;
328  hi--;
329  }
330  int split2 = lo;
331  QuickSort(index, values, start, split1);
332  QuickSort(index, values, split2, end);
333 }
334 
335 template <class T>
336 void QuickSort(int* index, const T* values, int nsize) {
337  for (int ii = 0; ii < nsize; ii++) {
338  index[ii] = ii;
339  }
340  QuickSort(index, values, 0, nsize);
341 }
342 bool FindKSmallValue(const float* distance, int dim, int k, int* index);
343 
344 bool FindKLargeValue(const float* distance, int dim, int k, int* index);
345 } // namespace camera
346 } // namespace perception
347 } // namespace apollo
float score
Definition: common_functions.h:39
int Size() const
Definition: common_functions.h:226
int GetPixelCount() const
Definition: common_functions.h:253
bool FindKLargeValue(const float *distance, int dim, int k, int *index)
Definition: point.h:82
Definition: common_functions.h:36
bool RansacFitting(const std::vector< Eigen::Matrix< Dtype, 2, 1 >> &pos_vec, std::vector< Eigen::Matrix< Dtype, 2, 1 >> *selected_points, Eigen::Matrix< Dtype, 4, 1 > *coeff, const int max_iters=100, const int N=5, const Dtype inlier_thres=static_cast< Dtype >(0.1))
Definition: common_functions.h:112
base::BBox2DI GetBBox() const
Definition: common_functions.h:254
bool CameraPoint2Image(const Eigen::Vector3d &camera_point, const Eigen::Matrix3f &intrinsic_params, base::Point2DF *img_point)
ConnectedComponent(int x, int y)
Definition: common_functions.h:238
bool FindCC(const std::vector< unsigned char > &src, int width, int height, const base::RectI &roi, std::vector< ConnectedComponent > *cc)
Eigen::Vector3f Vector3f
Definition: base_map_fwd.h:29
Definition: common_functions.h:234
PlanningContext is the runtime context in planning. It is persistent across multiple frames...
Definition: atomic_hash_map.h:25
DisjointSet()
Definition: common_functions.h:206
float x
Definition: common_functions.h:41
const size_t A
Definition: util.h:160
Eigen::Vector3d Vector3d
Definition: frame_transform.h:27
void Init(size_t size)
Definition: common_functions.h:212
std::vector< base::Point2DI > GetPixels() const
Definition: common_functions.h:255
T abs(const T &x)
Definition: misc.h:48
bool PolyEval(const Dtype &x, int order, const Eigen::Matrix< Dtype, max_poly_order+1, 1 > &coeff, Dtype *y)
Definition: common_functions.h:92
bool FindKSmallValue(const float *distance, int dim, int k, int *index)
T x
Definition: point.h:83
void Reset()
Definition: common_functions.h:218
Eigen::Matrix3f Matrix3f
Definition: base_map_fwd.h:27
T y
Definition: point.h:84
Definition: common_functions.h:204
#define ADEBUG
Definition: log.h:41
float y
Definition: common_functions.h:43
bool ComparePoint2DY(const base::Point2DF &point1, const base::Point2DF &point2)
DisjointSet(size_t size)
Definition: common_functions.h:207
int type
Definition: common_functions.h:37
ConnectedComponent()
Definition: common_functions.h:236
std::vector< base::Point2DF > Point2DSet
Definition: common_functions.h:31
bool ImagePoint2Camera(const base::Point2DF &img_point, float pitch_angle, float camera_ground_height, const Eigen::Matrix3f &intrinsic_params_inverse, Eigen::Vector3d *camera_point)
void QuickSort(int *index, const T *values, int start, int end)
Definition: common_functions.h:286
void QSwap_(T *a, T *b)
Definition: common_functions.h:279
#define AERROR
Definition: log.h:44
~DisjointSet()
Definition: common_functions.h:210
std::vector< base::Point3DF > Point3DSet
Definition: common_functions.h:30
size_t Num() const
Definition: common_functions.h:227
bool PolyFit(const std::vector< Eigen::Matrix< Dtype, 2, 1 >> &pos_vec, const int &order, Eigen::Matrix< Dtype, max_poly_order+1, 1 > *coeff, const bool &is_x_axis=true)
Definition: common_functions.h:47
~ConnectedComponent()
Definition: common_functions.h:249