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