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