Apollo 10.0
自动驾驶开放平台
lane_based_calibrator.cc
浏览该文件的文档.
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 *****************************************************************************/
17
19
20namespace apollo {
21namespace perception {
22namespace camera {
23
24void GetYawVelocityInfo(const float &time_diff, const double cam_coord_cur[3],
25 const double cam_coord_pre[3],
26 const double cam_coord_pre_pre[3], float *yaw_rate,
27 float *velocity) {
28 assert(yaw_rate != nullptr);
29 assert(velocity != nullptr);
30 double time_diff_r = algorithm::IRec(static_cast<double>(time_diff));
31 double dist = algorithm::ISqrt(
32 algorithm::ISquaresumDiffU2(cam_coord_cur, cam_coord_pre));
33 *velocity = static_cast<float>(dist * time_diff_r);
34
35 double offset_cur[2] = {
36 cam_coord_cur[0] - cam_coord_pre[0],
37 cam_coord_cur[1] - cam_coord_pre[1],
38 };
39 double offset_pre[2] = {
40 cam_coord_pre[0] - cam_coord_pre_pre[0],
41 cam_coord_pre[1] - cam_coord_pre_pre[1],
42 };
43 double yaw_cur = atan2(offset_cur[1], offset_cur[0]);
44 double yaw_pre = atan2(offset_pre[1], offset_pre[0]);
45 double yaw_rate_db = (yaw_cur - yaw_pre) * time_diff_r;
46 *yaw_rate = static_cast<float>(yaw_rate_db);
47}
48
50 // General
52 sampling_lane_point_rate = 0.05f; // 0.05f
54
55 // Slow set-up
56 // min_distance_to_update_calibration_in_meter = 1600.0f;
57 // min_required_straight_driving_distance_in_meter = 40.0f;
58
59 // Fast set-up
62
63 // Histogram params
66 // -10 ~ 10 degree
68
73
81 static_cast<int>(hist_estimator_params.smooth_kernel.size());
84
87 // hist_estimator_params.histogram_mass_limit = 500;
89 // Decay 6-times to half value
91}
92
94 const CalibratorParams *params) {
95 ClearUp();
96 image_width_ = options.image_width;
97 image_height_ = options.image_height;
98 assert(image_width_ > 0);
99 assert(image_height_ > 0);
100 k_mat_[0] = options.focal_x;
101 k_mat_[4] = options.focal_y;
102 k_mat_[2] = options.cx;
103 k_mat_[5] = options.cy;
104 k_mat_[1] = k_mat_[3] = k_mat_[6] = k_mat_[7] = 0.0f;
105 k_mat_[8] = 1.0f;
106
107 if (params != nullptr) {
108 params_ = *params;
109 }
110 pitch_histogram_.Init(&params_.hist_estimator_params);
111}
112
114 vp_buffer_.clear();
115 pitch_histogram_.Clear();
116 image_width_ = 0;
117 image_height_ = 0;
118 memset(k_mat_, 0.0f, sizeof(float) * 9);
119 pitch_cur_ = 0.0f;
120 pitch_estimation_ = 0.0f;
121 vanishing_row_ = 0.0f;
122 accumulated_straight_driving_in_meter_ = 0.0f;
123}
124
125bool LaneBasedCalibrator::Process(const EgoLane &lane, const float &velocity,
126 const float &yaw_rate,
127 const float &time_diff) {
128 float distance_traveled_in_meter = velocity * time_diff;
129 float vehicle_yaw_changed = yaw_rate * time_diff;
130
131 // distance_traveled_in_meter = 0.5f; // hardcode for debug
132
133 // TODO(Xun): Change cout or cerr to log.
134
135 // Check for driving straight
136 if (!IsTravelingStraight(vehicle_yaw_changed)) {
137 AINFO << "Do not calibate if not moving straight: "
138 << "yaw angle changed " << vehicle_yaw_changed;
139 vp_buffer_.clear();
140 return false;
141 }
142
143 VanishingPoint vp_cur;
144 VanishingPoint vp_work;
145
146 // Get the current estimation on vanishing point from lane
147 if (!GetVanishingPoint(lane, &vp_cur)) {
148 AINFO << "Lane is not valid for calibration.";
149 return false;
150 }
151 vp_cur.distance_traveled = distance_traveled_in_meter;
152 // std::cout << "#current v-row: " << vp_cur.pixel_pos[1] << std::endl;
153
154 // Push vanishing point into buffer
155 PushVanishingPoint(vp_cur);
156 if (!PopVanishingPoint(&vp_work)) {
157 AINFO << "Driving distance is not long enough";
158 return false;
159 }
160
161 // Get current estimation on pitch
162 pitch_cur_ = 0.0f;
163 if (!GetPitchFromVanishingPoint(vp_work, &pitch_cur_)) {
164 AINFO << "Failed to estimate pitch from vanishing point.";
165 return false;
166 }
167 // std::cout << "#current pitch: " << pitch_cur_ << std::endl;
168 vanishing_row_ = vp_work.pixel_pos[1];
169
170 // Get the filtered output using histogram
171 if (!AddPitchToHistogram(pitch_cur_)) {
172 AINFO << "Calculated pitch is out-of-range.";
173 return false;
174 }
175
176 accumulated_straight_driving_in_meter_ += distance_traveled_in_meter;
177 // std::cout << "acc_d: " << accumulated_straight_driving_in_meter_ << "\n";
178 if (accumulated_straight_driving_in_meter_ >
180 pitch_histogram_.Process()) {
181 pitch_estimation_ = pitch_histogram_.get_val_estimation();
182 const float cy = k_mat_[5];
183 const float fy = k_mat_[4];
184 vanishing_row_ = tanf(pitch_estimation_) * fy + cy;
185 accumulated_straight_driving_in_meter_ = 0.0f;
186 return true;
187 }
188 return false;
189}
190
191void LaneBasedCalibrator::PushVanishingPoint(const VanishingPoint &v_point) {
192 int nr_vps = static_cast<int>(vp_buffer_.size());
193 if (nr_vps < kMaxNrHistoryFrames) {
194 vp_buffer_.push_back(v_point);
195 } else {
196 vp_buffer_.pop_front();
197 vp_buffer_.push_back(v_point);
198 }
199}
200
201bool LaneBasedCalibrator::PopVanishingPoint(VanishingPoint *v_point) {
202 float accumulated_distance = 0.0f;
203 for (const auto &vp : vp_buffer_) {
204 accumulated_distance += vp.distance_traveled;
205 }
206 if (accumulated_distance <
208 return false;
209 }
210 *v_point = vp_buffer_.back();
211 vp_buffer_.pop_back();
212 return true;
213}
214
215bool LaneBasedCalibrator::AddPitchToHistogram(float pitch) {
216 return pitch_histogram_.Push(pitch);
217}
218
219bool LaneBasedCalibrator::GetPitchFromVanishingPoint(const VanishingPoint &vp,
220 float *pitch) const {
221 assert(pitch != nullptr);
222 const float cx = k_mat_[2];
223 const float cy = k_mat_[5];
224 const float fx = k_mat_[0];
225 const float fy = k_mat_[4];
226 float yaw_check = static_cast<float>(atan2(vp.pixel_pos[0] - cx, fx));
227 if (fabs(yaw_check) > params_.max_allowed_yaw_angle_in_radian) {
228 return false;
229 }
230 *pitch = static_cast<float>(atan2(vp.pixel_pos[1] - cy, fy));
231 return true;
232}
233
234bool LaneBasedCalibrator::GetVanishingPoint(const EgoLane &lane,
235 VanishingPoint *v_point) {
236 assert(v_point != nullptr);
237 float line_seg_l[4] = {0};
238 float line_seg_r[4] = {0};
239
240 // Get line segment
241 bool get_line_seg_left =
242 SelectTwoPointsFromLineForVanishingPoint(lane.left_line, line_seg_l);
243 if (!get_line_seg_left) {
244 AINFO << "Left lane is too short.";
245 return false;
246 }
247
248 bool get_line_seg_right =
249 SelectTwoPointsFromLineForVanishingPoint(lane.right_line, line_seg_r);
250 if (!get_line_seg_right) {
251 AINFO << "Right lane is too short.";
252 return false;
253 }
254
255 // Get vanishing point by line segments intersection
256 return GetIntersectionFromTwoLineSegments(line_seg_l, line_seg_r, v_point);
257}
258
259int LaneBasedCalibrator::GetCenterIndex(const Eigen::Vector2f *points,
260 int nr_pts) const {
261 assert(points != nullptr);
262 if (nr_pts <= 0) {
263 return -1;
264 }
265 float center_x = 0.0f;
266 float center_y = 0.0f;
267 for (int i = 0; i < nr_pts; ++i) {
268 center_x += points[i](0);
269 center_y += points[i](1);
270 }
271 center_x /= static_cast<float>(nr_pts);
272 center_y /= static_cast<float>(nr_pts);
273 float dist = 0.0f;
274 float dist_min = static_cast<float>(fabs(points[0](0) - center_x) +
275 fabs(points[0](1) - center_y));
276 int center_index = 0;
277 for (int i = 1; i < nr_pts; ++i) {
278 dist = static_cast<float>(fabs(points[i](0) - center_x) +
279 fabs(points[i](1) - center_y));
280 if (dist < dist_min) {
281 dist_min = dist;
282 center_index = i;
283 }
284 }
285 return is_in_image(points[center_index]) ? center_index : -1;
286}
287
288bool LaneBasedCalibrator::SelectTwoPointsFromLineForVanishingPoint(
289 const LaneLine &line, float line_seg[4]) {
290 int nr_pts = static_cast<int>(line.lane_point.size());
291 if (nr_pts < params_.min_nr_pts_laneline) {
292 return false;
293 }
294
295 int nr_samples = nr_pts * static_cast<int>(params_.sampling_lane_point_rate);
296 int offset_end = nr_pts - nr_samples - 1;
297 int sampled_start = GetCenterIndex(line.lane_point.data(), nr_samples);
298 int sampled_end =
299 offset_end +
300 GetCenterIndex(line.lane_point.data() + offset_end, nr_samples);
301
302 if (sampled_start >= 0 && sampled_end >= 0) {
303 line_seg[0] = line.lane_point[sampled_start](0); // start
304 line_seg[1] = line.lane_point[sampled_start](1);
305 line_seg[2] = line.lane_point[sampled_end](0); // end
306 line_seg[3] = line.lane_point[sampled_end](1);
307 } else {
308 line_seg[0] = line.lane_point.front()(0); // start
309 line_seg[1] = line.lane_point.front()(1);
310 line_seg[2] = line.lane_point.back()(0); // end
311 line_seg[3] = line.lane_point.back()(1);
312 }
313
314 // Ensure start is lower than end
315 if (line_seg[3] > line_seg[1]) {
316 std::swap(line_seg[0], line_seg[2]);
317 std::swap(line_seg[1], line_seg[3]);
318 }
319 return true;
320}
321
322bool LaneBasedCalibrator::GetIntersectionFromTwoLineSegments(
323 const float line_seg_l[4], const float line_seg_r[4],
324 VanishingPoint *v_point) {
325 assert(v_point != nullptr);
326 // ref: https://stackoverflow.com/questions/563198/...
327 // how-do-you-detect-where-two-line-segments-intersect/1968345#1968345
328 // need further debug!
329
330 // std::cout << "line seg from left:\n"
331 // << line_seg_l[0] << ", " << line_seg_l[1] << "\n"
332 // << line_seg_l[2] << ", " << line_seg_l[3] << std::endl;
333 // std::cout << "line seg from right:\n"
334 // << line_seg_r[0] << ", " << line_seg_r[1] << "\n"
335 // << line_seg_r[2] << ", " << line_seg_r[3] << std::endl;
336 /*
337 end end
338 0 2
339 ^ ^
340 | |
341 | |
342 1 3
343 start start
344 */
345
346 float left_start_x = line_seg_l[0];
347 float left_start_y = line_seg_l[1];
348 float left_end_x = line_seg_l[2];
349 float left_end_y = line_seg_l[3];
350
351 float right_start_x = line_seg_r[0];
352 float right_start_y = line_seg_r[1];
353 float right_end_x = line_seg_r[2];
354 float right_end_y = line_seg_r[3];
355
356 float v10[2] = {left_end_x - left_start_x, left_end_y - left_start_y};
357 float v32[2] = {right_end_x - right_start_x, right_end_y - right_start_y};
358 float dn = v10[0] * v32[1] - v10[1] * v32[0];
359
360 // Colinear
361 if (fabs(dn) < 1e-5) {
362 return false;
363 }
364
365 float v13[2] = {left_start_x - right_start_x, left_start_y - right_start_y};
366 float t = v32[0] * v13[1] - v32[1] * v13[0];
367 t *= algorithm::IRec(dn);
368
369 v_point->pixel_pos[0] = left_start_x + t * v10[0];
370 v_point->pixel_pos[1] = left_start_y + t * v10[1];
371 return true;
372}
373
374} // namespace camera
375} // namespace perception
376} // namespace apollo
void Init(const HistogramEstimatorParams *params=nullptr)
bool Process(const EgoLane &lane, const float &velocity, const float &yaw_rate, const float &time_diff)
void Init(const LocalCalibratorInitOptions &options, const CalibratorParams *params=nullptr)
#define AINFO
Definition log.h:42
float IDegreeToRadians(float d)
Definition i_basic.h:266
T ISquaresumDiffU2(const T x[2], const T y[2])
Definition i_blas.h:2633
void GetYawVelocityInfo(const float &time_diff, const double cam_coord_cur[3], const double cam_coord_pre[3], const double cam_coord_pre_pre[3], float *yaw_rate, float *velocity)
class register implement
Definition arena_queue.h:37