Apollo 11.0
自动驾驶开放平台
track_object_distance.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#include <limits>
20#include <map>
21#include <utility>
22#include <vector>
23
24#include <boost/format.hpp>
25
32
33namespace apollo {
34namespace perception {
35namespace fusion {
36
37double TrackObjectDistance::s_lidar2lidar_association_center_dist_threshold_ =
38 10.0;
39double TrackObjectDistance::s_lidar2radar_association_center_dist_threshold_ =
40 10.0;
41double TrackObjectDistance::s_radar2radar_association_center_dist_threshold_ =
42 10.0;
43size_t
44 TrackObjectDistance::s_lidar2camera_projection_downsample_target_pts_num_ =
45 100;
46size_t TrackObjectDistance::s_lidar2camera_projection_vertices_check_pts_num_ =
47 20;
48
49void TrackObjectDistance::GetModified2DRadarBoxVertices(
50 const EigenVector<Eigen::Vector3d>& radar_box_vertices,
51 const SensorObjectConstPtr& camera,
52 const base::BaseCameraModelPtr& camera_intrinsic,
53 const Eigen::Matrix4d& world2camera_pose,
54 EigenVector<Eigen::Vector2d>* radar_box2d_vertices) {
55 const double camera_height = camera->GetBaseObject()->size(2);
56 EigenVector<Eigen::Vector3d> modified_radar_box_vertices = radar_box_vertices;
57 for (size_t i = 0; i < 4; ++i) {
58 modified_radar_box_vertices[i + 4].z() =
59 modified_radar_box_vertices[i].z() + camera_height;
60 }
61 radar_box2d_vertices->reserve(radar_box_vertices.size());
62 for (const auto& box_vertex_3d : modified_radar_box_vertices) {
63 Eigen::Vector4d local_box_vertex =
64 world2camera_pose * box_vertex_3d.homogeneous();
65 Eigen::Vector2f temp_vertex =
66 camera_intrinsic->Project(local_box_vertex.head(3).cast<float>());
67 radar_box2d_vertices->push_back(temp_vertex.cast<double>());
68 }
69}
70
71base::BaseCameraModelPtr TrackObjectDistance::QueryCameraModel(
72 const SensorObjectConstPtr& camera) {
73 return SensorDataManager::Instance()->GetCameraIntrinsic(
74 camera->GetSensorId());
75}
76
77bool TrackObjectDistance::QueryWorld2CameraPose(
78 const SensorObjectConstPtr& camera, Eigen::Matrix4d* pose) {
79 Eigen::Affine3d camera2world_pose;
80 bool status = SensorDataManager::Instance()->GetPose(
81 camera->GetSensorId(), camera->GetTimestamp(), &camera2world_pose);
82 if (!status) {
83 return false;
84 }
85 (*pose) = camera2world_pose.matrix().inverse();
86 return true;
87}
88
89bool TrackObjectDistance::QueryLidar2WorldPose(
90 const SensorObjectConstPtr& lidar, Eigen::Matrix4d* pose) {
91 Eigen::Affine3d velo2world_pose;
92 if (!lidar->GetRelatedFramePose(&velo2world_pose)) {
93 return false;
94 }
95 (*pose) = velo2world_pose.matrix();
96 return true;
97}
98
99ProjectionCacheObject* TrackObjectDistance::BuildProjectionCacheObject(
100 const SensorObjectConstPtr& lidar, const SensorObjectConstPtr& camera,
101 const base::BaseCameraModelPtr& camera_model,
102 const std::string& measurement_sensor_id, double measurement_timestamp,
103 const std::string& projection_sensor_id, double projection_timestamp) {
104 // 1. get lidar2camera_pose
105 Eigen::Matrix4d world2camera_pose;
106 if (!QueryWorld2CameraPose(camera, &world2camera_pose)) {
107 return nullptr;
108 }
109 Eigen::Matrix4d lidar2world_pose;
110 if (!QueryLidar2WorldPose(lidar, &lidar2world_pose)) {
111 return nullptr;
112 }
113 Eigen::Matrix4d lidar2camera_pose =
114 static_cast<Eigen::Matrix<double, 4, 4, 0, 4, 4>>(world2camera_pose *
115 lidar2world_pose);
116 // 2. compute offset
117 double time_diff = camera->GetTimestamp() - lidar->GetTimestamp();
118 Eigen::Vector3d offset =
119 lidar->GetBaseObject()->velocity.cast<double>() * time_diff;
120 // 3. build projection cache
121 const base::PointFCloud& cloud =
122 lidar->GetBaseObject()->lidar_supplement.cloud;
123 double width = static_cast<double>(camera_model->get_width());
124 double height = static_cast<double>(camera_model->get_height());
125 const int lidar_object_id = lidar->GetBaseObject()->id;
126 ProjectionCacheObject* cache_object = projection_cache_.BuildObject(
127 measurement_sensor_id, measurement_timestamp, projection_sensor_id,
128 projection_timestamp, lidar_object_id);
129 if (cache_object == nullptr) {
130 AERROR << "Failed to build projection cache object";
131 return nullptr;
132 }
133 size_t start_ind = projection_cache_.GetPoint2dsSize();
134 size_t end_ind = projection_cache_.GetPoint2dsSize();
135 float xmin = std::numeric_limits<float>::max();
136 float ymin = std::numeric_limits<float>::max();
137 float xmax = -std::numeric_limits<float>::max();
138 float ymax = -std::numeric_limits<float>::max();
139 // 4. check whether all lidar's 8 3d vertices would projected outside frustum,
140 // if not, build projection object of its cloud and cache it
141 // else, build empty projection object and cache it
142 bool is_all_lidar_3d_vertices_outside_frustum = false;
143 if (cloud.size() > s_lidar2camera_projection_vertices_check_pts_num_) {
144 is_all_lidar_3d_vertices_outside_frustum = true;
145 EigenVector<Eigen::Vector3d> lidar_box_vertices;
146 GetObjectEightVertices(lidar->GetBaseObject(), &lidar_box_vertices);
147 for (size_t i = 0; i < lidar_box_vertices.size(); ++i) {
148 Eigen::Vector3d& vt = lidar_box_vertices[i];
149 Eigen::Vector4d project_vt =
150 static_cast<Eigen::Matrix<double, 4, 1, 0, 4, 1>>(
151 world2camera_pose * Eigen::Vector4d(vt(0) + offset(0),
152 vt(1) + offset(1),
153 vt(2) + offset(2), 1.0));
154 if (project_vt(2) <= 0) {
155 continue;
156 }
157 Eigen::Vector2f project_vt2f = camera_model->Project(Eigen::Vector3f(
158 static_cast<float>(project_vt(0)), static_cast<float>(project_vt(1)),
159 static_cast<float>(project_vt(2))));
160 if (!IsPtInFrustum(project_vt2f, width, height)) {
161 continue;
162 }
163 is_all_lidar_3d_vertices_outside_frustum = false;
164 break;
165 }
166 }
167 // 5. if not all lidar 3d vertices outside frustum, build projection object
168 // of its cloud and cache it, else build & cache an empty one.
169 if (!is_all_lidar_3d_vertices_outside_frustum) {
170 // 5.1 check whehter downsampling needed
171 size_t every_n = 1;
172 if (cloud.size() > s_lidar2camera_projection_downsample_target_pts_num_) {
173 every_n =
174 cloud.size() / s_lidar2camera_projection_downsample_target_pts_num_;
175 }
176 for (size_t i = 0; i < cloud.size(); ++i) {
177 if ((every_n > 1) && (i % every_n != 0)) {
178 continue;
179 }
180 const base::PointF& pt = cloud.at(i);
181 Eigen::Vector4d project_pt =
182 static_cast<Eigen::Matrix<double, 4, 1, 0, 4, 1>>(
183 lidar2camera_pose * Eigen::Vector4d(pt.x + offset(0),
184 pt.y + offset(1),
185 pt.z + offset(2), 1.0));
186 if (project_pt(2) <= 0) {
187 continue;
188 }
189 Eigen::Vector2f project_pt2f = camera_model->Project(Eigen::Vector3f(
190 static_cast<float>(project_pt(0)), static_cast<float>(project_pt(1)),
191 static_cast<float>(project_pt(2))));
192 if (!IsPtInFrustum(project_pt2f, width, height)) {
193 continue;
194 }
195 if (project_pt2f.x() < xmin) {
196 xmin = project_pt2f.x();
197 }
198 if (project_pt2f.y() < ymin) {
199 ymin = project_pt2f.y();
200 }
201 if (project_pt2f.x() > xmax) {
202 xmax = project_pt2f.x();
203 }
204 if (project_pt2f.y() > ymax) {
205 ymax = project_pt2f.y();
206 }
207 projection_cache_.AddPoint(project_pt2f);
208 }
209 }
210 end_ind = projection_cache_.GetPoint2dsSize();
211 cache_object->SetStartInd(start_ind);
212 cache_object->SetEndInd(end_ind);
213 base::BBox2DF box = base::BBox2DF(xmin, ymin, xmax, ymax);
214 cache_object->SetBox(box);
215 return cache_object;
216}
217
218ProjectionCacheObject* TrackObjectDistance::QueryProjectionCacheObject(
219 const SensorObjectConstPtr& lidar, const SensorObjectConstPtr& camera,
220 const base::BaseCameraModelPtr& camera_model,
221 const bool measurement_is_lidar) {
222 // 1. try to query existed projection cache object
223 const std::string& measurement_sensor_id =
224 measurement_is_lidar ? lidar->GetSensorId() : camera->GetSensorId();
225 const double measurement_timestamp =
226 measurement_is_lidar ? lidar->GetTimestamp() : camera->GetTimestamp();
227 const std::string& projection_sensor_id =
228 measurement_is_lidar ? camera->GetSensorId() : lidar->GetSensorId();
229 const double projection_timestamp =
230 measurement_is_lidar ? camera->GetTimestamp() : lidar->GetTimestamp();
231 const int lidar_object_id = lidar->GetBaseObject()->id;
232 ProjectionCacheObject* cache_object = projection_cache_.QueryObject(
233 measurement_sensor_id, measurement_timestamp, projection_sensor_id,
234 projection_timestamp, lidar_object_id);
235 if (cache_object != nullptr) {
236 return cache_object;
237 } // 2. if query failed, build projection and cache it
238 return BuildProjectionCacheObject(
239 lidar, camera, camera_model, measurement_sensor_id, measurement_timestamp,
240 projection_sensor_id, projection_timestamp);
241}
242
243void TrackObjectDistance::QueryProjectedVeloCtOnCamera(
244 const SensorObjectConstPtr& velodyne64, const SensorObjectConstPtr& camera,
245 const Eigen::Matrix4d& lidar2camera_pose, Eigen::Vector3d* projected_ct) {
246 double time_diff = camera->GetTimestamp() - velodyne64->GetTimestamp();
247 Eigen::Vector3d offset =
248 velodyne64->GetBaseObject()->velocity.cast<double>() * time_diff;
249 const Eigen::Vector3d& velo_ct = velodyne64->GetBaseObject()->center;
250 Eigen::Vector4d projected_ct_4d =
251 static_cast<Eigen::Matrix<double, 4, 1, 0, 4, 1>>(
252 lidar2camera_pose * Eigen::Vector4d(velo_ct[0] + offset[0],
253 velo_ct[1] + offset[1],
254 velo_ct[2] + offset[2], 1.0));
255 *projected_ct = projected_ct_4d.head(3);
256}
257
258bool TrackObjectDistance::QueryPolygonDCenter(
259 const base::ObjectConstPtr& object, const Eigen::Vector3d& ref_pos,
260 const int range, Eigen::Vector3d* polygon_ct) {
261 if (object == nullptr) {
262 return false;
263 }
264 const base::PolygonDType& polygon = object->polygon;
265 if (!ComputePolygonCenter(polygon, ref_pos, range, polygon_ct)) {
266 return false;
267 }
268 return true;
269}
270
271bool TrackObjectDistance::IsTrackIdConsistent(
272 const SensorObjectConstPtr& object1, const SensorObjectConstPtr& object2) {
273 if (object1 == nullptr || object2 == nullptr) {
274 return false;
275 }
276 if (object1->GetBaseObject()->track_id ==
277 object2->GetBaseObject()->track_id) {
278 return true;
279 }
280 return false;
281}
282
283bool TrackObjectDistance::LidarCameraCenterDistanceExceedDynamicThreshold(
284 const SensorObjectConstPtr& lidar, const SensorObjectConstPtr& camera) {
285 double center_distance =
286 (lidar->GetBaseObject()->center - camera->GetBaseObject()->center)
287 .head(2)
288 .norm();
289 double local_distance = 60;
290 const base::PointFCloud& cloud =
291 lidar->GetBaseObject()->lidar_supplement.cloud;
292 if (cloud.size() > 0) {
293 const base::PointF& pt = cloud.at(0);
294 local_distance = std::sqrt(pt.x * pt.x + pt.y * pt.y);
295 }
296 double dynamic_threshold = 5 + 0.15 * local_distance;
297 if (center_distance > dynamic_threshold) {
298 return true;
299 }
300 return false;
301}
302
303// @brief: compute the distance between input fused track and sensor object
304// @return track object distance
305float TrackObjectDistance::Compute(const TrackPtr& fused_track,
306 const SensorObjectPtr& sensor_object,
307 const TrackObjectDistanceOptions& options) {
308 FusedObjectPtr fused_object = fused_track->GetFusedObject();
309 if (fused_object == nullptr) {
310 AERROR << "fused object is nullptr";
311 return (std::numeric_limits<float>::max)();
312 }
313 Eigen::Vector3d* ref_point = options.ref_point;
314 if (ref_point == nullptr) {
315 AERROR << "reference point is nullptr";
316 return (std::numeric_limits<float>::max)();
317 }
318 float distance = (std::numeric_limits<float>::max)();
319 float min_distance = (std::numeric_limits<float>::max)();
320 SensorObjectConstPtr lidar_object = fused_track->GetLatestLidarObject();
321 SensorObjectConstPtr radar_object = fused_track->GetLatestRadarObject();
322 SensorObjectConstPtr camera_object = fused_track->GetLatestCameraObject();
323 if (IsLidar(sensor_object)) {
324 if (lidar_object != nullptr) {
325 distance = ComputeLidarLidar(lidar_object, sensor_object, *ref_point);
326 min_distance = std::min(distance, min_distance);
327 }
328 if (radar_object != nullptr) {
329 distance = ComputeLidarRadar(radar_object, sensor_object, *ref_point);
330 min_distance = std::min(distance, min_distance);
331 }
332 if (camera_object != nullptr) {
333 bool is_lidar_track_id_consistent =
334 IsTrackIdConsistent(lidar_object, sensor_object);
335 distance = ComputeLidarCamera(sensor_object, camera_object, true,
336 is_lidar_track_id_consistent);
337 min_distance = std::min(distance, min_distance);
338 }
339 } else if (IsRadar(sensor_object)) {
340 if (lidar_object != nullptr) {
341 distance = ComputeLidarRadar(lidar_object, sensor_object, *ref_point);
342 min_distance = std::min(distance, min_distance);
343 }
344 if (radar_object != nullptr) {
345 distance = ComputeRadarRadar(radar_object, sensor_object, *ref_point);
346 min_distance = std::min(distance, min_distance);
347 }
348 if (camera_object != nullptr) {
349 distance = ComputeRadarCamera(sensor_object, camera_object);
350 min_distance = std::min(distance, min_distance);
351 }
352 } else if (IsCamera(sensor_object)) {
353 if (lidar_object != nullptr) {
354 bool is_camera_track_id_consistent =
355 IsTrackIdConsistent(camera_object, sensor_object);
356 distance = ComputeLidarCamera(lidar_object, sensor_object, false,
357 is_camera_track_id_consistent);
358 min_distance = std::min(distance, min_distance);
359 }
360 } else {
361 AERROR << "fused sensor type is not support";
362 }
363 return min_distance;
364}
365
366// @brief: compute the distance between velodyne64 observation and
367// velodyne64 observation
368// @return the distance of velodyne64 vs. velodyne64
370 const SensorObjectConstPtr& fused_object,
371 const SensorObjectPtr& sensor_object, const Eigen::Vector3d& ref_pos,
372 int range) {
373 double center_distance = (sensor_object->GetBaseObject()->center -
374 fused_object->GetBaseObject()->center)
375 .head(2)
376 .norm();
377 if (center_distance > s_lidar2lidar_association_center_dist_threshold_) {
378 ADEBUG << "center distance exceed lidar2lidar tight threshold: "
379 << "center_dist@" << center_distance << ", "
380 << "tight_threh@"
381 << s_lidar2lidar_association_center_dist_threshold_;
382 return (std::numeric_limits<float>::max)();
383 }
384 float distance =
385 ComputePolygonDistance3d(fused_object, sensor_object, ref_pos, range);
386 ADEBUG << "ComputeLidarLidar distance: " << distance;
387 return distance;
388}
389
390// @brief: compute the distance between velodyne64 observation and
391// radar observation
392// @return distance of velodyne64 vs. radar
394 const SensorObjectConstPtr& fused_object,
395 const SensorObjectPtr& sensor_object, const Eigen::Vector3d& ref_pos,
396 int range) {
397 double center_distance = (sensor_object->GetBaseObject()->center -
398 fused_object->GetBaseObject()->center)
399 .head(2)
400 .norm();
401 if (center_distance > s_lidar2radar_association_center_dist_threshold_) {
402 ADEBUG << "center distance exceed lidar2radar tight threshold: "
403 << "center_dist@" << center_distance << ", "
404 << "tight_threh@"
405 << s_lidar2radar_association_center_dist_threshold_;
406 return (std::numeric_limits<float>::max)();
407 }
408 float distance =
409 ComputePolygonDistance3d(fused_object, sensor_object, ref_pos, range);
410 ADEBUG << "ComputeLidarRadar distance: " << distance;
411 return distance;
412}
413
414// @brief: compute the distance between radar observation and
415// radar observation
416// @return distance of radar vs. radar
418 const SensorObjectConstPtr& fused_object,
419 const SensorObjectPtr& sensor_object, const Eigen::Vector3d& ref_pos,
420 int range) {
421 double center_distance = (sensor_object->GetBaseObject()->center -
422 fused_object->GetBaseObject()->center)
423 .head(2)
424 .norm();
425 if (center_distance > s_radar2radar_association_center_dist_threshold_) {
426 ADEBUG << "center distance exceed radar2radar tight threshold: "
427 << "center_dist@" << center_distance << ", "
428 << "tight_threh@"
429 << s_radar2radar_association_center_dist_threshold_;
430 return (std::numeric_limits<float>::max)();
431 }
432 float distance =
433 ComputePolygonDistance3d(fused_object, sensor_object, ref_pos, range);
434 ADEBUG << "ComputeRadarRadar distance: " << distance;
435 return distance;
436}
437
438// @brief: compute the distance between lidar observation and
439// camera observation
440// @return distance of lidar vs. camera
442 const SensorObjectConstPtr& lidar, const SensorObjectConstPtr& camera,
443 const bool measurement_is_lidar, const bool is_track_id_consistent) {
444 if (!is_track_id_consistent) {
445 if (LidarCameraCenterDistanceExceedDynamicThreshold(lidar, camera)) {
446 return distance_thresh_;
447 }
448 }
449 float distance = distance_thresh_;
450 // 1. get camera intrinsic and pose
451 base::BaseCameraModelPtr camera_model = QueryCameraModel(camera);
452 if (camera_model == nullptr) {
453 AERROR << "Failed to get camera model for " << camera->GetSensorId();
454 return distance;
455 }
456 Eigen::Matrix4d world2camera_pose;
457 if (!QueryWorld2CameraPose(camera, &world2camera_pose)) {
458 AERROR << "Failed to query camera pose";
459 return distance;
460 }
461 Eigen::Matrix4d lidar2world_pose;
462 if (!QueryLidar2WorldPose(lidar, &lidar2world_pose)) {
463 AERROR << "Failed to query lidar pose";
464 return distance;
465 }
466 Eigen::Matrix4d lidar2camera_pose =
467 static_cast<Eigen::Matrix<double, 4, 4, 0, 4, 4>>(world2camera_pose *
468 lidar2world_pose);
469 // 2. compute distance of camera vs. lidar observation
470 const base::PointFCloud& cloud =
471 lidar->GetBaseObject()->lidar_supplement.cloud;
472 const base::BBox2DF& camera_bbox =
473 camera->GetBaseObject()->camera_supplement.box;
474 const base::Point2DF camera_bbox_ct = camera_bbox.Center();
475 const Eigen::Vector2d box2d_ct =
476 Eigen::Vector2d(camera_bbox_ct.x, camera_bbox_ct.y);
477 ADEBUG << "object cloud size : " << cloud.size();
478 if (cloud.size() > 0) {
479 // 2.1 if cloud is not empty, calculate distance according to pts box
480 // similarity
481 ProjectionCacheObject* cache_object = QueryProjectionCacheObject(
482 lidar, camera, camera_model, measurement_is_lidar);
483 if (cache_object == nullptr) {
484 AERROR << "Failed to query projection cached object";
485 return distance;
486 }
487 double similarity =
488 ComputePtsBoxSimilarity(&projection_cache_, cache_object, camera_bbox);
489 distance =
490 distance_thresh_ * ((1.0f - static_cast<float>(similarity)) /
491 (1.0f - vc_similarity2distance_penalize_thresh_));
492 } else {
493 // 2.2 if cloud is empty, calculate distance according to ct diff
494 Eigen::Vector3d projected_velo_ct;
495 QueryProjectedVeloCtOnCamera(lidar, camera, lidar2camera_pose,
496 &projected_velo_ct);
497 if (projected_velo_ct[2] > 0) {
498 Eigen::Vector2f project_pt2f = camera_model->Project(
499 Eigen::Vector3f(static_cast<float>(projected_velo_ct[0]),
500 static_cast<float>(projected_velo_ct[1]),
501 static_cast<float>(projected_velo_ct[2])));
502 Eigen::Vector2d project_pt2d = project_pt2f.cast<double>();
503 Eigen::Vector2d ct_diff = project_pt2d - box2d_ct;
504 distance =
505 static_cast<float>(ct_diff.norm()) * vc_diff2distance_scale_factor_;
506 } else {
507 distance = std::numeric_limits<float>::max();
508 }
509 }
510 ADEBUG << "ComputeLidarCamera distance: " << distance;
511 return distance;
512}
513
514// @brief: compute the distance between radar observation and
515// camera observation
516// @return distance of radar vs. camera
518 const SensorObjectConstPtr& radar, const SensorObjectConstPtr& camera) {
519 float distance = distance_thresh_;
520 // 1. get camera model and pose
521 base::BaseCameraModelPtr camera_model = QueryCameraModel(camera);
522 if (camera_model == nullptr) {
523 AERROR << "Failed to get camera model for " << camera->GetSensorId();
524 return distance;
525 }
526 Eigen::Matrix4d world2camera_pose;
527 if (!QueryWorld2CameraPose(camera, &world2camera_pose)) {
528 return distance;
529 }
530 // get camera useful information
531 const base::BBox2DF& camera_bbox =
532 camera->GetBaseObject()->camera_supplement.box;
533 const base::Point2DF camera_bbox_ct = camera_bbox.Center();
534 const Eigen::Vector2d box2d_ct =
535 Eigen::Vector2d(camera_bbox_ct.x, camera_bbox_ct.y);
536 Eigen::Vector2d box2d_size = Eigen::Vector2d(
537 camera_bbox.xmax - camera_bbox.xmin, camera_bbox.ymax - camera_bbox.ymin);
538 Eigen::Vector2d rc_min_box_size(rc_min_box_size_[0], rc_min_box_size_[1]);
539 box2d_size = box2d_size.cwiseMax(rc_min_box_size);
540 double width = static_cast<double>(camera_model->get_width());
541 double height = static_cast<double>(camera_model->get_height());
542 // get radar useful information
543 double time_diff = camera->GetTimestamp() - radar->GetTimestamp();
544 Eigen::Vector3d offset =
545 radar->GetBaseObject()->velocity.cast<double>() * time_diff;
546 offset.setZero();
547 Eigen::Vector3d radar_ct = radar->GetBaseObject()->center + offset;
548 Eigen::Vector4d local_pt = static_cast<Eigen::Matrix<double, 4, 1, 0, 4, 1>>(
549 world2camera_pose *
550 Eigen::Vector4d(radar_ct[0], radar_ct[1], radar_ct[2], 1.0));
551 EigenVector<Eigen::Vector3d> radar_box_vertices;
552 GetObjectEightVertices(radar->GetBaseObject(), &radar_box_vertices);
553 EigenVector<Eigen::Vector2d> radar_box2d_vertices;
554 GetModified2DRadarBoxVertices(radar_box_vertices, camera, camera_model,
555 world2camera_pose, &radar_box2d_vertices);
556 // compute similarity
557 double fused_similarity = 0.0;
558 if (local_pt[2] > 0) {
559 Eigen::Vector3f pt3f;
560 pt3f << camera_model->Project(Eigen::Vector3f(
561 static_cast<float>(local_pt[0]), static_cast<float>(local_pt[1]),
562 static_cast<float>(local_pt[2]))),
563 static_cast<float>(local_pt[2]);
564 Eigen::Vector3d pt3d = pt3f.cast<double>();
565 if (IsPtInFrustum(pt3d, width, height)) {
566 // compute similarity on x direction
567 double x_similarity = ComputeRadarCameraXSimilarity(
568 pt3d.x(), box2d_ct.x(), box2d_size.x(), rc_x_similarity_params_);
569 // compute similarity on y direction
570 double y_similarity = ComputeRadarCameraYSimilarity(
571 pt3d.y(), box2d_ct.y(), box2d_size.y(), rc_y_similarity_params_);
572 // compute similarity on height
573 // use camera car height to modify the radar location
574 double h_similarity = ComputeRadarCameraHSimilarity(
575 radar, camera, box2d_size.y(), radar_box2d_vertices,
576 rc_h_similarity_params_);
577 // compute similarity on width
578 double w_similarity = ComputeRadarCameraWSimilarity(
579 radar, width, box2d_size.x(), radar_box2d_vertices,
580 rc_w_similarity_params_);
581 // compute similarity on offset 3d
582 double loc_similarity = ComputeRadarCameraLocSimilarity(
583 radar_ct, camera, world2camera_pose, rc_loc_similarity_params_);
584 // compute similarity on velocity
585 double velocity_similarity =
587 // fuse similarity
588 std::vector<double> multiple_similarities = {
589 x_similarity, y_similarity, loc_similarity,
590 velocity_similarity, h_similarity, w_similarity};
591 fused_similarity = FuseMultipleProbabilities(multiple_similarities);
592 }
593 }
594 distance = distance_thresh_ * static_cast<float>(1.0 - fused_similarity) /
595 (1.0f - rc_similarity2distance_penalize_thresh_);
596 ADEBUG << "ComputeRadarCamera distance: " << distance;
597 return distance;
598}
599
600// @brief: compute the distance between camera observation and
601// camera observation
602// @return the distance of camera vs. camera
604 const SensorObjectPtr& fused_camera, const SensorObjectPtr& sensor_camera) {
605 return (std::numeric_limits<float>::max());
606}
607
608// @brief: calculate the similarity between velodyne64 observation and
609// camera observation
610// @return the similarity which belongs to [0, 1]. When velodyne64
611// observation is similar to the camera one, the similarity would
612// close to 1. Otherwise, it would close to 0.
613// @key idea:
614// 1. get camera intrinsic and pose
615// 2. compute similarity between camera's box and velodyne64's pts
616// within camera's frustum
617// @NOTE: original method name is compute_velodyne64_camera_dist_score
619 const SensorObjectConstPtr& lidar, const SensorObjectConstPtr& camera,
620 const bool measurement_is_lidar) {
621 double similarity = 0.0;
622 // 1. get camera intrinsic and pose
623 base::BaseCameraModelPtr camera_model = QueryCameraModel(camera);
624 if (camera_model == nullptr) {
625 AERROR << "Failed to get camera model for " << camera->GetSensorId();
626 return similarity;
627 }
628 Eigen::Matrix4d world2camera_pose;
629 if (!QueryWorld2CameraPose(camera, &world2camera_pose)) {
630 return similarity;
631 }
632 Eigen::Matrix4d lidar2world_pose;
633 if (!QueryLidar2WorldPose(lidar, &lidar2world_pose)) {
634 return similarity;
635 }
636 // Eigen::Matrix4d lidar2camera_pose = world2camera_pose * lidar2world_pose;
637 // 2. compute similarity of camera vs. velodyne64 observation
638 const base::PointFCloud& cloud =
639 lidar->GetBaseObject()->lidar_supplement.cloud;
640 const base::BBox2DF& camera_bbox =
641 camera->GetBaseObject()->camera_supplement.box;
642 if (cloud.size() > 0) {
643 ProjectionCacheObject* cache_object = QueryProjectionCacheObject(
644 lidar, camera, camera_model, measurement_is_lidar);
645 if (cache_object == nullptr) {
646 return similarity;
647 }
648 similarity =
649 ComputePtsBoxSimilarity(&projection_cache_, cache_object, camera_bbox);
650 }
651 return similarity;
652}
653
654// @brief: calculate the similarity between radar observation and
655// camera observation
656// @return the similarity which belongs to [0, 1]. When radar
657// observation is similar to the camera one, the similarity would
658// close to 1. Otherwise, it would close to 0.
659// @NOTE: original method name is compute_radar_camera_dist_score
660// @TODO: THIS METHOD SHOULD RETURN 0, IF RADAR IS IN FRONT OF CAMERA DETECTION
662 const SensorObjectConstPtr& radar, const SensorObjectConstPtr& camera) {
663 double similarity = 0.0;
664 // 1. get camera intrinsic and pose
665 base::BaseCameraModelPtr camera_model = QueryCameraModel(camera);
666 if (camera_model == nullptr) {
667 AERROR << "Failed to get camera model for " << camera->GetSensorId();
668 return similarity;
669 }
670 Eigen::Matrix4d world2camera_pose;
671 if (!QueryWorld2CameraPose(camera, &world2camera_pose)) {
672 return similarity;
673 }
674 // 2. get information of camera
675 const base::BBox2DF& camera_bbox =
676 camera->GetBaseObject()->camera_supplement.box;
677 const base::Point2DF camera_bbox_ct = camera_bbox.Center();
678 const Eigen::Vector2d box2d_ct =
679 Eigen::Vector2d(camera_bbox_ct.x, camera_bbox_ct.y);
680 Eigen::Vector2d box2d_size = Eigen::Vector2d(
681 camera_bbox.xmax - camera_bbox.xmin, camera_bbox.ymax - camera_bbox.ymin);
682 Eigen::Vector2d rc_min_box_size(rc_min_box_size_[0], rc_min_box_size_[1]);
683 box2d_size = box2d_size.cwiseMax(rc_min_box_size);
684 double width = static_cast<double>(camera_model->get_width());
685 double height = static_cast<double>(camera_model->get_height());
686 // 3. get information of radar
687 Eigen::Vector3d radar_ct = radar->GetBaseObject()->center;
688 Eigen::Vector4d local_pt = static_cast<Eigen::Matrix<double, 4, 1, 0, 4, 1>>(
689 world2camera_pose *
690 Eigen::Vector4d(radar_ct[0], radar_ct[1], radar_ct[2], 1.0));
691 // 4. similarity computation
692 Eigen::Vector3d camera_ct = camera->GetBaseObject()->center;
693 Eigen::Vector3d camera_ct_c =
694 (world2camera_pose * camera_ct.homogeneous()).head(3);
695 double depth_diff = local_pt.z() - camera_ct_c.z();
696 const double depth_diff_th = 0.1;
697 depth_diff /= camera_ct_c.z();
698 if (local_pt[2] > 0 && depth_diff > -depth_diff_th) {
699 Eigen::Vector3f pt3f;
700 pt3f << camera_model->Project(Eigen::Vector3f(
701 static_cast<float>(local_pt[0]), static_cast<float>(local_pt[1]),
702 static_cast<float>(local_pt[2]))),
703 static_cast<float>(local_pt[2]);
704 Eigen::Vector3d pt3d = pt3f.cast<double>();
705 if (IsPtInFrustum(pt3d, width, height)) {
706 rc_x_similarity_params_2_.welsh_loss_scale_ =
707 rc_x_similarity_params_2_welsh_loss_scale_;
708 // compute similarity on x direction
709 double x_similarity = ComputeRadarCameraXSimilarity(
710 pt3d.x(), box2d_ct.x(), box2d_size.x(), rc_x_similarity_params_2_);
711 // compute similarity on y direction
712 double y_similarity = ComputeRadarCameraXSimilarity(
713 pt3d.y(), box2d_ct.y(), box2d_size.y(), rc_x_similarity_params_2_);
714 std::vector<double> multiple_similarities = {x_similarity, y_similarity};
715 similarity = FuseMultipleProbabilities(multiple_similarities);
716 }
717 }
718 return similarity;
719}
720
721// @brief: compute polygon distance between fused object and sensor object
722// @return 3d distance between fused object and sensor object
724 const SensorObjectConstPtr& fused_object,
725 const SensorObjectPtr& sensor_object, const Eigen::Vector3d& ref_pos,
726 int range) {
727 const base::ObjectConstPtr& obj_f = fused_object->GetBaseObject();
728 Eigen::Vector3d fused_poly_center(0, 0, 0);
729 if (!QueryPolygonDCenter(obj_f, ref_pos, range, &fused_poly_center)) {
730 return (std::numeric_limits<float>::max());
731 }
732 const base::ObjectConstPtr obj_s = sensor_object->GetBaseObject();
733 Eigen::Vector3d sensor_poly_center(0, 0, 0);
734 if (!QueryPolygonDCenter(obj_s, ref_pos, range, &sensor_poly_center)) {
735 return (std::numeric_limits<float>::max());
736 }
737 double fusion_timestamp = fused_object->GetTimestamp();
738 double sensor_timestamp = sensor_object->GetTimestamp();
739 double time_diff = sensor_timestamp - fusion_timestamp;
740 fused_poly_center(0) += obj_f->velocity(0) * time_diff;
741 fused_poly_center(1) += obj_f->velocity(1) * time_diff;
742 float distance =
743 ComputeEuclideanDistance(fused_poly_center, sensor_poly_center);
744 return distance;
745}
746
747// @brief: compute euclidean distance of input pts
748// @return eculidean distance of input pts
750 const Eigen::Vector3d& des, const Eigen::Vector3d& src) {
751 Eigen::Vector3d diff_pos = des - src;
752 float distance = static_cast<float>(
753 std::sqrt(diff_pos.head(2).cwiseProduct(diff_pos.head(2)).sum()));
754 return distance;
755}
756
757// @brief: compute polygon center
758// @return true if get center successfully, otherwise return false
760 const base::PolygonDType& polygon, Eigen::Vector3d* center) {
761 int size = static_cast<int>(polygon.size());
762 if (size == 0) {
763 return false;
764 }
765 *center = Eigen::Vector3d(0, 0, 0);
766 for (int i = 0; i < size; ++i) {
767 const auto& point = polygon.at(i);
768 (*center)[0] += point.x;
769 (*center)[1] += point.y;
770 }
771 (*center) /= size;
772 return true;
773}
774
775// @brief: compute polygon center
776// @return true if get center successfully, otherwise return false
778 const base::PolygonDType& polygon, const Eigen::Vector3d& ref_pos,
779 int range, Eigen::Vector3d* center) {
780 base::PolygonDType polygon_part;
781 std::map<double, int> distance2idx;
782 for (size_t idx = 0; idx < polygon.size(); ++idx) {
783 const auto& point = polygon.at(idx);
784 double distance =
785 sqrt(pow(point.x - ref_pos(0), 2) + pow(point.y - ref_pos(1), 2));
786 distance2idx.insert(std::make_pair(distance, idx));
787 }
788 int size = static_cast<int>(distance2idx.size());
789 int nu = std::max(range, size / range + 1);
790 nu = std::min(nu, size);
791 int count = 0;
792 std::map<double, int>::iterator it = distance2idx.begin();
793 for (; it != distance2idx.end(), count < nu; ++it, ++count) {
794 polygon_part.push_back(polygon[it->second]);
795 }
796 bool state = ComputePolygonCenter(polygon_part, center);
797 return state;
798}
799
800} // namespace fusion
801} // namespace perception
802} // namespace apollo
const PointT * at(size_t col, size_t row) const
Definition point_cloud.h:63
virtual void push_back(const PointT &point)
ProjectionCacheObject * BuildObject(const std::string &measurement_sensor_id, double measurement_timestamp, const std::string &projection_sensor_id, double projection_timestamp, int lidar_object_id)
void AddPoint(const Eigen::Vector2f &pt)
ProjectionCacheObject * QueryObject(const std::string &measurement_sensor_id, double measurement_timestamp, const std::string &projection_sensor_id, double projection_timestamp, int lidar_object_id)
float ComputePolygonDistance3d(const SensorObjectConstPtr &fused_object, const SensorObjectPtr &sensor_object, const Eigen::Vector3d &ref_pos, int range)
float ComputeLidarLidar(const SensorObjectConstPtr &fused_object, const SensorObjectPtr &sensor_object, const Eigen::Vector3d &ref_pos, int range=3)
float Compute(const TrackPtr &fused_track, const SensorObjectPtr &sensor_object, const TrackObjectDistanceOptions &options)
float ComputeEuclideanDistance(const Eigen::Vector3d &des, const Eigen::Vector3d &src)
apollo::common::EigenVector< EigenType > EigenVector
double ComputeRadarCameraSimilarity(const SensorObjectConstPtr &radar, const SensorObjectConstPtr &camera)
float ComputeRadarRadar(const SensorObjectConstPtr &fused_object, const SensorObjectPtr &sensor_object, const Eigen::Vector3d &ref_pos, int range=3)
double ComputeLidarCameraSimilarity(const SensorObjectConstPtr &lidar, const SensorObjectConstPtr &camera, const bool measurement_is_lidar)
float ComputeLidarRadar(const SensorObjectConstPtr &fused_object, const SensorObjectPtr &sensor_object, const Eigen::Vector3d &ref_pos, int range=3)
float ComputeLidarCamera(const SensorObjectConstPtr &lidar, const SensorObjectConstPtr &camera, const bool measurement_is_lidar, const bool is_track_id_consistent)
float ComputeCameraCamera(const SensorObjectPtr &fused_camera, const SensorObjectPtr &sensor_camera)
float ComputeRadarCamera(const SensorObjectConstPtr &radar, const SensorObjectConstPtr &camera)
bool ComputePolygonCenter(const base::PolygonDType &polygon, Eigen::Vector3d *center)
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
uint32_t height
Height of point cloud
uint32_t width
Width of point cloud
std::shared_ptr< BaseCameraModel > BaseCameraModelPtr
Definition camera.h:75
Point< float > PointF
Definition point.h:56
AttributePointCloud< PointF > PointFCloud
std::shared_ptr< const Object > ObjectConstPtr
Definition object.h:128
PointCloud< PointD > PolygonDType
BBox2D< float > BBox2DF
Definition box.h:164
std::shared_ptr< const SensorObject > SensorObjectConstPtr
std::shared_ptr< SensorObject > SensorObjectPtr
double FuseMultipleProbabilities(const std::vector< double > &probs)
bool IsCamera(const SensorObjectConstPtr &obj)
double ComputePtsBoxSimilarity(const ProjectionCachePtr &cache, const ProjectionCacheObject *object, const base::BBox2DF &camera_bbox)
double ComputeRadarCameraWSimilarity(const SensorObjectConstPtr &radar, const double width, const double size_x, const EigenVector< Eigen::Vector2d > &radar_box2d_vertices, const WSimilarityParams &params)
calculate the w similarity between radar and camera
double ComputeRadarCameraYSimilarity(const double velo_ct_y, const double camera_ct_y, const double size_y, const YSimilarityParams &params)
calculate the y similarity between radar and camera
std::shared_ptr< Track > TrackPtr
Definition track.h:397
std::shared_ptr< FusedObject > FusedObjectPtr
double ComputeRadarCameraXSimilarity(const double velo_ct_x, const double camera_ct_x, const double size_x, const XSimilarityParams &params)
void GetObjectEightVertices(std::shared_ptr< const base::Object > obj, EigenVector< Eigen::Vector3d > *vertices)
bool IsLidar(const SensorObjectConstPtr &obj)
double ComputeRadarCameraVelocitySimilarity(const SensorObjectConstPtr &radar, const SensorObjectConstPtr &camera)
calculate the velocity similarity between radar and camera
bool IsRadar(const SensorObjectConstPtr &obj)
double ComputeRadarCameraLocSimilarity(const Eigen::Vector3d &radar_ct, const SensorObjectConstPtr &camera, const Eigen::Matrix4d &world2camera_pose, const LocSimilarityParams &params)
calculate the loc similarity between radar and camera
bool IsPtInFrustum(const VectorType &pt, double width, double height)
Is point lies in the frustum
Definition camera_util.h:49
double ComputeRadarCameraHSimilarity(const SensorObjectConstPtr &radar, const SensorObjectConstPtr &camera, const double size_y, const EigenVector< Eigen::Vector2d > &radar_box2d_vertices, const HSimilarityParams &params)
calculate the h similarity between radar and camera
class register implement
Definition arena_queue.h:37
Point2D< T > Center() const
Definition box.h:145