Apollo 11.0
自动驾驶开放平台
cipv_camera.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2019 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
18
19#include <algorithm>
20#include <cmath>
21#include <limits>
22
23#include "cyber/common/log.h"
25
26namespace apollo {
27namespace perception {
28namespace camera {
29
30bool Cipv::Init(const Eigen::Matrix3d &homography_im2car,
31 const CipvInitOptions &options) {
32 b_image_based_cipv_ = options.image_based_cipv;
33 debug_level_ =
34 options.debug_level;
35 // 0: no debug message
36 // 1: minimal output
37 // 2: some important output
38 // 3: verbose message
39 // 4: visualization
40 // 5: all
41 // -x: specific debugging, where x is the specific number
42 time_unit_ = options.average_frame_rate;
43 homography_im2car_ = homography_im2car;
44 homography_car2im_ = homography_im2car.inverse();
45
46 min_laneline_length_for_cipv_ = options.min_laneline_length_for_cipv;
47 average_lane_width_in_meter_ = options.average_lane_width_in_meter;
48 max_vehicle_width_in_meter_ = options.max_vehicle_width_in_meter;
49 margin_vehicle_to_lane_ =
50 (average_lane_width_in_meter_ - max_vehicle_width_in_meter_) * 0.5f;
51 single_virtual_egolane_width_in_meter_ = max_vehicle_width_in_meter_;
52 half_vehicle_width_in_meter_ = max_vehicle_width_in_meter_ * 0.5f;
53 half_virtual_egolane_width_in_meter_ =
54 single_virtual_egolane_width_in_meter_ * 0.5f;
55 old_cipv_track_id_ = -2;
56
57 return true;
58}
59
61 const CipvOptions &options,
62 const Eigen::Affine3d &world2camera,
63 const base::MotionBufferPtr &motion_buffer) {
64 DetermineCipv(frame->lane_objects, options, world2camera,
65 &frame->tracked_objects);
66
67 // Get Drop points
68 if (motion_buffer->size() > 0) {
69 CollectDrops(motion_buffer, world2camera, &frame->tracked_objects);
70 } else {
71 AWARN << "motion_buffer is empty";
72 }
73 return true;
74}
75
76// Distance from a point to a line segment
77bool Cipv::DistanceFromPointToLineSegment(const Point2Df &point,
78 const Point2Df &line_seg_start_point,
79 const Point2Df &line_seg_end_point,
80 float *distance) {
81 apollo::common::math::Vec2d p = {point(0), point(1)};
83 {line_seg_start_point(0), line_seg_start_point(1)},
84 {line_seg_end_point(0), line_seg_end_point(1)});
85 if (line_seg.length_sqr() <= kFloatEpsilon) {
86 // line length = 0
87 return false;
88 }
89 *distance = static_cast<float>(line_seg.DistanceTo(p));
90 return true;
91}
92
93// Select CIPV among multiple objects
94bool Cipv::GetEgoLane(const std::vector<base::LaneLine> &lane_objects,
95 EgoLane *egolane_image, EgoLane *egolane_ground,
96 bool *b_left_valid, bool *b_right_valid) {
97 float x, y;
98 for (size_t i = 0; i < lane_objects.size(); ++i) {
99 const auto &lane_object = lane_objects[i];
100 const size_t curve_image_point_size =
101 lane_object.curve_image_point_set.size();
102 const size_t curve_car_coord_point_set_size =
103 lane_object.curve_car_coord_point_set.size();
104 if (lane_object.pos_type == base::LaneLinePositionType::EGO_LEFT) {
105 if (debug_level_ >= 2) {
106 AINFO << "[GetEgoLane]LEFT_image_lane_objects[" << i
107 << "].curve_image_point_set.size(): " << curve_image_point_size;
108 AINFO << "[GetEgoLane]LEFT_ground_lane_objects[" << i
109 << "].curve_car_coord_point_set_size: "
110 << curve_car_coord_point_set_size;
111 }
112 if (curve_image_point_size < min_laneline_length_for_cipv_) {
113 *b_left_valid = false;
114 } else {
115 *b_left_valid = true;
116
117 for (size_t j = 0; j < curve_car_coord_point_set_size; ++j) {
118 // ground_point
119 x = lane_object.curve_car_coord_point_set[j].x;
120 y = lane_object.curve_car_coord_point_set[j].y;
121 egolane_ground->left_line.line_point.emplace_back(x, y);
122 }
123 for (size_t j = 0; j < curve_image_point_size; ++j) {
124 // image_point
125 x = lane_object.curve_image_point_set[j].x;
126 y = lane_object.curve_image_point_set[j].y;
127 egolane_image->left_line.line_point.emplace_back(x, y);
128 }
129 }
130 } else if (lane_object.pos_type == base::LaneLinePositionType::EGO_RIGHT) {
131 if (debug_level_ >= 2) {
132 AINFO << "[GetEgoLane]RIGHT_image_lane_objects[" << i
133 << "].curve_image_point_set.size(): " << curve_image_point_size;
134 AINFO << "[GetEgoLane]RIGHT_ground_lane_objects[" << i
135 << "].curve_car_coord_point_set_size: "
136 << curve_car_coord_point_set_size;
137 }
138 if (curve_image_point_size < min_laneline_length_for_cipv_) {
139 *b_right_valid = false;
140 } else {
141 *b_right_valid = true;
142 for (size_t j = 0; j < curve_car_coord_point_set_size; ++j) {
143 // ground_point
144 x = lane_object.curve_car_coord_point_set[j].x;
145 y = lane_object.curve_car_coord_point_set[j].y;
146 egolane_ground->right_line.line_point.emplace_back(x, y);
147 }
148 for (size_t j = 0; j < curve_image_point_size; ++j) {
149 // image_point
150 x = lane_object.curve_image_point_set[j].x;
151 y = lane_object.curve_image_point_set[j].y;
152 egolane_image->right_line.line_point.emplace_back(x, y);
153 }
154 }
155 }
156 }
157 return true;
158}
159
160// Make a virtual lane line using a reference lane line and its offset distance
161bool Cipv::MakeVirtualLane(const LaneLineSimple &ref_lane_line,
162 const float yaw_rate, const float offset_distance,
163 LaneLineSimple *virtual_lane_line) {
164 // TODO(techoe): Use union of lane line and yaw_rate path to define the
165 // virtual lane
166 virtual_lane_line->line_point.clear();
167 for (uint32_t i = 0; i < ref_lane_line.line_point.size(); ++i) {
168 virtual_lane_line->line_point.emplace_back(
169 ref_lane_line.line_point[i](0),
170 ref_lane_line.line_point[i](1) + offset_distance);
171 }
172 return true;
173}
174
175float Cipv::VehicleDynamics(const uint32_t tick, const float yaw_rate,
176 const float velocity, const float time_unit,
177 float *x, float *y) {
178 // Option 1. Straight model;
179 // *x = time_unit * velocity * static_cast<float>(tick);
180 // *y = 0.0f;
181
182 // Option 2. Sphere model
183 float adjusted_velocity = std::max(kMinVelocity, velocity);
184 float theta = static_cast<float>(tick) * time_unit * yaw_rate;
185 float displacement = static_cast<float>(tick) * time_unit * adjusted_velocity;
186 *x = displacement * static_cast<float>(cos(theta));
187 *y = displacement * static_cast<float>(sin(theta));
188
189 // Option 3. Bicycle model
190 // TODO(techoe): Apply bicycle model for vehicle dynamics (need wheel base)
191
192 return true;
193}
194
195// Provide vehicle dynamics considersing vehicle size
196float Cipv::VehicleDynamics(const uint32_t tick, const float yaw_rate,
197 const float velocity, const float time_unit,
198 const float half_vehicle_width, float *center_x,
199 float *center_y, float *left_x, float *left_y,
200 float *right_x, float *right_y) {
201 // Option 1. Straight model;
202 // *x = time_unit * velocity * static_cast<float>(tick);
203 // *y = 0.0f;
204
205 // Option 2. Sphere model
206 float adjusted_velocity = std::max(kMinVelocity, velocity);
207 float theta = static_cast<float>(tick) * time_unit * yaw_rate;
208 float displacement = static_cast<float>(tick) * time_unit * adjusted_velocity;
209 float offset = half_vehicle_width;
210 *center_x = displacement * static_cast<float>(cos(theta));
211 *center_y = displacement * static_cast<float>(sin(theta));
212 if (theta < 0) {
213 offset = -half_vehicle_width;
214 }
215 *left_x = (displacement + offset) * static_cast<float>(cos(theta)) - offset;
216 *left_y = (displacement + offset) * static_cast<float>(sin(theta)) +
217 half_vehicle_width;
218 *right_x = (displacement - offset) * static_cast<float>(cos(theta)) + offset;
219 *right_y = (displacement - offset) * static_cast<float>(sin(theta)) -
220 half_vehicle_width;
221
222 // Option 3. Bicycle model
223 // TODO(techoe): Apply bicycle model for vehicle dynamics (need wheel base)
224
225 return true;
226}
227
228// Make a virtual lane line using a yaw_rate
229bool Cipv::MakeVirtualEgoLaneFromYawRate(const float yaw_rate,
230 const float velocity,
231 const float offset_distance,
232 LaneLineSimple *left_lane_line,
233 LaneLineSimple *right_lane_line) {
234 float center_x = 0.0f;
235 float center_y = 0.0f;
236 float left_x = 0.0f;
237 float left_y = 0.0f;
238 float right_x = 0.0f;
239 float right_y = 0.0f;
240 left_lane_line->line_point.clear();
241 right_lane_line->line_point.clear();
242
243 for (uint32_t i = 1; i < kMaxNumVirtualLanePoint; ++i) {
244 VehicleDynamics(i, yaw_rate, velocity, kAverageFrameRate, offset_distance,
245 &center_x, &center_y, &left_x, &left_y, &right_x, &right_y);
246 Point2Df left_point(left_x, left_y);
247 left_lane_line->line_point.emplace_back(left_point);
248 Point2Df right_point(right_x, right_y);
249 right_lane_line->line_point.emplace_back(right_point);
250 }
251 return true;
252}
253
254// Elongate lane line
255bool Cipv::ElongateEgoLane(const std::vector<base::LaneLine> &lane_objects,
256 const bool b_left_valid, const bool b_right_valid,
257 const float yaw_rate, const float velocity,
258 EgoLane *egolane_image, EgoLane *egolane_ground) {
259 float offset_distance = half_virtual_egolane_width_in_meter_;
260 // When left lane line is available
261 if (b_left_valid && b_right_valid) {
262 // elongate both lanes or do nothing
263 if (debug_level_ >= 2) {
264 AINFO << "Both lanes are fine";
265 }
266 // When only left lane line is available
267 } else if (!b_left_valid && b_right_valid) {
268 // Generate virtual left lane based on right lane
269 offset_distance = single_virtual_egolane_width_in_meter_;
270 MakeVirtualLane(egolane_ground->right_line, yaw_rate, offset_distance,
271 &egolane_ground->left_line);
272 if (debug_level_ >= 2) {
273 AINFO << "Made left lane with offset: " << offset_distance;
274 }
275
276 // When only right lane line is available
277 } else if (b_left_valid && !b_right_valid) {
278 // Generate virtual right lane based on left lane
279 offset_distance = -single_virtual_egolane_width_in_meter_;
280 MakeVirtualLane(egolane_ground->left_line, yaw_rate, offset_distance,
281 &egolane_ground->right_line);
282 if (debug_level_ >= 2) {
283 AINFO << "Made right lane with offset: " << offset_distance;
284 }
285 }
286 return true;
287}
288
289// Create virtual lane line
290bool Cipv::CreateVirtualEgoLane(const float yaw_rate, const float velocity,
291 EgoLane *egolane_ground) {
292 float offset_distance = half_vehicle_width_in_meter_;
293 // Generate new egolane using yaw-rate velocity
294 MakeVirtualEgoLaneFromYawRate(yaw_rate, velocity, offset_distance,
295 &egolane_ground->left_line,
296 &egolane_ground->right_line);
297 if (debug_level_ >= 2) {
298 AINFO << "Made both lane_objects with size of "
299 << egolane_ground->left_line.line_point.size();
300 }
301
302 return true;
303}
304
305// Get closest edge of an object in image coordinate
306bool Cipv::FindClosestObjectImage(const std::shared_ptr<base::Object> &object,
307 const EgoLane &egolane_image,
308 LineSegment2Df *closted_object_edge,
309 float *distance) {
310 float size_x = object->size(0);
311 float size_y = object->size(1);
312 float size_z = object->size(2);
313
314 if (size_x < 1.0e-2 && size_y < 1.0e-2 && size_z < 1.0e-2) {
315 // size_x = 0.1;
316 // size_y = 0.1;
317 // size_z = 0.1;
318 return false;
319 }
320 // Footprint (left + width/2, top + height) as a center position
321 float center_x = (object->camera_supplement.box.xmin +
322 object->camera_supplement.box.xmin) *
323 0.5f;
324 float center_y = object->camera_supplement.box.ymax;
325
326 if (debug_level_ >= 3) {
327 AINFO << "object->camera_supplement.box = base::RectF("
328 << object->camera_supplement.box.xmin << ", "
329 << object->camera_supplement.box.ymin << ", "
330 << object->camera_supplement.box.xmax -
331 object->camera_supplement.box.xmin
332 << ", "
333 << object->camera_supplement.box.ymax -
334 object->camera_supplement.box.ymin
335 << ");";
336 }
337 closted_object_edge->start_point(0) = object->camera_supplement.box.xmin;
338 closted_object_edge->start_point(1) = object->camera_supplement.box.ymax;
339
340 closted_object_edge->end_point(0) = object->camera_supplement.box.xmax;
341 closted_object_edge->end_point(1) = object->camera_supplement.box.ymax;
342
343 *distance =
344 static_cast<float>(sqrt(center_x * center_x + center_y * center_y));
345 if (debug_level_ >= 2) {
346 AINFO << "start(" << closted_object_edge->start_point(0) << ", "
347 << closted_object_edge->start_point(1) << ")->";
348 AINFO << "end(" << closted_object_edge->end_point(0) << ", "
349 << closted_object_edge->end_point(1) << ")";
350 AINFO << "closest distance: " << *distance;
351 }
352 return true;
353}
354// Get closest edge of an object in ground coordinate
355// TODO(techoe): This function should be changed to find min-y and max-y edges
356// to decide CIPV.
357bool Cipv::FindClosestObjectGround(const std::shared_ptr<base::Object> &object,
358 const EgoLane &egolane_ground,
359 const Eigen::Affine3d &world2camera,
360 LineSegment2Df *closted_object_edge,
361 float *distance) {
362 if (debug_level_ >= 2) {
363 AINFO << "object->track_id = " << object->track_id;
364 }
365 float size_x = object->size(0);
366 float size_y = object->size(1);
367 float size_z = object->size(2);
368 if (size_x < 1.0e-2 && size_y < 1.0e-2 && size_z < 1.0e-2) {
369 // size_x = 0.1;
370 // size_y = 0.1;
371 // size_z = 0.1;
372 return false;
373 }
374 // Option 1. Get position from center
375 auto pos = world2camera * object->center;
376 float center_x = static_cast<float>(pos(2));
377 float center_y = static_cast<float>(-pos(0));
378
379 // Option 2. Homography based 3D inference
380 // base::RectF rect(object->camera_supplement.box);
381 // float footprint_x = static_cast<float>(rect.x + rect.width * 0.5);
382 // float footprint_y = static_cast<float>(rect.y + rect.height);
383 // float center_x;
384 // float center_y;
385 // image2ground(footprint_x, footprint_y, &center_x, &center_y);
386
387 double theta_ray = atan2(pos(0), pos(2));
388 double theta = object->camera_supplement.alpha + theta_ray;
389 theta -= M_PI_2;
390
391 if (debug_level_ >= 3) {
392 AINFO << "object->camera_supplement.box = base::RectF("
393 << object->camera_supplement.box.xmin << ", "
394 << object->camera_supplement.box.ymin << ", "
395 << object->camera_supplement.box.xmax -
396 object->camera_supplement.box.xmin
397 << ", "
398 << object->camera_supplement.box.ymax -
399 object->camera_supplement.box.ymin
400 << ");";
401
402 AINFO << "object.center(0) = " << object->center(0) << ";";
403 AINFO << "object.center(1) = " << object->center(1) << ";";
404 AINFO << "object.center(2) = " << object->center(2) << ";";
405 AINFO << "pos(0) = " << pos(0) << ";";
406 AINFO << "pos(1) = " << pos(1) << ";";
407 AINFO << "pos(2) = " << pos(2) << ";";
408 AINFO << "object->camera_supplement.local_center(0) = "
409 << object->camera_supplement.local_center(0) << ";";
410 AINFO << "object->camera_supplement.local_center(1) = "
411 << object->camera_supplement.local_center(1) << ";";
412 AINFO << "object->camera_supplement.local_center(2) = "
413 << object->camera_supplement.local_center(2) << ";";
414 AINFO << "theta_ray = " << theta_ray << ";";
415 AINFO << "object->camera_supplement.alpha = "
416 << object->camera_supplement.alpha << ";";
417 AINFO << "theta = " << theta << ";";
418 AINFO << "object.anchor_point(0) = " << object->anchor_point(0) << ";";
419 AINFO << "object.anchor_point(1) = " << object->anchor_point(1) << ";";
420 AINFO << "object.anchor_point(2) = " << object->anchor_point(2) << ";";
421 AINFO << "object.direction(0) = " << object->direction(0) << ";";
422 AINFO << "object.direction(1) = " << object->direction(1) << ";";
423 AINFO << "object.direction(2) = " << object->direction(2) << ";";
424 AINFO << "object.size(0) = " << object->size(0) << ";";
425 AINFO << "object.size(1) = " << object->size(1) << ";";
426 AINFO << "object.size(2) = " << object->size(2) << ";";
427 }
428 float x1 = size_x * 0.5f;
429 float x2 = -x1;
430 float y1 = size_y * 0.5f;
431 float y2 = -y1;
432 float cos_theta = static_cast<float>(cos(theta)); // direction_x / len;
433 float sin_theta = static_cast<float>(sin(theta)); // -direction_y / len;
434
435 Point2Df p[4];
436
437 p[0](0) = x2 * cos_theta + y1 * sin_theta + center_x;
438 p[0](1) = y1 * cos_theta - x2 * sin_theta + center_y;
439
440 p[1](0) = x2 * cos_theta + y2 * sin_theta + center_x;
441 p[1](1) = y2 * cos_theta - x2 * sin_theta + center_y;
442
443 p[2](0) = x1 * cos_theta + y1 * sin_theta + center_x;
444 p[2](1) = y1 * cos_theta - x1 * sin_theta + center_y;
445
446 p[3](0) = x1 * cos_theta + y2 * sin_theta + center_x;
447 p[3](1) = y2 * cos_theta - x1 * sin_theta + center_y;
448
449 if (debug_level_ >= 2) {
450 AINFO << "P0(" << p[0](0) << ", " << p[0](1) << ")";
451 AINFO << "P1(" << p[1](0) << ", " << p[1](1) << ")";
452 AINFO << "P2(" << p[2](0) << ", " << p[2](1) << ")";
453 AINFO << "P3(" << p[3](0) << ", " << p[3](1) << ")";
454 }
455
456 float closest_x = kMaxFloat;
457 float left_y = kMaxFloat;
458 float right_y = -kMaxFloat;
459 int32_t closest_index = -1;
460 int32_t left_index = -1;
461 int32_t right_index = -1;
462 for (int32_t i = 0; i < 4; i++) {
463 if (p[i](1) <= left_y) {
464 left_index = i;
465 left_y = p[i](1);
466 }
467 if (p[i](1) > right_y) {
468 right_index = i;
469 right_y = p[i](1);
470 }
471 if (p[i](0) < closest_x) {
472 closest_index = i;
473 closest_x = p[i](0);
474 }
475 }
476
477 if (left_index < 0 || right_index < 0 || left_index == right_index) {
478 if (debug_level_ >= 2) {
479 AINFO << "left_index: " << left_index;
480 AINFO << "right_index: " << right_index;
481 }
482 return false;
483 }
484
485 closted_object_edge->start_point(0) = p[right_index](0);
486 closted_object_edge->start_point(1) = p[right_index](1);
487
488 closted_object_edge->end_point(0) = p[left_index](0);
489 closted_object_edge->end_point(1) = p[left_index](1);
490
491 // Added filter to consider an object only in front of ego-car.
492 if ((p[left_index](0) < 0 && p[right_index](0) < 0) ||
493 (p[closest_index](0) < 0)) {
494 return false;
495 }
496
497 *distance =
498 static_cast<float>(sqrt(p[closest_index](0) * p[closest_index](0) +
499 p[closest_index](1) * p[closest_index](1)));
500 if (debug_level_ >= 2) {
501 AINFO << "start(" << closted_object_edge->start_point(0) << ", "
502 << closted_object_edge->start_point(1) << ")->";
503 AINFO << "end(" << closted_object_edge->end_point(0) << ", "
504 << closted_object_edge->end_point(1) << ")";
505 AINFO << "closest distance to p[" << closest_index << "]("
506 << p[closest_index](0) << ", " << p[closest_index](1)
507 << "): " << *distance;
508 }
509 return true;
510}
511
512// Check if the distance between lane and object are OK
513bool Cipv::AreDistancesSane(const float distance_start_point_to_right_lane,
514 const float distance_start_point_to_left_lane,
515 const float distance_end_point_to_right_lane,
516 const float distance_end_point_to_left_lane) {
517 float distance = -1.0f;
518 if (distance_start_point_to_right_lane > kMaxDistObjectToLaneInMeter) {
519 if (debug_level_ >= 1) {
520 AINFO << "distance from start to right lane("
521 << distance_start_point_to_right_lane << " m) is too long";
522 }
523 return false;
524 }
525 if (distance_start_point_to_left_lane > kMaxDistObjectToLaneInMeter) {
526 if (debug_level_ >= 1) {
527 AINFO << "distance from start to left lane("
528 << distance_start_point_to_left_lane << " m) is too long";
529 }
530 return false;
531 }
532 if (distance_end_point_to_right_lane > kMaxDistObjectToLaneInMeter) {
533 if (debug_level_ >= 1) {
534 AINFO << "distance from end to right lane("
535 << distance_end_point_to_right_lane << " m) is too long";
536 }
537 return false;
538 }
539 if (distance_end_point_to_left_lane > kMaxDistObjectToLaneInMeter) {
540 if (debug_level_ >= 1) {
541 AINFO << "distance from end to left lane("
542 << distance_end_point_to_left_lane << " m) is too long";
543 }
544 return false;
545 }
546 distance = static_cast<float>(fabs(distance_start_point_to_right_lane -
547 distance_end_point_to_right_lane));
548 if (distance > kMaxVehicleWidthInMeter) {
549 if (debug_level_ >= 1) {
550 AINFO << "width of vehicle (" << distance << " m) is too long";
551 }
552 return false;
553 }
554
555 distance = static_cast<float>(fabs(distance_end_point_to_left_lane -
556 distance_start_point_to_left_lane));
557 if (distance > kMaxVehicleWidthInMeter) {
558 if (debug_level_ >= 1) {
559 AINFO << "width of vehicle (" << distance << " m) is too long";
560 }
561 return false;
562 }
563 // put more conditions here if required.
564
565 // AINFO << "Distances are sane!";
566
567 return true;
568}
569
570// Check if a point is left of a line segment
571bool Cipv::IsPointLeftOfLine(const Point2Df &point,
572 const Point2Df &line_seg_start_point,
573 const Point2Df &line_seg_end_point) {
574 float cross_product = ((line_seg_end_point(0) - line_seg_start_point(0)) *
575 (point(1) - line_seg_start_point(1))) -
576 ((line_seg_end_point(1) - line_seg_start_point(1)) *
577 (point(0) - line_seg_start_point(0)));
578
579 if (cross_product > 0.0f) {
580 if (debug_level_ >= 2) {
581 AINFO << "point (" << point(0) << ", " << point(1)
582 << ") is left of line_segment (" << line_seg_start_point(0) << ", "
583 << line_seg_start_point(1) << ")->(" << line_seg_end_point(0)
584 << ", " << line_seg_end_point(1)
585 << "), cross_product: " << cross_product;
586 }
587 return true;
588 }
589 if (debug_level_ >= 2) {
590 AINFO << "point (" << point(0) << ", " << point(1)
591 << ") is right of line_segment (" << line_seg_start_point(0) << ", "
592 << line_seg_start_point(1) << ")->(" << line_seg_end_point(0) << ", "
593 << line_seg_end_point(1) << "), cross_product: " << cross_product;
594 }
595 return false;
596}
597
598// Check if the object is in the lane in image space
599bool Cipv::IsObjectInTheLaneImage(const std::shared_ptr<base::Object> &object,
600 const EgoLane &egolane_image,
601 float *object_distance) {
602 LineSegment2Df closted_object_edge;
603 bool b_left_lane_clear = false;
604 bool b_right_lane_clear = false;
605 float shortest_distance = kMaxFloat;
606 float distance = 0.0f;
607
608 int closest_index = -1;
609 // Find closest edge of a given object bounding box
610 float b_valid_object = FindClosestObjectImage(
611 object, egolane_image, &closted_object_edge, &distance);
612 if (!b_valid_object) {
613 if (debug_level_ >= 1) {
614 AINFO << "The closest edge of an object is not available";
615 }
616 return false;
617 }
618 *object_distance = distance;
619
620 if (debug_level_ >= 3) {
621 AINFO << "egolane_image.left_line.line_point.size(): "
622 << egolane_image.left_line.line_point.size();
623 }
624 if (egolane_image.left_line.line_point.size() <= 1) {
625 if (debug_level_ >= 1) {
626 AINFO << "No left lane";
627 }
628 return false;
629 }
630
631 // Check end_point and left lane
632 closest_index = -1;
633 shortest_distance = kMaxFloat;
634 for (size_t i = 0; i + 1 < egolane_image.left_line.line_point.size(); ++i) {
635 // If an end point is in the closest left lane line segments
636 distance = kMaxFloat;
637 if (DistanceFromPointToLineSegment(
638 closted_object_edge.end_point,
639 egolane_image.left_line.line_point[i],
640 egolane_image.left_line.line_point[i + 1], &distance)) {
641 if (distance < shortest_distance) {
642 closest_index = static_cast<int>(i);
643 shortest_distance = distance;
644 }
645 }
646 }
647
648 // When the closest line segment was found
649 if (closest_index >= 0) {
650 // Check if the end point is on the right of the line segment
651 if (debug_level_ >= 3) {
652 AINFO << "[Left] closest_index: " << closest_index
653 << ", shortest_distance: " << shortest_distance;
654 AINFO << "Should be left to be selected";
655 }
656 if (IsPointLeftOfLine(
657 closted_object_edge.end_point,
658 egolane_image.left_line.line_point[closest_index],
659 egolane_image.left_line.line_point[closest_index + 1])) {
660 b_left_lane_clear = true;
661 AINFO << "The left lane is clear";
662 }
663 }
664
665 if (debug_level_ >= 3) {
666 AINFO << "egolane_image.right_line.line_point.size(): "
667 << egolane_image.right_line.line_point.size();
668 }
669 // Check start_point and right lane
670 if (egolane_image.right_line.line_point.size() <= 1) {
671 if (debug_level_ >= 1) {
672 AINFO << "No right lane";
673 }
674 return false;
675 }
676 closest_index = -1;
677 shortest_distance = kMaxFloat;
678 for (size_t i = 0; i + 1 < egolane_image.right_line.line_point.size(); ++i) {
679 // If an end point is in the closest right lane line segments
680 distance = kMaxFloat;
681 if (DistanceFromPointToLineSegment(
682 closted_object_edge.start_point,
683 egolane_image.right_line.line_point[i],
684 egolane_image.right_line.line_point[i + 1], &distance)) {
685 if (distance < shortest_distance) {
686 closest_index = static_cast<int>(i);
687 shortest_distance = distance;
688 }
689 }
690 }
691 // When the closest line segment was found
692 if (closest_index >= 0) {
693 if (debug_level_ >= 3) {
694 AINFO << "[right] closest_index: " << closest_index
695 << ", shortest_distance: " << shortest_distance;
696 AINFO << "Should be right to be selected";
697 }
698 // Check if the end point is on the right of the line segment
699 if (!IsPointLeftOfLine(
700 closted_object_edge.start_point,
701 egolane_image.right_line.line_point[closest_index],
702 egolane_image.right_line.line_point[closest_index + 1])) {
703 b_right_lane_clear = true;
704 AINFO << "The right lane is clear";
705 }
706 }
707
708 if (b_left_lane_clear && b_right_lane_clear) {
709 AINFO << "The object is in the ego lane";
710 } else {
711 AINFO << "The object is out of the ego lane";
712 }
713 return (b_left_lane_clear && b_right_lane_clear);
714}
715
716// Check if the object is in the lane in ego-ground space
717// | |
718// | *------* |
719// | *-+-----*
720// | | *--------* <- closest edge of object
721// *+------* |
722// | |
723// l_lane r_lane
724bool Cipv::IsObjectInTheLaneGround(const std::shared_ptr<base::Object> &object,
725 const EgoLane &egolane_ground,
726 const Eigen::Affine3d &world2camera,
727 const bool b_virtual,
728 float *object_distance) {
729 LineSegment2Df closted_object_edge;
730 bool b_left_lane_clear = false;
731 bool b_right_lane_clear = false;
732 float shortest_distance = 0.0f;
733 float distance = 0.0f;
734 float max_dist_object_to_lane_in_meter =
735 b_virtual ? max_dist_object_to_virtual_lane_in_meter_
736 : max_dist_object_to_lane_in_meter_;
737 int closest_index = -1;
738 // Find closest edge of a given object bounding box
739 float b_valid_object = FindClosestObjectGround(
740 object, egolane_ground, world2camera, &closted_object_edge, &distance);
741 if (!b_valid_object) {
742 if (debug_level_ >= 1) {
743 AINFO << "The closest edge of an object is not available";
744 }
745 return false;
746 }
747 *object_distance = distance;
748
749 if (debug_level_ >= 3) {
750 AINFO << "egolane_ground.left_line.line_point.size(): "
751 << egolane_ground.left_line.line_point.size();
752 }
753 if (egolane_ground.left_line.line_point.size() <= 1) {
754 if (debug_level_ >= 1) {
755 AINFO << "No left lane";
756 }
757 return false;
758 }
759
760 // Check end_point and left lane
761 closest_index = -1;
762 shortest_distance = kMaxFloat;
763 for (size_t i = 0; i + 1 < egolane_ground.left_line.line_point.size(); ++i) {
764 // If an end point is in the closest left lane line segments
765 distance = kMaxFloat;
766 if (DistanceFromPointToLineSegment(
767 closted_object_edge.end_point,
768 egolane_ground.left_line.line_point[i],
769 egolane_ground.left_line.line_point[i + 1], &distance)) {
770 if (distance < shortest_distance) {
771 closest_index = static_cast<int>(i);
772 shortest_distance = distance;
773 }
774 }
775 }
776
777 // When the closest line segment was found
778 if (closest_index >= 0) {
779 // Check if the end point is on the right of the line segment
780 if (debug_level_ >= 3) {
781 AINFO << "[Left] closest_index: " << closest_index
782 << ", shortest_distance: " << shortest_distance;
783 }
784 if (!IsPointLeftOfLine(
785 closted_object_edge.end_point,
786 egolane_ground.left_line.line_point[closest_index],
787 egolane_ground.left_line.line_point[closest_index + 1]) &&
788 shortest_distance < max_dist_object_to_lane_in_meter) {
789 b_left_lane_clear = true;
790 }
791 }
792
793 if (debug_level_ >= 3) {
794 AINFO << "egolane_ground.right_line.line_point.size(): "
795 << egolane_ground.right_line.line_point.size();
796 }
797 // Check start_point and right lane
798 if (egolane_ground.right_line.line_point.size() <= 1) {
799 if (debug_level_ >= 1) {
800 AINFO << "No right lane";
801 }
802 return false;
803 }
804 closest_index = -1;
805 shortest_distance = kMaxFloat;
806 for (size_t i = 0; i + 1 < egolane_ground.right_line.line_point.size(); ++i) {
807 // If an end point is in the closest right lane line segments
808 distance = kMaxFloat;
809 if (DistanceFromPointToLineSegment(
810 closted_object_edge.start_point,
811 egolane_ground.right_line.line_point[i],
812 egolane_ground.right_line.line_point[i + 1], &distance)) {
813 if (distance < shortest_distance) {
814 closest_index = static_cast<int>(i);
815 shortest_distance = distance;
816 }
817 }
818 }
819 // When the closest line segment was found
820 if (closest_index >= 0) {
821 if (debug_level_ >= 3) {
822 AINFO << "[right] closest_index: " << closest_index
823 << ", shortest_distance: " << shortest_distance;
824 }
825 // Check if the end point is on the right of the line segment
826 if (IsPointLeftOfLine(
827 closted_object_edge.start_point,
828 egolane_ground.right_line.line_point[closest_index],
829 egolane_ground.right_line.line_point[closest_index + 1]) &&
830 shortest_distance < max_dist_object_to_lane_in_meter) {
831 b_right_lane_clear = true;
832 }
833 }
834
835 return b_left_lane_clear && b_right_lane_clear;
836}
837
838// Check if the object is in the lane in ego-ground space
839bool Cipv::IsObjectInTheLane(const std::shared_ptr<base::Object> &object,
840 const EgoLane &egolane_image,
841 const EgoLane &egolane_ground,
842 const Eigen::Affine3d &world2camera,
843 const bool b_virtual, float *distance) {
844 if (b_image_based_cipv_) {
845 return IsObjectInTheLaneImage(object, egolane_image, distance);
846 }
847 return IsObjectInTheLaneGround(object, egolane_ground, world2camera,
848 b_virtual, distance);
849}
850
851// =====================================================================
852// Decide CIPV among multiple objects
853bool Cipv::DetermineCipv(const std::vector<base::LaneLine> &lane_objects,
854 const CipvOptions &options,
855 const Eigen::Affine3d &world2camera,
856 std::vector<std::shared_ptr<base::Object>> *objects) {
857 if (debug_level_ >= 3) {
858 AINFO << "Cipv Got SensorObjects with size of " << objects->size();
859 AINFO << "Cipv Got lane object with size of " << lane_objects.size();
860 }
861
862 // float yaw_rate = options.yaw_rate;
863 // float velocity = options.velocity;
864 int32_t cipv_index = -1;
865 // int32_t old_cipv_track_id = sensor_objects.cipv_track_id;
866 int32_t cipv_track_id = -1;
867 bool b_left_valid = false;
868 bool b_right_valid = false;
869 int32_t old_cipv_index = -1;
870 EgoLane egolane_image;
871 EgoLane egolane_ground;
872 EgoLane virtual_egolane_ground;
873 egolane_ground.left_line.line_point.clear();
874 egolane_ground.right_line.line_point.clear();
875 virtual_egolane_ground.left_line.line_point.clear();
876 virtual_egolane_ground.right_line.line_point.clear();
877
878 // Get ego lanes (in both image and ground coordinate)
879 GetEgoLane(lane_objects, &egolane_image, &egolane_ground, &b_left_valid,
880 &b_right_valid);
881 ElongateEgoLane(lane_objects, b_left_valid, b_right_valid, options.yaw_rate,
882 options.velocity, &egolane_image, &egolane_ground);
883
884 CreateVirtualEgoLane(options.yaw_rate, options.velocity,
885 &virtual_egolane_ground);
886
887 float min_distance = std::numeric_limits<float>::max();
888 float distance;
889 for (int32_t i = 0; i < static_cast<int32_t>(objects->size()); ++i) {
890 if (debug_level_ >= 2) {
891 AINFO << "objects[" << i << "]->track_id: " << (*objects)[i]->track_id;
892 }
893 if (IsObjectInTheLane((*objects)[i], egolane_image, egolane_ground,
894 world2camera, false, &distance) ||
895 IsObjectInTheLane((*objects)[i], egolane_image, virtual_egolane_ground,
896 world2camera, true, &distance)) {
897 if (cipv_index < 0 || distance < min_distance) {
898 cipv_index = i;
899 cipv_track_id = (*objects)[i]->track_id;
900 min_distance = distance;
901 }
902
903 if (debug_level_ >= 2) {
904 AINFO << "current cipv_index: " << cipv_index;
905 }
906 }
907 if ((*objects)[i]->track_id == old_cipv_track_id_) {
908 old_cipv_index = cipv_index;
909 }
910 }
911 if (debug_level_ >= 1) {
912 AINFO << "old_cipv_index: " << old_cipv_index;
913 AINFO << "old_cipv_track_id_: " << old_cipv_track_id_;
914 }
915 if (cipv_index >= 0) {
916 if (old_cipv_index >= 0 && old_cipv_index != cipv_index &&
917 old_cipv_index < static_cast<int32_t>(objects->size())) {
918 (*objects)[old_cipv_index]->b_cipv = false;
919 }
920 (*objects)[cipv_index]->b_cipv = true;
921 old_cipv_track_id_ = cipv_track_id;
922 // sensor_objects.cipv_index = cipv_index;
923 // sensor_objects.cipv_track_id = cipv_track_id;
924 if (debug_level_ >= 1) {
925 AINFO << "final cipv_index: " << cipv_index;
926 AINFO << "final cipv_track_id: " << cipv_track_id;
927 // AINFO << "CIPV Index is changed from " << old_cipv_index << "th
928 // object to "
929 // << cipv_index << "th object.";
930 // AINFO << "CIPV Track_ID is changed from " << old_cipv_track_id <<
931 // " to "
932 // << cipv_track_id << ".";
933 }
934 } else {
935 if (debug_level_ >= 1) {
936 AINFO << "No cipv";
937 }
938 }
939
940 return true;
941}
942
943bool Cipv::TranformPoint(const Eigen::VectorXf &in,
944 const Eigen::Matrix4f &motion_matrix,
945 Eigen::Vector3d *out) {
946 if (in.rows() != motion_matrix.cols()) {
947 AERROR << "Matrix mismatch";
948 }
949 Eigen::VectorXf trans_pt = motion_matrix * in;
950 if (fabs(trans_pt(3)) < kFloatEpsilon) {
951 return false;
952 }
953
954 trans_pt /= trans_pt(3);
955 *out << trans_pt(0), trans_pt(1), trans_pt(2);
956 return true;
957}
958
960 const Eigen::Affine3d &world2camera,
961 std::vector<std::shared_ptr<base::Object>> *objects) {
962 int motion_size = static_cast<int>(motion_buffer->size());
963 if (debug_level_ >= 2) {
964 AINFO << " motion_size: " << motion_size;
965 }
966 if (motion_size <= 0) {
967 ADEBUG << " motion_size: " << motion_size;
968 return false;
969 }
970 // std::map<int, std::vector<std::pair<float, float>>>
971 // tmp_object_trackjectories;
972 // std::swap(object_trackjectories_, tmp_object_trackjectories);
973
974 if (debug_level_ >= 2) {
975 AINFO << "object_trackjectories_.size(): " << object_trackjectories_.size();
976 }
977 for (auto obj : *objects) {
978 int cur_id = obj->track_id;
979 if (debug_level_ >= 2) {
980 AINFO << "target ID: " << cur_id;
981 }
982 // for (auto point : tmp_object_trackjectories[cur_id]) {
983 // object_trackjectories_[cur_id].emplace_back(point);
984 // }
985
986 // If it is the first object, set capacity.
987 if (object_trackjectories_[cur_id].empty()) {
988 object_trackjectories_[cur_id].set_capacity(kDropsHistorySize);
989 }
990
991 object_id_skip_count_[cur_id] = 0;
992
993 auto pos = world2camera * obj->center;
994 float center_x = static_cast<float>(pos(2));
995 float center_y = static_cast<float>(-pos(0));
996
997 object_trackjectories_[cur_id].push_back(
998 std::make_pair(center_x, center_y));
999
1000 if (debug_level_ >= 2) {
1001 AINFO << "object_trackjectories_[" << cur_id
1002 << " ].size(): " << object_trackjectories_[cur_id].size();
1003 }
1004
1005 Eigen::Matrix4f accum_motion_buffer =
1006 motion_buffer->at(motion_size - 1).motion;
1007 // Add drops
1008 for (std::size_t it = object_trackjectories_[cur_id].size() - 1, count = 0;
1009 it > 0; it--) {
1010 if (count >= kDropsHistorySize || count > motion_buffer->size()) {
1011 break;
1012 }
1013 if (static_cast<int>(it) + 1 > motion_size) {
1014 continue;
1015 }
1016 Eigen::VectorXf pt =
1017 Eigen::VectorXf::Zero((*motion_buffer)[0].motion.cols());
1018 pt(0) = object_trackjectories_[cur_id][it].first;
1019 pt(1) = object_trackjectories_[cur_id][it].second;
1020 pt(2) = 0.0f;
1021 pt(3) = 1.0f;
1022
1023 Eigen::Vector3d transformed_pt;
1024 accum_motion_buffer *= motion_buffer->at(motion_size - it - 1).motion;
1025 TranformPoint(pt, accum_motion_buffer, &transformed_pt);
1026 // TranformPoint(pt, (*motion_buffer)[motion_size - count - 1].motion,
1027 // &transformed_pt);
1028 if (debug_level_ >= 3) {
1029 AINFO << "(*motion_buffer)[" << motion_size - it - 1 << "].motion:";
1030 AINFO << motion_buffer->at(motion_size - it - 1).motion;
1031 AINFO << "accum_motion_buffer[" << motion_size - it - 1 << "] =";
1032 AINFO << accum_motion_buffer;
1033 AINFO << "target[" << obj->track_id << "][" << it << "]: ("
1034 << transformed_pt(0) << ", " << transformed_pt(1) << ")";
1035 }
1036 obj->drops[count] = transformed_pt;
1037 obj->drop_num = count++;
1038 }
1039 }
1040
1041 // Currently remove trajectory if they do not exist in the current frame
1042 // TODO(techoe): need to wait several frames
1043 for (const auto &each_object : object_trackjectories_) {
1044 int obj_id = each_object.first;
1045 bool b_found_id = false;
1046 for (auto obj : *objects) {
1047 int cur_id = obj->track_id;
1048 if (obj_id == cur_id) {
1049 b_found_id = true;
1050 break;
1051 }
1052 }
1053 // If object ID was not found erase it from map
1054 if (!b_found_id && object_trackjectories_[obj_id].size() > 0) {
1055 // object_id_skip_count_[obj_id].second++;
1056 object_id_skip_count_[obj_id]++;
1057 if (debug_level_ >= 2) {
1058 AINFO << "object_id_skip_count_[" << obj_id
1059 << " ]: " << object_id_skip_count_[obj_id];
1060 }
1061 if (object_id_skip_count_[obj_id] >= kMaxAllowedSkipObject) {
1062 if (debug_level_ >= 2) {
1063 AINFO << "Removed obsolete object " << obj_id;
1064 }
1065 object_trackjectories_.erase(obj_id);
1066 object_id_skip_count_.erase(obj_id);
1067 }
1068 }
1069 }
1070 if (debug_level_ >= 2) {
1071 for (auto obj : *objects) {
1072 int cur_id = obj->track_id;
1073 AINFO << "obj->track_id: " << cur_id;
1074 AINFO << "obj->drop_num: " << obj->drop_num;
1075 }
1076 }
1077 return true;
1078}
1079
1080bool Cipv::image2ground(const float image_x, const float image_y,
1081 float *ground_x, float *ground_y) {
1082 Eigen::Vector3d p_homo;
1083
1084 p_homo << image_x, image_y, 1;
1085 Eigen::Vector3d p_ground;
1086 p_ground = homography_im2car_ * p_homo;
1087 if (fabs(p_ground(2)) > std::numeric_limits<double>::min()) {
1088 *ground_x = static_cast<float>(p_ground(0) / p_ground(2));
1089 *ground_y = static_cast<float>(p_ground(1) / p_ground(2));
1090 return true;
1091 }
1092 if (debug_level_ >= 1) {
1093 AINFO << "p_ground(2) too small :" << p_ground(2);
1094 }
1095 return false;
1096}
1097
1098bool Cipv::ground2image(const float ground_x, const float ground_y,
1099 float *image_x, float *image_y) {
1100 Eigen::Vector3d p_homo_ground;
1101
1102 p_homo_ground << ground_x, ground_y, 1;
1103 Eigen::Vector3d p_image;
1104 p_image = homography_car2im_ * p_homo_ground;
1105 if (fabs(p_image(2)) > std::numeric_limits<double>::min()) {
1106 *image_x = static_cast<float>(p_image(0) / p_image(2));
1107 *image_y = static_cast<float>(p_image(1) / p_image(2));
1108 return true;
1109 }
1110 if (debug_level_ >= 1) {
1111 AINFO << "p_image(2) too small :" << p_image(2);
1112 }
1113 return false;
1114}
1115
1116std::string Cipv::Name() const { return "Cipv"; }
1117
1118// Register plugin.
1119// REGISTER_CIPV(Cipv);
1120
1122
1123} // namespace camera
1124} // namespace perception
1125} // namespace apollo
#define PERCEPTION_REGISTER_CIPV(name)
Definition base_cipv.h:74
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
std::string Name() const override
bool DetermineCipv(const std::vector< base::LaneLine > &lane_objects, const CipvOptions &options, const Eigen::Affine3d &world2camera, std::vector< std::shared_ptr< base::Object > > *objects)
bool Process(CameraFrame *frame, const CipvOptions &options, const Eigen::Affine3d &world2camera, const base::MotionBufferPtr &motion_buffer) override
bool Init(const Eigen::Matrix3d &homography_im2car, const CipvInitOptions &options=CipvInitOptions()) override
bool CollectDrops(const base::MotionBufferPtr &motion_buffer, const Eigen::Affine3d &world2camera, std::vector< std::shared_ptr< base::Object > > *objects)
static bool MakeVirtualEgoLaneFromYawRate(const float yaw_rate, const float velocity, const float offset_distance, LaneLineSimple *left_lane_line, LaneLineSimple *right_lane_line)
static float VehicleDynamics(const uint32_t tick, const float yaw_rate, const float velocity, const float time_unit, float *x, float *y)
Define the LineSegment2d class.
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
#define AWARN
Definition log.h:43
float cos(Angle16 a)
Definition angle.cc:42
float sin(Angle16 a)
Definition angle.cc:25
std::shared_ptr< MotionBuffer > MotionBufferPtr
@ EGO_LEFT
left lane marking of the ego lane
@ EGO_RIGHT
right lane marking of the ego lane
constexpr float kMinVelocity
Definition cipv_camera.h:40
constexpr float kMaxDistObjectToLaneInMeter
Definition cipv_camera.h:41
constexpr float kMaxVehicleWidthInMeter
Definition lane_object.h:41
constexpr float kMaxFloat
Definition lane_object.h:29
constexpr float kFloatEpsilon
Definition lane_object.h:32
Eigen::Vector2f Point2Df
Definition lane_object.h:53
class register implement
Definition arena_queue.h:37
apollo::common::EigenVector< Point2Df > line_point
Definition lane_object.h:62
std::vector< base::LaneLine > lane_objects
std::vector< base::ObjectPtr > tracked_objects