Apollo 10.0
自动驾驶开放平台
denseline_lane_postprocessor.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
18#include <algorithm>
19
20#include "cyber/common/file.h"
21#include "cyber/common/log.h"
26
27namespace apollo {
28namespace perception {
29namespace camera {
30
32
34 const LanePostprocessorInitOptions& options) {
35 // read postprocessor parameter
36 std::string config_file =
37 GetConfigFile(options.config_path, options.config_file);
38 if (!cyber::common::GetProtoFromFile(config_file,
39 &lane_postprocessor_param_)) {
40 AERROR << "Read config detect_param failed: " << config_file;
41 return false;
42 }
43
44 AINFO << "lane_postprocessor param: "
45 << lane_postprocessor_param_.DebugString();
46 input_offset_x_ = lane_postprocessor_param_.input_offset_x();
47 input_offset_y_ = lane_postprocessor_param_.input_offset_y();
48 input_crop_height_ = lane_postprocessor_param_.crop_height();
49 input_crop_width_ = lane_postprocessor_param_.crop_width();
50
51 omit_bottom_line_num_ = lane_postprocessor_param_.omit_bottom_line_num();
52 laneline_map_score_thresh_ =
53 lane_postprocessor_param_.laneline_map_score_thresh();
54 laneline_point_score_thresh_ =
55 lane_postprocessor_param_.laneline_point_score_thresh();
56 laneline_point_min_num_thresh_ =
57 lane_postprocessor_param_.laneline_point_min_num_thresh();
58 cc_valid_pixels_ratio_ = lane_postprocessor_param_.cc_valid_pixels_ratio();
59 laneline_reject_dist_thresh_ =
60 lane_postprocessor_param_.laneline_reject_dist_thresh();
61
62 lane_map_dim_ = lane_map_width_ * lane_map_height_;
63 lane_pos_blob_.Reshape({4, lane_map_dim_});
64 lane_hist_blob_.Reshape({2, lane_map_dim_});
65 return true;
66}
67
69 const LanePostprocessorOptions& options, CameraFrame* frame) {
70 frame->lane_objects.clear();
71 // 1. locate the lane line point set
72 bool flag = LocateLanelinePointSet(frame);
73 if (!flag) {
74 return true;
75 }
76
77 // 2. classify the lane line pos type
78 std::vector<base::LaneLinePositionType> line_pos_type_vec(
79 image_group_point_set_.size());
80 std::vector<bool> line_flag(image_group_point_set_.size(), false);
81 ClassifyLanelinePosTypeInImage(image_group_point_set_, &line_pos_type_vec,
82 &line_flag);
84 for (int line_index = 0;
85 line_index < static_cast<int>(image_group_point_set_.size());
86 line_index++) {
87 if (!line_flag[line_index]) {
88 ADEBUG << "line_pos_type is invalid";
89 continue;
90 }
91 AddImageLaneline(image_group_point_set_[line_index], line_type,
92 line_pos_type_vec[line_index], line_index,
93 &(frame->lane_objects));
94 }
95 AINFO << "[AfterProcess2D]lane_lines_num: " << frame->lane_objects.size();
96
97 return true;
98}
99
101 const LanePostprocessorOptions& options, CameraFrame* frame) {
102 ConvertImagePoint2Camera(frame);
103 PolyFitCameraLaneline(frame);
104 return true;
105}
106
107void DenselineLanePostprocessor::ConvertImagePoint2Camera(CameraFrame* frame) {
108 float pitch_angle = frame->calibration_service->QueryPitchAngle();
109 float camera_ground_height =
111 const Eigen::Matrix3f& intrinsic_params = frame->camera_k_matrix;
112 const Eigen::Matrix3f& intrinsic_params_inverse = intrinsic_params.inverse();
113 std::vector<base::LaneLine>& lane_objects = frame->lane_objects;
114 int laneline_num = static_cast<int>(lane_objects.size());
115 for (int line_index = 0; line_index < laneline_num; line_index++) {
116 std::vector<base::Point2DF>& image_point_set =
117 lane_objects[line_index].curve_image_point_set;
118 std::vector<base::Point3DF>& camera_point_set =
119 lane_objects[line_index].curve_camera_point_set;
120 for (int i = 0; i < static_cast<int>(image_point_set.size()); i++) {
121 base::Point3DF camera_point;
122 Eigen::Vector3d camera_point3d;
123 const base::Point2DF& image_point = image_point_set[i];
124 ImagePoint2Camera(image_point, pitch_angle, camera_ground_height,
125 intrinsic_params_inverse, &camera_point3d);
126 camera_point.x = static_cast<float>(camera_point3d(0));
127 camera_point.y = static_cast<float>(camera_point3d(1));
128 camera_point.z = static_cast<float>(camera_point3d(2));
129 camera_point_set.push_back(camera_point);
130 }
131 }
132}
133
134void DenselineLanePostprocessor::CalLaneMap(
135 const float* output_data, int width, int height,
136 std::vector<unsigned char>* lane_map) {
137 int out_dim = width * height;
138 for (int y = 0; y < height - omit_bottom_line_num_; y++) {
139 float score_channel[4];
140 int row_start = y * width;
141 int channel0_pos = row_start;
142 int channel1_pos = out_dim + row_start;
143 int channel2_pos = 2 * out_dim + row_start;
144 int channel3_pos = 3 * out_dim + row_start;
145 int channel5_pos = 5 * out_dim + row_start;
146 int channel6_pos = 6 * out_dim + row_start;
147
148 for (int x = 0; x < width; ++x) {
149 score_channel[0] = output_data[channel0_pos + x];
150 score_channel[1] = output_data[channel1_pos + x];
151 score_channel[2] = output_data[channel2_pos + x];
152 score_channel[3] = output_data[channel3_pos + x];
153 // Utilize softmax to get the probability
154 float sum_score = 0.0f;
155 for (int i = 0; i < 4; i++) {
156 score_channel[i] = static_cast<float>(exp(score_channel[i]));
157 sum_score += score_channel[i];
158 }
159 for (int i = 0; i < 4; i++) {
160 score_channel[i] /= sum_score;
161 }
162 // 1: ego-lane; 2: adj-left lane; 3: adj-right lane
163 // find the score with max lane map
164 int max_channel_idx = 0;
165 float max_score = score_channel[0];
166 for (int channel_idx = 1; channel_idx < 4; channel_idx++) {
167 if (max_score < score_channel[channel_idx]) {
168 max_score = score_channel[channel_idx];
169 max_channel_idx = channel_idx;
170 }
171 }
172 // if the channel 0 has the maximum probability
173 // or the score is less than the setting value
174 // omit it
175 if (max_channel_idx == 0 || max_score < laneline_map_score_thresh_) {
176 continue;
177 }
178 int pixel_pos = row_start + x;
179 (*lane_map)[pixel_pos] = 1;
180
181 float dist_left = sigmoid(output_data[channel5_pos + x]);
182 float dist_right = sigmoid(output_data[channel6_pos + x]);
183 lane_output_[pixel_pos] = dist_left;
184 lane_output_[out_dim + pixel_pos] = dist_right;
185 lane_output_[out_dim * 2 + pixel_pos] = max_score;
186 }
187 }
188}
189
190// @brief infer the lane line points using lane center point information
191void DenselineLanePostprocessor::InferPointSetFromLaneCenter(
192 const std::vector<ConnectedComponent>& lane_ccs,
193 const std::vector<LaneType>& ccs_pos_type,
194 std::vector<std::vector<LanePointInfo>>* lane_map_group_point_set) {
195 // 0: adj-left lane center
196 // 1: ego-lane center;
197 // 2: adj-right lane center
198 int map_dim = lane_map_width_ * lane_map_height_;
199 if (lane_map_dim_ != map_dim) {
200 lane_map_dim_ = map_dim;
201 lane_pos_blob_.Reshape({4, lane_map_dim_});
202 lane_hist_blob_.Reshape({2, lane_map_dim_});
203 }
204
205 for (int i = 0; i < static_cast<int>(lane_ccs.size()); i++) {
206 int left_index = -1;
207 int right_index = -1;
208 if (ccs_pos_type[i] == LaneType::EGO_LANE) {
209 left_index = 1;
210 right_index = 2;
211 } else if (ccs_pos_type[i] == LaneType::ADJACENT_LEFT_LANE) {
212 left_index = 0;
213 } else if (ccs_pos_type[i] == LaneType::ADJACENT_RIGHT_LANE) {
214 right_index = 3;
215 }
216 InferPointSetFromOneCC(lane_ccs[i], left_index, right_index,
217 lane_map_group_point_set);
218 }
219}
220
221// @brief infer the lane line points from one CC
222void DenselineLanePostprocessor::InferPointSetFromOneCC(
223 const ConnectedComponent& lane_cc, int left_index, int right_index,
224 std::vector<std::vector<LanePointInfo>>* lane_map_group_point_set) {
225 // find the points which belongs to this CC
226 const std::vector<base::Point2DI>& pixels = lane_cc.GetPixels();
227 // initialize the memory
228 float* pos_blob_head = lane_pos_blob_.mutable_cpu_data();
229 float* score_left_vec = pos_blob_head;
230 float* x_left_vec = pos_blob_head + lane_pos_blob_.offset(1);
231 float* score_right_vec = pos_blob_head + lane_pos_blob_.offset(2);
232 float* x_right_vec = pos_blob_head + lane_pos_blob_.offset(3);
233
234 int* hist_blob_head = lane_hist_blob_.mutable_cpu_data();
235 int* x_left_count = hist_blob_head;
236 int* x_right_count = hist_blob_head + lane_hist_blob_.offset(1);
237 memset(lane_pos_blob_.mutable_cpu_data(), 0,
238 sizeof(float) * lane_pos_blob_.count());
239 memset(lane_hist_blob_.mutable_cpu_data(), 0,
240 sizeof(int) * lane_hist_blob_.count());
241
242 int lane_map_dim = lane_map_width_ * lane_map_height_;
243 for (int j = 0; j < static_cast<int>(pixels.size()); j++) {
244 int pixel_x = pixels[j].x;
245 int pixel_y = pixels[j].y;
246 int pixel_pos = pixel_y * lane_map_width_ + pixel_x;
247
248 float score = lane_output_[lane_map_dim * 2 + pixel_pos];
249 float dist_left = lane_output_[pixel_pos];
250 float x_left_map = static_cast<float>(pixel_x) -
251 dist_left * static_cast<float>(lane_map_width_);
252 int x_left = static_cast<int>(x_left_map);
253 if (left_index != -1 && x_left > 0 && x_left < lane_map_width_ - 1) {
254 int pos_left = pixel_y * lane_map_width_ + x_left;
255 score_left_vec[pos_left] += score;
256 x_left_vec[pos_left] += x_left_map;
257 ++x_left_count[pos_left];
258 }
259
260 float dist_right = lane_output_[lane_map_dim + pixel_pos];
261 float x_right_map = static_cast<float>(pixel_x) +
262 dist_right * static_cast<float>(lane_map_width_);
263 int x_right = static_cast<int>(x_right_map);
264 if (right_index != -1 && x_right < lane_map_width_ - 1 && x_right > 0) {
265 int pos_right = pixel_y * lane_map_width_ + x_right;
266 score_right_vec[pos_right] += score;
267 x_right_vec[pos_right] += x_right_map;
268 ++x_right_count[pos_right];
269 }
270 }
271
272 const base::BBox2DI& bbox = lane_cc.GetBBox();
273 int ymax = bbox.ymax;
274 int ymin = bbox.ymin;
275 for (int j = ymin; j <= ymax; j++) {
276 int start_pos = j * lane_map_width_;
277 // Find the position with maximum value for left side
278 if (left_index != -1) {
279 float* score_left_pointer = score_left_vec + start_pos;
280 float* x_left_pointer = x_left_vec + start_pos;
281 int* x_left_count_pointer = x_left_count + start_pos;
282 LanePointInfo left_point;
283 bool left_flag = MaxScorePoint(score_left_pointer, x_left_pointer,
284 x_left_count_pointer, j, &left_point);
285 if (left_flag) {
286 (*lane_map_group_point_set)[left_index].push_back(left_point);
287 }
288 }
289
290 // find the position with maximum value for right side
291 if (right_index != -1) {
292 float* score_right_pointer = score_right_vec + start_pos;
293 float* x_right_pointer = x_right_vec + start_pos;
294 int* x_right_count_pointer = x_right_count + start_pos;
295 LanePointInfo right_point;
296 bool right_flag = MaxScorePoint(score_right_pointer, x_right_pointer,
297 x_right_count_pointer, j, &right_point);
298 if (right_flag) {
299 (*lane_map_group_point_set)[right_index].push_back(right_point);
300 }
301 }
302 }
303}
304
305bool DenselineLanePostprocessor::MaxScorePoint(const float* score_pointer,
306 const float* x_pointer,
307 const int* x_count_pointer,
308 int y_pos,
309 LanePointInfo* point_info) {
310 int large_index[2];
311 bool flag = FindKLargeValue(score_pointer, lane_map_width_, 2, large_index);
312 if (!flag) {
313 return false;
314 }
315 int max_x = large_index[0];
316 float max_score = score_pointer[large_index[0]];
317 if (max_score <= laneline_point_score_thresh_) {
318 return false;
319 }
320 (*point_info).x =
321 x_pointer[max_x] / static_cast<float>(x_count_pointer[max_x]);
322 (*point_info).y = static_cast<float>(y_pos);
323 (*point_info).score = max_score / static_cast<float>(x_count_pointer[max_x]);
324 return true;
325}
326
327bool DenselineLanePostprocessor::SelectLanecenterCCs(
328 const std::vector<ConnectedComponent>& lane_ccs,
329 std::vector<ConnectedComponent>* select_lane_ccs) {
330 select_lane_ccs->clear();
331 int lane_ccs_num = static_cast<int>(lane_ccs.size());
332 if (lane_ccs_num == 0) {
333 AINFO << "lane_ccs_num is 0.";
334 return false;
335 }
336 // select top 3 ccs with largest pixels size
337 int valid_pixels_num = static_cast<int>(cc_valid_pixels_ratio_ *
338 static_cast<float>(lane_map_height_));
339 std::vector<ConnectedComponent> valid_lane_ccs;
340 for (int i = 0; i < lane_ccs_num; i++) {
341 const std::vector<base::Point2DI>& pixels = lane_ccs[i].GetPixels();
342 if (static_cast<int>(pixels.size()) < valid_pixels_num) {
343 AINFO << "pixels_size < valid_pixels_num.";
344 continue;
345 }
346 valid_lane_ccs.push_back(lane_ccs[i]);
347 }
348 int valid_ccs_num = static_cast<int>(valid_lane_ccs.size());
349 if (valid_ccs_num == 0) {
350 AINFO << "valid_ccs_num is 0.";
351 return false;
352 }
353 std::sort(valid_lane_ccs.begin(), valid_lane_ccs.end(), CompareCCSize);
354 int select_cc_num = std::min(valid_ccs_num, 3);
355 for (int i = 0; i < select_cc_num; i++) {
356 select_lane_ccs->push_back(valid_lane_ccs[i]);
357 }
358 return true;
359}
360
361// @brief: locate lane line points
362bool DenselineLanePostprocessor::LocateLanelinePointSet(
363 const CameraFrame* frame) {
364 // find laneline_point center_point of each row
365 // 0:adj-left 1:ego-left 2:ego-right 3:adj-right
366 // 1.get the lane points in the feature map
367 auto data_provider = frame->data_provider;
368 input_image_width_ = data_provider->src_width();
369 input_image_height_ = data_provider->src_height();
370 std::vector<int> out_put_shape = frame->lane_detected_blob->shape();
371 int channels = frame->lane_detected_blob->channels();
372 if (channels < net_model_channel_num_) {
373 AERROR << "channel (" << channels << ") is less than net channel ("
374 << net_model_channel_num_ << ")";
375 return false;
376 }
377
378 lane_map_height_ = frame->lane_detected_blob->height();
379 lane_map_width_ = frame->lane_detected_blob->width();
380 const float* output_data = frame->lane_detected_blob->cpu_data();
381 ADEBUG << "input_size: [" << input_image_width_ << "," << input_image_height_
382 << "] "
383 << "output_shape: channels=" << channels
384 << " height=" << lane_map_height_ << " width=" << lane_map_width_;
385
386 image_group_point_set_.clear();
387 image_group_point_set_.resize(4);
388
389 int out_dim = lane_map_width_ * lane_map_height_;
390 lane_map_.clear();
391 lane_output_.clear();
392 lane_map_.resize(out_dim, 0);
393 lane_output_.resize(out_dim * 3, 0);
394 CalLaneMap(output_data, lane_map_width_, lane_map_height_, &lane_map_);
395 // 2.group the lane points
396 base::RectI roi;
397 roi.x = 0;
398 roi.y = 0;
399 roi.width = lane_map_width_;
400 roi.height = lane_map_height_;
401 lane_ccs_.clear();
402 bool flag =
403 FindCC(lane_map_, lane_map_width_, lane_map_height_, roi, &lane_ccs_);
404 if (!flag) {
405 return false;
406 }
407
408 // 3. select lane center ccs
409 flag = SelectLanecenterCCs(lane_ccs_, &select_lane_ccs_);
410 if (!flag) {
411 return false;
412 }
413
414 // 4. Classify the lane_ccs_ type
415 std::vector<LaneType> ccs_pos_type(select_lane_ccs_.size(),
417 flag = ClassifyLaneCCsPosTypeInImage(select_lane_ccs_, &ccs_pos_type);
418 if (!flag) {
419 return false;
420 }
421
422 // 5. get the lane line points
423 std::vector<std::vector<LanePointInfo>> lane_map_group_point_set(4);
424 InferPointSetFromLaneCenter(select_lane_ccs_, ccs_pos_type,
425 &lane_map_group_point_set);
426
427 // 6. convert to the original image
428 Convert2OriginalCoord(lane_map_group_point_set, &image_group_point_set_);
429 return true;
430}
431
432// @brief: classify lane ccs type in image domain
433bool DenselineLanePostprocessor::ClassifyLaneCCsPosTypeInImage(
434 const std::vector<ConnectedComponent>& select_lane_ccs,
435 std::vector<LaneType>* ccs_pos_type) {
436 //
437 int ccs_num = static_cast<int>(select_lane_ccs.size());
438 std::vector<float> cc_bottom_center_x(ccs_num);
439 float min_dist = 1e6;
440 int min_index = -1;
441 float lane_map_center_x = static_cast<float>(lane_map_width_ >> 1);
442 for (int i = 0; i < ccs_num; i++) {
443 const std::vector<base::Point2DI>& pixels = select_lane_ccs[i].GetPixels();
444 const base::BBox2DI& bbox = select_lane_ccs[i].GetBBox();
445 int x_min = -1;
446 int x_max = -1;
447 int y_max = bbox.ymax;
448 for (int j = 0; j < static_cast<int>(pixels.size()); j++) {
449 int pixel_y = pixels[j].y;
450 if (pixel_y != y_max) {
451 continue;
452 }
453 int pixel_x = pixels[j].x;
454 if (x_min == -1) {
455 x_min = pixel_x;
456 } else {
457 x_min = std::min(x_min, pixel_x);
458 }
459 if (x_max == -1) {
460 x_max = pixel_x;
461 } else {
462 x_max = std::max(x_max, pixel_x);
463 }
464 }
465 cc_bottom_center_x[i] = static_cast<float>(x_min + x_max) / 2.0f;
466 float dist =
467 static_cast<float>(fabs(cc_bottom_center_x[i] - lane_map_center_x));
468 if (dist < min_dist) {
469 min_dist = dist;
470 min_index = i;
471 }
472 }
473 if (min_index == -1) {
474 AERROR << "min_index=-1";
475 return false;
476 }
477 // 0: ego-lane
478 // 1: adj-left lane
479 // 2: adj-right lane
480 float center_x = cc_bottom_center_x[min_index];
481 // ego lane
482 (*ccs_pos_type)[min_index] = LaneType::EGO_LANE;
483 for (int i = 0; i < ccs_num; i++) {
484 if (i == min_index) {
485 continue;
486 }
487 if (cc_bottom_center_x[i] > center_x) {
488 // adj-right lane
489 (*ccs_pos_type)[i] = LaneType::ADJACENT_RIGHT_LANE;
490 } else if (cc_bottom_center_x[i] < center_x) {
491 // adj-left lane
492 (*ccs_pos_type)[i] = LaneType::ADJACENT_LEFT_LANE;
493 }
494 }
495 return true;
496}
497
498// @brief classify lane line pos type in image
499// [adj-left/ego-left/ego-right/adj-right]
500void DenselineLanePostprocessor::ClassifyLanelinePosTypeInImage(
501 const std::vector<std::vector<LanePointInfo>>& image_group_point_set,
502 std::vector<base::LaneLinePositionType>* laneline_type,
503 std::vector<bool>* line_flag) {
504 int set_size = static_cast<int>(image_group_point_set.size());
505 std::vector<float> latitude_intersection(set_size, lane_max_value_);
506
507 int ego_left_index = -1;
508 int ego_right_index = -1;
509 float ego_left_value = -1e6;
510 float ego_right_value = 1e6;
511 float lane_center_pos = static_cast<float>(input_image_width_ >> 1);
512 for (int i = 0; i < set_size; i++) {
513 int point_num = static_cast<int>(image_group_point_set[i].size());
514 if (point_num <= laneline_point_min_num_thresh_) {
515 continue;
516 }
517 float fx0 = image_group_point_set[i][point_num - 2].x;
518 float fy0 = image_group_point_set[i][point_num - 2].y;
519 float fx1 = image_group_point_set[i][point_num - 1].x;
520 float fy1 = image_group_point_set[i][point_num - 1].y;
521 float dif_x = fx1 - fx0;
522 float dif_y = fy1 - fy0;
523 if (fabs(dif_y) < 1e-3) {
524 latitude_intersection[i] = fx1;
525 } else {
526 float fk = dif_x / dif_y;
527 float fb = fx1 - fk * fy1;
528 latitude_intersection[i] =
529 fk * static_cast<float>(input_image_height_ - 1) + fb;
530 }
531 if (latitude_intersection[i] <= lane_center_pos &&
532 latitude_intersection[i] > ego_left_value) {
533 ego_left_value = latitude_intersection[i];
534 ego_left_index = i;
535 }
536 if (latitude_intersection[i] > lane_center_pos &&
537 latitude_intersection[i] < ego_right_value) {
538 ego_right_value = latitude_intersection[i];
539 ego_right_index = i;
540 }
541 }
542 if (ego_left_index != -1) {
543 (*laneline_type)[ego_left_index] = base::LaneLinePositionType::EGO_LEFT;
544 (*line_flag)[ego_left_index] = true;
545 }
546 if (ego_right_index != -1) {
547 (*laneline_type)[ego_right_index] = base::LaneLinePositionType::EGO_RIGHT;
548 (*line_flag)[ego_right_index] = true;
549 }
550 // locate adjacent left laneline
551 int adj_left_index = -1;
552 LocateNeighborLaneLine(latitude_intersection, ego_left_index, true,
553 &adj_left_index);
554 if (adj_left_index != -1) {
555 (*laneline_type)[adj_left_index] =
557 (*line_flag)[adj_left_index] = true;
558 }
559 // locate adjacent right laneline
560 int adj_right_index = -1;
561 LocateNeighborLaneLine(latitude_intersection, ego_right_index, false,
562 &adj_right_index);
563 if (adj_right_index != -1) {
564 (*laneline_type)[adj_right_index] =
566 (*line_flag)[adj_right_index] = true;
567 }
568}
569
570// @brief: locate neighbor lane lines
571bool DenselineLanePostprocessor::LocateNeighborLaneLine(
572 const std::vector<float>& latitude_intersection, int line_index,
573 bool left_flag, int* locate_index) {
574 // left_flag = true: find the line which is at left side of the line
575 // left_flag = false: find the line which is at right side of the line
576 int set_size = static_cast<int>(latitude_intersection.size());
577 if (line_index < 0 || line_index >= set_size) {
578 return false;
579 }
580 float intersection_x = latitude_intersection[line_index];
581 if (left_flag) {
582 float max_value = -1e6;
583 for (int i = 0; i < set_size; i++) {
584 if (latitude_intersection[i] >= intersection_x ||
585 latitude_intersection[i] >= lane_max_value_) {
586 continue;
587 }
588 if (latitude_intersection[i] > max_value) {
589 max_value = latitude_intersection[i];
590 *locate_index = i;
591 }
592 }
593 } else {
594 float min_value = 1e6;
595 for (int i = 0; i < set_size; i++) {
596 if (latitude_intersection[i] <= intersection_x ||
597 latitude_intersection[i] >= lane_max_value_) {
598 continue;
599 }
600 if (latitude_intersection[i] < min_value) {
601 min_value = latitude_intersection[i];
602 *locate_index = i;
603 }
604 }
605 }
606 return true;
607}
608
609// @brief: convert the point to the original image
610void DenselineLanePostprocessor::Convert2OriginalCoord(
611 const std::vector<std::vector<LanePointInfo>>& lane_map_group_point_set,
612 std::vector<std::vector<LanePointInfo>>* image_group_point_set) {
613 float x_ratio =
614 static_cast<float>(input_crop_width_) * lane_map_width_inverse_;
615 float y_ratio =
616 static_cast<float>(input_crop_height_) * lane_map_height_inverse_;
617 for (int i = 0; i < static_cast<int>(lane_map_group_point_set.size()); i++) {
618 for (int j = 0; j < static_cast<int>(lane_map_group_point_set[i].size());
619 j++) {
620 LanePointInfo lane_map_info = lane_map_group_point_set[i][j];
621 LanePointInfo original_info;
622 original_info.x =
623 lane_map_info.x * x_ratio + static_cast<float>(input_offset_x_);
624 original_info.y =
625 lane_map_info.y * y_ratio + static_cast<float>(input_offset_y_);
626 original_info.score = lane_map_info.score;
627 (*image_group_point_set)[i].push_back(original_info);
628 }
629 }
630}
631
632// @brief: add image lane line
633void DenselineLanePostprocessor::AddImageLaneline(
634 const std::vector<LanePointInfo>& image_point_set,
635 const base::LaneLineType type, const base::LaneLinePositionType pos_type,
636 int line_index, std::vector<base::LaneLine>* lane_marks) {
637 // x: longitudinal direction
638 // y: horizontal direction
639 // image: x = f(y)
640 int image_point_set_size = static_cast<int>(image_point_set.size());
641 if (image_point_set_size <= laneline_point_min_num_thresh_) {
642 return;
643 }
644 base::LaneLine lane_mark;
645 EigenVector<Eigen::Matrix<float, 2, 1>> img_pos_vec(image_point_set_size);
646 Eigen::Matrix<float, max_poly_order + 1, 1> img_coeff;
647 bool is_x_axis = false;
648 float r_start = -1;
649 float r_end = -1;
650 float confidence = 0.0f;
651 lane_mark.curve_image_point_set.resize(image_point_set_size);
652 for (int i = 0; i < image_point_set_size; i++) {
653 float x_pos = image_point_set[i].x;
654 float y_pos = image_point_set[i].y;
655 img_pos_vec[i] << x_pos, y_pos;
656 lane_mark.curve_image_point_set[i].x = image_point_set[i].x;
657 lane_mark.curve_image_point_set[i].y = image_point_set[i].y;
658 if (r_start == -1) {
659 r_start = y_pos;
660 } else if (y_pos < r_start) {
661 r_start = y_pos;
662 }
663 if (r_end == -1) {
664 r_end = y_pos;
665 } else if (y_pos > r_end) {
666 r_end = y_pos;
667 }
668 confidence += image_point_set[i].score;
669 }
670 confidence /= static_cast<float>(image_point_set_size);
671
672 bool fit_flag = PolyFit(img_pos_vec, max_poly_order, &img_coeff, is_x_axis);
673 if (!fit_flag) {
674 return;
675 }
676 // check the validity of laneline
677 float sum_dist = 0.0f;
678 float avg_dist = 0.0f;
679 int count = 0;
680 for (int i = 0; i < image_point_set_size; i++) {
681 float x_pos = img_pos_vec[i](0, 0);
682 float y_pos = img_pos_vec[i](1, 0);
683 float x_poly = 0.0f;
684 PolyEval(y_pos, max_poly_order, img_coeff, &x_poly);
685 float dist = static_cast<float>(fabs(x_poly - x_pos));
686 sum_dist += dist;
687 count++;
688 }
689 if (count > 0) {
690 avg_dist = sum_dist / static_cast<float>(count);
691 }
692 if (avg_dist >= laneline_reject_dist_thresh_) {
693 AERROR << "avg_dist>=laneline_reject_dist_thresh_";
694 return;
695 }
696 lane_mark.curve_image_coord.a = img_coeff(3, 0);
697 lane_mark.curve_image_coord.b = img_coeff(2, 0);
698 lane_mark.curve_image_coord.c = img_coeff(1, 0);
699 lane_mark.curve_image_coord.d = img_coeff(0, 0);
700 lane_mark.curve_image_coord.x_start = r_start;
701 lane_mark.curve_image_coord.x_end = r_end;
702
703 lane_mark.confidence = confidence;
704 lane_mark.track_id = line_index;
705 lane_mark.type = type;
706 lane_mark.pos_type = pos_type;
707 lane_marks->push_back(lane_mark);
708}
709
710// @brief: fit camera lane line using polynomial
711void DenselineLanePostprocessor::PolyFitCameraLaneline(CameraFrame* frame) {
712 std::vector<base::LaneLine>& lane_objects = frame->lane_objects;
713 int laneline_num = static_cast<int>(lane_objects.size());
714 for (int line_index = 0; line_index < laneline_num; line_index++) {
715 const std::vector<base::Point3DF>& camera_point_set =
716 lane_objects[line_index].curve_camera_point_set;
717 // z: longitudinal direction
718 // x: latitudinal direction
719 float x_start = camera_point_set[0].z;
720 float x_end = 0.0f;
721 Eigen::Matrix<float, max_poly_order + 1, 1> camera_coeff;
722 EigenVector<Eigen::Matrix<float, 2, 1>> camera_pos_vec;
723 for (int i = 0; i < static_cast<int>(camera_point_set.size()); i++) {
724 x_end = std::max(camera_point_set[i].z, x_end);
725 x_start = std::min(camera_point_set[i].z, x_start);
726 Eigen::Matrix<float, 2, 1> camera_pos;
727 camera_pos << camera_point_set[i].z, camera_point_set[i].x;
728 camera_pos_vec.push_back(camera_pos);
729 }
730
731 bool is_x_axis = true;
732 bool fit_flag =
733 PolyFit(camera_pos_vec, max_poly_order, &camera_coeff, is_x_axis);
734 if (!fit_flag) {
735 continue;
736 }
737 lane_objects[line_index].curve_camera_coord.a = camera_coeff(3, 0);
738 lane_objects[line_index].curve_camera_coord.b = camera_coeff(2, 0);
739 lane_objects[line_index].curve_camera_coord.c = camera_coeff(1, 0);
740 lane_objects[line_index].curve_camera_coord.d = camera_coeff(0, 0);
741 lane_objects[line_index].curve_camera_coord.x_start = x_start;
742 lane_objects[line_index].curve_camera_coord.x_end = x_end;
743 lane_objects[line_index].curve_car_coord.a = -camera_coeff(3, 0);
744 lane_objects[line_index].curve_car_coord.b = -camera_coeff(2, 0);
745 lane_objects[line_index].curve_car_coord.c = -camera_coeff(1, 0);
746 lane_objects[line_index].curve_car_coord.d = -camera_coeff(0, 0);
747 lane_objects[line_index].curve_car_coord.x_start = x_start;
748 lane_objects[line_index].curve_car_coord.x_end = x_end;
749 lane_objects[line_index].use_type = base::LaneLineUseType::REAL;
750 }
751}
752
753std::vector<std::vector<LanePointInfo>>
755 return image_group_point_set_;
756}
757
758std::vector<LanePointInfo>
760 float x_ratio =
761 static_cast<float>(input_crop_width_) * lane_map_width_inverse_;
762 float y_ratio =
763 static_cast<float>(input_crop_height_) * lane_map_height_inverse_;
764 image_laneline_point_set_.clear();
765 int lane_map_dim = lane_map_width_ * lane_map_height_;
766 float lane_map_width_float = static_cast<float>(lane_map_width_);
767 for (int i = 0; i < lane_map_height_; i++) {
768 for (int j = 0; j < lane_map_width_; j++) {
769 int pixel_pos = i * lane_map_width_ + j;
770 float score = lane_output_[lane_map_dim * 2 + pixel_pos];
771 if (score < laneline_point_score_thresh_) {
772 continue;
773 }
774 float dist_left = lane_output_[pixel_pos];
775 float dist_right = lane_output_[lane_map_dim + pixel_pos];
776 float map_x_left =
777 static_cast<float>(j) - dist_left * lane_map_width_float;
778 float map_x_right =
779 static_cast<float>(j) + dist_right * lane_map_width_float;
780 float org_img_y =
781 static_cast<float>(i) * y_ratio + static_cast<float>(input_offset_y_);
782 if (map_x_left > 0) {
783 LanePointInfo left_point;
784 float org_img_x_left =
785 map_x_left * x_ratio + static_cast<float>(input_offset_x_);
786 left_point.x = org_img_x_left;
787 left_point.y = org_img_y;
788 left_point.score = score;
789 image_laneline_point_set_.push_back(left_point);
790 }
791 if (map_x_right < lane_map_width_float) {
792 LanePointInfo right_point;
793 float org_img_x_right =
794 map_x_right * x_ratio + static_cast<float>(input_offset_x_);
795 right_point.x = org_img_x_right;
796 right_point.y = org_img_y;
797 right_point.score = score;
798 image_laneline_point_set_.push_back(right_point);
799 }
800 }
801 }
802 return image_laneline_point_set_;
803}
804
806 std::vector<unsigned char>* lane_map, int* lane_map_width,
807 int* lane_map_height, std::vector<ConnectedComponent>* connected_components,
808 std::vector<ConnectedComponent>* select_connected_components) {
809 *lane_map = lane_map_;
810 *lane_map_width = lane_map_width_;
811 *lane_map_height = lane_map_height_;
812 *connected_components = lane_ccs_;
813 *select_connected_components = select_lane_ccs_;
814}
815
817 return "DenselineLanePostprocessor";
818}
819
821} // namespace camera
822} // namespace perception
823} // namespace apollo
#define REGISTER_LANE_POSTPROCESSOR(name)
int offset(const int n, const int c=0, const int h=0, const int w=0) const
Definition blob.h:231
void Reshape(const int num, const int channels, const int height, const int width)
Deprecated; use Reshape(const std::vector<int>& shape).
Definition blob.cc:72
bool Process3D(const LanePostprocessorOptions &options, CameraFrame *frame) override
bool Process2D(const LanePostprocessorOptions &options, CameraFrame *frame) override
std::vector< std::vector< LanePointInfo > > GetLanelinePointSet()
bool Init(const LanePostprocessorInitOptions &options=LanePostprocessorInitOptions()) override
void GetLaneCCs(std::vector< unsigned char > *lane_map, int *lane_map_width, int *lane_map_height, std::vector< ConnectedComponent > *connected_components, std::vector< ConnectedComponent > *select_connected_components)
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
std::vector< EigenType, Eigen::aligned_allocator< EigenType > > EigenVector
Definition eigen_defs.h:33
bool GetProtoFromFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the file specified by the file_name as a representation of protobufs,...
Definition file.cc:132
Rect< int > RectI
Definition box.h:159
Point3D< float > Point3DF
Definition point.h:98
LaneLinePositionType
Definition of the position of a lane marking in respect to the ego lane.
Definition lane_struct.h:34
@ ADJACENT_RIGHT
lane marking on the right side next to ego lane
@ ADJACENT_LEFT
lane marking on the left side next to ego lane
@ EGO_LEFT
left lane marking of the ego lane
@ EGO_RIGHT
right lane marking of the ego lane
BBox2D< int > BBox2DI
Definition box.h:163
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)
bool PolyEval(const Dtype &x, int order, const Eigen::Matrix< Dtype, max_poly_order+1, 1 > &coeff, Dtype *y)
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)
std::string GetConfigFile(const std::string &config_path, const std::string &config_file)
Definition util.cc:80
class register implement
Definition arena_queue.h:37
BaseCalibrationService * calibration_service
std::vector< base::LaneLine > lane_objects