Apollo 11.0
自动驾驶开放平台
lane_detection_component.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 <iomanip>
20#include <iostream>
21#include <string>
22#include <tuple>
23
24#include <boost/algorithm/string.hpp>
25#include <boost/format.hpp>
26
27#include "Eigen/Core"
28#include "Eigen/Dense"
29#include "absl/strings/str_cat.h"
30#include "yaml-cpp/yaml.h"
31
32#include "cyber/common/file.h"
33#include "cyber/common/log.h"
34#include "cyber/time/clock.h"
41
42namespace apollo {
43namespace perception {
44namespace onboard {
45
47using ::apollo::cyber::Clock;
49
50FunInfoType LaneDetectionComponent::init_func_arry_[] = {
51 {&LaneDetectionComponent::InitSensorInfo, "InitSensorInfo"},
52 {&LaneDetectionComponent::InitCameraFrames, "InitCameraFrames"},
53 {&LaneDetectionComponent::InitProjectMatrix, "InitProjectMatrix"},
54 {&LaneDetectionComponent::InitMotionService, "InitMotionService"},
55 {&LaneDetectionComponent::InitCameraListeners, "InitCameraListeners"}};
56
57static int GetGpuId(const camera::CameraPerceptionInitOptions &options) {
58 camera::app::PerceptionParam perception_param;
59 std::string config_file =
60 GetAbsolutePath(options.config_path, options.config_file);
61 if (!cyber::common::GetProtoFromFile(config_file, &perception_param)) {
62 AERROR << "Read config failed: " << config_file;
63 return -1;
64 }
65 if (!perception_param.has_gpu_id()) {
66 AINFO << "gpu id not found.";
67 return -1;
68 }
69 return perception_param.gpu_id();
70}
71
72static bool SetCameraHeight(const std::string &sensor_name,
73 const std::string &params_dir,
74 const std::string &lidar_sensor_name,
75 float default_camera_height, float *camera_height) {
76 float base_h = default_camera_height;
77 float camera_offset = 0.0f;
78 try {
79 YAML::Node lidar_height =
80 YAML::LoadFile(params_dir + "/" + lidar_sensor_name + "_height.yaml");
81 base_h = lidar_height["vehicle"]["parameters"]["height"].as<float>();
82 AINFO << base_h;
83 YAML::Node camera_ex =
84 YAML::LoadFile(params_dir + "/" + sensor_name + "_extrinsics.yaml");
85 camera_offset = camera_ex["transform"]["translation"]["z"].as<float>();
86 AINFO << camera_offset;
87 *camera_height = base_h + camera_offset;
88 } catch (YAML::InvalidNode &in) {
89 AERROR << "load camera extrisic file error, YAML::InvalidNode exception";
90 return false;
91 } catch (YAML::TypedBadConversion<float> &bc) {
92 AERROR << "load camera extrisic file error, "
93 << "YAML::TypedBadConversion exception";
94 return false;
95 } catch (YAML::Exception &e) {
96 AERROR << "load camera extrisic file "
97 << " error, YAML exception:" << e.what();
98 return false;
99 }
100 return true;
101}
102
103// @description: load camera extrinsics from yaml file
104static bool LoadExtrinsics(const std::string &yaml_file,
105 Eigen::Matrix4d *camera_extrinsic) {
106 if (!apollo::cyber::common::PathExists(yaml_file)) {
107 AINFO << yaml_file << " not exist!";
108 return false;
109 }
110 YAML::Node node = YAML::LoadFile(yaml_file);
111 double qw = 0.0;
112 double qx = 0.0;
113 double qy = 0.0;
114 double qz = 0.0;
115 double tx = 0.0;
116 double ty = 0.0;
117 double tz = 0.0;
118 try {
119 if (node.IsNull()) {
120 AINFO << "Load " << yaml_file << " failed! please check!";
121 return false;
122 }
123 qw = node["transform"]["rotation"]["w"].as<double>();
124 qx = node["transform"]["rotation"]["x"].as<double>();
125 qy = node["transform"]["rotation"]["y"].as<double>();
126 qz = node["transform"]["rotation"]["z"].as<double>();
127 tx = node["transform"]["translation"]["x"].as<double>();
128 ty = node["transform"]["translation"]["y"].as<double>();
129 tz = node["transform"]["translation"]["z"].as<double>();
130 } catch (YAML::InvalidNode &in) {
131 AERROR << "load camera extrisic file " << yaml_file
132 << " with error, YAML::InvalidNode exception";
133 return false;
134 } catch (YAML::TypedBadConversion<double> &bc) {
135 AERROR << "load camera extrisic file " << yaml_file
136 << " with error, YAML::TypedBadConversion exception";
137 return false;
138 } catch (YAML::Exception &e) {
139 AERROR << "load camera extrisic file " << yaml_file
140 << " with error, YAML exception:" << e.what();
141 return false;
142 }
143 camera_extrinsic->setConstant(0);
144 Eigen::Quaterniond q;
145 q.x() = qx;
146 q.y() = qy;
147 q.z() = qz;
148 q.w() = qw;
149 (*camera_extrinsic).block<3, 3>(0, 0) = q.normalized().toRotationMatrix();
150 (*camera_extrinsic)(0, 3) = tx;
151 (*camera_extrinsic)(1, 3) = ty;
152 (*camera_extrinsic)(2, 3) = tz;
153 (*camera_extrinsic)(3, 3) = 1;
154 return true;
155}
156
157// @description: get project matrix
158static bool GetProjectMatrix(
159 const std::vector<std::string> &camera_names,
160 const EigenMap<std::string, Eigen::Matrix4d> &extrinsic_map,
161 const EigenMap<std::string, Eigen::Matrix3f> &intrinsic_map,
162 Eigen::Matrix3d *project_matrix, double *pitch_diff = nullptr) {
163 if (camera_names.size() != 2) {
164 AINFO << "camera number must be 2!";
165 return false;
166 }
167 *project_matrix =
168 intrinsic_map.at(camera_names[0]).cast<double>() *
169 extrinsic_map.at(camera_names[0]).block<3, 3>(0, 0).inverse() *
170 extrinsic_map.at(camera_names[1]).block<3, 3>(0, 0) *
171 intrinsic_map.at(camera_names[1]).cast<double>().inverse();
172 // extract the pitch_diff = pitch_narrow - pitch_obstacle
173 if (pitch_diff != nullptr) {
174 Eigen::Vector3d euler =
175 (extrinsic_map.at(camera_names[0]).block<3, 3>(0, 0).inverse() *
176 extrinsic_map.at(camera_names[1]).block<3, 3>(0, 0))
177 .eulerAngles(0, 1, 2);
178 *pitch_diff = euler(0);
179 AINFO << "pitch diff: " << *pitch_diff;
180 }
181 return true;
182}
183
185
187 if (InitConfig() != cyber::SUCC) {
188 AERROR << "InitConfig() failed.";
189 return false;
190 }
191
192 writer_ = node_->CreateWriter<PerceptionLanes>(output_lanes_channel_name_);
194 LaneDetectionComponent::init_func_arry_)) {
195 return false;
196 }
197 SetCameraHeightAndPitch();
198
199 // Init visualizer
200 // TODO(techoe, yg13): homography from image to ground should be
201 // computed from camera height and pitch.
202 // Apply online calibration to adjust pitch/height automatically
203 // Temporary code is used here for testing
204 double pitch_adj_degree = 0.0;
205 double yaw_adj_degree = 0.0;
206 double roll_adj_degree = 0.0;
207 // load in lidar to imu extrinsic
208 Eigen::Matrix4d ex_lidar2imu;
209 // Todo(zero): need fix! use tf
210 LoadExtrinsics(FLAGS_obs_sensor_intrinsic_path + "/" +
211 FLAGS_lidar_sensor_name + "_novatel_extrinsics.yaml",
212 &ex_lidar2imu);
213 AINFO << FLAGS_lidar_sensor_name + "_novatel_extrinsics.yaml: "
214 << ex_lidar2imu;
215
217 camera_names_, visual_camera_, intrinsic_map_, extrinsic_map_,
218 ex_lidar2imu, pitch_adj_degree, yaw_adj_degree, roll_adj_degree,
219 image_height_, image_width_));
220 homography_image2ground_ = visualize_.homography_im2car(visual_camera_);
221 camera_lane_pipeline_->SetIm2CarHomography(homography_image2ground_);
222
223 if (enable_visualization_) {
224 if (write_visual_img_) {
225 visualize_.write_out_img_ = true;
226 visualize_.SetDirectory(visual_debug_folder_);
227 }
228 }
229 AINFO << "Init processes all succeed";
230 return true;
231}
232
233// On receiving motion service input, convert it to motion_buff_
234void LaneDetectionComponent::OnMotionService(
235 const MotionServiceMsgType &message) {
236 // Comment: use the circular buff to do it smartly, only push the latest
237 // circular_buff only saves only the incremental motion between frames.
238 // motion_service is now hard-coded for camera front 6mm
239 base::VehicleStatus vehicledata;
240 vehicledata.roll_rate = message->vehicle_status()[0].roll_rate();
241 vehicledata.pitch_rate = message->vehicle_status()[0].pitch_rate();
242 vehicledata.yaw_rate = message->vehicle_status()[0].yaw_rate();
243 vehicledata.velocity = message->vehicle_status()[0].velocity();
244 vehicledata.velocity_x = message->vehicle_status()[0].velocity_x();
245 vehicledata.velocity_y = message->vehicle_status()[0].velocity_y();
246 vehicledata.velocity_z = message->vehicle_status()[0].velocity_z();
247 vehicledata.time_ts = message->vehicle_status()[0].time_ts();
248 vehicledata.time_d = message->vehicle_status()[0].time_d();
249
250 base::MotionType motion_2d = base::MotionType::Identity();
251 motion_2d(0, 0) = message->vehicle_status()[0].motion().m00();
252 motion_2d(0, 1) = message->vehicle_status()[0].motion().m01();
253 motion_2d(0, 2) = message->vehicle_status()[0].motion().m02();
254 motion_2d(0, 3) = message->vehicle_status()[0].motion().m03();
255 motion_2d(1, 0) = message->vehicle_status()[0].motion().m10();
256 motion_2d(1, 1) = message->vehicle_status()[0].motion().m11();
257 motion_2d(1, 2) = message->vehicle_status()[0].motion().m12();
258 motion_2d(1, 3) = message->vehicle_status()[0].motion().m13();
259 motion_2d(2, 0) = message->vehicle_status()[0].motion().m20();
260 motion_2d(2, 1) = message->vehicle_status()[0].motion().m21();
261 motion_2d(2, 2) = message->vehicle_status()[0].motion().m22();
262 motion_2d(2, 3) = message->vehicle_status()[0].motion().m23();
263 motion_2d(3, 0) = message->vehicle_status()[0].motion().m30();
264 motion_2d(3, 1) = message->vehicle_status()[0].motion().m31();
265 motion_2d(3, 2) = message->vehicle_status()[0].motion().m32();
266 motion_2d(3, 3) = message->vehicle_status()[0].motion().m33();
267 vehicledata.motion = motion_2d;
268
269 mot_buffer_->push_back(vehicledata);
270
271 // TODO(@yg13): output motion in text file
272}
273
274void LaneDetectionComponent::OnReceiveImage(
275 const std::shared_ptr<apollo::drivers::Image> &message,
276 const std::string &camera_name) {
277 std::lock_guard<std::mutex> lock(mutex_);
278 const double msg_timestamp = message->measurement_time() + timestamp_offset_;
279 AINFO << "Enter LaneDetectionComponent::Proc(), camera_name: " << camera_name
280 << " image ts: " << msg_timestamp;
281 // timestamp should be almost monotonic
282 if (last_timestamp_ - msg_timestamp > ts_diff_) {
283 AINFO << "Received an old message. Last ts is " << std::setprecision(19)
284 << last_timestamp_ << " current ts is " << msg_timestamp
285 << " last - current is " << last_timestamp_ - msg_timestamp;
286 return;
287 }
288 last_timestamp_ = msg_timestamp;
289 ++seq_num_;
290
291 // for e2e lantency statistics
292 {
293 const double cur_time = Clock::NowInSeconds();
294 const double start_latency = (cur_time - message->measurement_time()) * 1e3;
295 AINFO << "FRAME_STATISTICS:Camera:Start:msg_time[" << camera_name << "-"
296 << FORMAT_TIMESTAMP(message->measurement_time()) << "]:cur_time["
297 << FORMAT_TIMESTAMP(cur_time) << "]:cur_latency[" << start_latency
298 << "]";
299 }
300
301 // protobuf msg
302 std::shared_ptr<apollo::perception::PerceptionLanes> out_message(
303 new (std::nothrow) apollo::perception::PerceptionLanes);
305
306 // prefused msg
307 std::shared_ptr<SensorFrameMessage> prefused_message(new (std::nothrow)
308 SensorFrameMessage);
309 if (InternalProc(message, camera_name, &error_code, prefused_message.get(),
310 out_message.get()) != cyber::SUCC) {
311 AERROR << "InternalProc failed, error_code: " << error_code;
312 return;
313 }
314
315 // for e2e lantency statistics
316 {
317 const double end_timestamp = Clock::NowInSeconds();
318 const double end_latency =
319 (end_timestamp - message->measurement_time()) * 1e3;
320 AINFO << "FRAME_STATISTICS:Camera:End:msg_time[" << camera_name << "-"
321 << FORMAT_TIMESTAMP(message->measurement_time()) << "]:cur_time["
322 << FORMAT_TIMESTAMP(end_timestamp) << "]:cur_latency[" << end_latency
323 << "]";
324 }
325}
326
327int LaneDetectionComponent::InitConfig() {
328 // the macro READ_CONF would return cyber::FAIL if config not exists
330 if (!GetProtoConfig(&lane_detection_param)) {
331 AINFO << "load lane detection component proto param failed";
332 return false;
333 }
334
335 std::string camera_names_str = lane_detection_param.camera_names();
336 boost::algorithm::split(camera_names_, camera_names_str,
337 boost::algorithm::is_any_of(","));
338 if (camera_names_.size() != 2) {
339 AERROR << "Now LaneDetectionComponent only support 2 cameras";
340 return cyber::FAIL;
341 }
342
343 std::string input_camera_channel_names_str =
344 lane_detection_param.input_camera_channel_names();
345 boost::algorithm::split(input_camera_channel_names_,
346 input_camera_channel_names_str,
347 boost::algorithm::is_any_of(","));
348 if (input_camera_channel_names_.size() != camera_names_.size()) {
349 AERROR << "wrong input_camera_channel_names_.size(): "
350 << input_camera_channel_names_.size();
351 return cyber::FAIL;
352 }
353
354 // Init camera_lane_pipeline
355 auto detection_param = lane_detection_param.detection_param();
356 camera_perception_init_options_.config_path = detection_param.config_path();
357 camera_perception_init_options_.config_file = detection_param.config_file();
358 camera_perception_init_options_.lane_calibration_working_sensor_name =
359 lane_detection_param.lane_calibration_working_sensor_name();
360
361 frame_capacity_ = lane_detection_param.frame_capacity();
362 image_channel_num_ = lane_detection_param.image_channel_num();
363 enable_undistortion_ = lane_detection_param.enable_undistortion();
364 enable_visualization_ = lane_detection_param.enable_visualization();
365 visual_debug_folder_ = lane_detection_param.visual_debug_folder();
366 visual_camera_ = lane_detection_param.visual_camera();
367 output_lanes_channel_name_ = lane_detection_param.output_lanes_channel_name();
368 default_camera_pitch_ =
369 static_cast<float>(lane_detection_param.default_camera_pitch());
370 default_camera_height_ =
371 static_cast<float>(lane_detection_param.default_camera_height());
372 ts_diff_ = lane_detection_param.ts_diff();
373 write_visual_img_ = lane_detection_param.write_visual_img();
374
375 std::string format_str = R"(
376 LaneDetectionComponent InitConfig success
377 camera_names: %s, %s
378 camera_lane_perception_config_path: %s
379 camera_lane_perception_config_file: %s
380 frame_capacity: %d
381 image_channel_num: %d
382 enable_undistortion: %d
383 enable_visualization: %d
384 visual_debug_folder_: %s
385 visual_camera_: %s
386 output_lanes_channel_name: %s
387 write_visual_img_: %s)";
388 std::string config_info_str =
389 str(boost::format(format_str.c_str()) % camera_names_[0] %
390 camera_names_[1] % camera_perception_init_options_.config_path %
391 camera_perception_init_options_.config_file % frame_capacity_ %
392 image_channel_num_ % enable_undistortion_ % enable_visualization_ %
393 visual_debug_folder_ % visual_camera_ % output_lanes_channel_name_ %
394 write_visual_img_);
395 AINFO << config_info_str;
396
397 return cyber::SUCC;
398}
399
400int LaneDetectionComponent::InitSensorInfo() {
401 if (camera_names_.size() != 2) {
402 AERROR << "invalid camera_names_.size(): " << camera_names_.size();
403 return cyber::FAIL;
404 }
405
406 auto *sensor_manager = algorithm::SensorManager::Instance();
407 for (size_t i = 0; i < camera_names_.size(); ++i) {
408 if (!sensor_manager->IsSensorExist(camera_names_[i])) {
409 AERROR << ("sensor_name: " + camera_names_[i] + " not exists.");
410 return cyber::FAIL;
411 }
412
413 base::SensorInfo sensor_info;
414 if (!(sensor_manager->GetSensorInfo(camera_names_[i], &sensor_info))) {
415 AERROR << "Failed to get sensor info, sensor name: " << camera_names_[i];
416 return cyber::FAIL;
417 }
418 sensor_info_map_[camera_names_[i]] = sensor_info;
419
420 std::string tf_camera_frame_id =
421 sensor_manager->GetFrameId(camera_names_[i]);
422 tf_camera_frame_id_map_[camera_names_[i]] = tf_camera_frame_id;
423 std::shared_ptr<TransformWrapper> trans_wrapper(new TransformWrapper);
424 trans_wrapper->Init(tf_camera_frame_id);
425 camera2world_trans_wrapper_map_[camera_names_[i]] = trans_wrapper;
426 }
427
428 // assume all camera have same image size
429 base::BaseCameraModelPtr camera_model_ptr =
430 sensor_manager->GetUndistortCameraModel(camera_names_[0]);
431 ACHECK(camera_model_ptr) << "Can't find " << camera_names_[0]
432 << " in data/conf/sensor_meta.pb.txt";
433 image_width_ = static_cast<int>(camera_model_ptr->get_width());
434 image_height_ = static_cast<int>(camera_model_ptr->get_height());
435
436 std::string format_str = R"(
437 camera_names: %s %s
438 tf_camera_frame_ids: %s %s
439 image_width: %d
440 image_height: %d
441 image_channel_num: %d)";
442 std::string sensor_info_str =
443 str(boost::format(format_str.c_str()) % camera_names_[0] %
444 camera_names_[1] % tf_camera_frame_id_map_[camera_names_[0]] %
445 tf_camera_frame_id_map_[camera_names_[1]] % image_width_ %
446 image_height_ % image_channel_num_);
447 AINFO << sensor_info_str;
448
449 return cyber::SUCC;
450}
451
452int LaneDetectionComponent::InitAlgorithmPlugin() {
453 camera_lane_pipeline_.reset(new camera::LaneCameraPerception);
454 if (!camera_lane_pipeline_->Init(camera_perception_init_options_)) {
455 AERROR << "camera_lane_pipeline_->Init() failed";
456 return cyber::FAIL;
457 }
458 AINFO << "camera_lane_pipeline_->Init() succeed";
459 return cyber::SUCC;
460}
461
462int LaneDetectionComponent::InitCameraFrames() {
463 if (camera_names_.size() != 2) {
464 AERROR << "invalid camera_names_.size(): " << camera_names_.size();
465 return cyber::FAIL;
466 }
467 // fixed size
468 camera_frames_.resize(frame_capacity_);
469 if (camera_frames_.empty()) {
470 AERROR << "frame_capacity_ must > 0";
471 return cyber::FAIL;
472 }
473
474 // init data_providers for each camera
475 for (const auto &camera_name : camera_names_) {
476 camera::DataProvider::InitOptions data_provider_init_options;
477 data_provider_init_options.image_height = image_height_;
478 data_provider_init_options.image_width = image_width_;
479 data_provider_init_options.do_undistortion = enable_undistortion_;
480 data_provider_init_options.sensor_name = camera_name;
481 int gpu_id = GetGpuId(camera_perception_init_options_);
482 if (gpu_id == -1) {
483 return cyber::FAIL;
484 }
485 data_provider_init_options.device_id = gpu_id;
486 AINFO << "data_provider_init_options.device_id: "
487 << data_provider_init_options.device_id
488 << " camera_name: " << camera_name;
489
490 std::shared_ptr<camera::DataProvider> data_provider(
491 new camera::DataProvider);
492 data_provider->Init(data_provider_init_options);
493 data_providers_map_[camera_name] = data_provider;
494 }
495
496 // init extrinsic/intrinsic
497 for (const auto &camera_name : camera_names_) {
499 model = algorithm::SensorManager::Instance()->GetUndistortCameraModel(
500 camera_name);
501 ACHECK(model) << "Can't find " << camera_name
502 << " in data/conf/sensor_meta.pb.txt";
503 auto pinhole = static_cast<base::PinholeCameraModel *>(model.get());
504 Eigen::Matrix3f intrinsic = pinhole->get_intrinsic_params();
505 intrinsic_map_[camera_name] = intrinsic;
506 AINFO << "#intrinsics of " << camera_name << ": "
507 << intrinsic_map_[camera_name];
508 Eigen::Matrix4d extrinsic;
509 // Todo(zero): need fix! use tf
510 LoadExtrinsics(FLAGS_obs_sensor_intrinsic_path + "/" + camera_name +
511 "_extrinsics.yaml",
512 &extrinsic);
513 extrinsic_map_[camera_name] = extrinsic;
514 }
515
516 // Init camera height
517 for (const auto &camera_name : camera_names_) {
518 float height = 0.0f;
519 // Todo(zero): need fix! use SensorManager
520 SetCameraHeight(camera_name, FLAGS_obs_sensor_intrinsic_path,
521 FLAGS_lidar_sensor_name, default_camera_height_, &height);
522 camera_height_map_[camera_name] = height;
523 }
524
525 for (auto &frame : camera_frames_) {
526 frame.track_feature_blob.reset(new base::Blob<float>());
527 frame.lane_detected_blob.reset(new base::Blob<float>());
528 }
529 return cyber::SUCC;
530}
531
532int LaneDetectionComponent::InitProjectMatrix() {
533 if (!GetProjectMatrix(camera_names_, extrinsic_map_, intrinsic_map_,
534 &project_matrix_, &pitch_diff_)) {
535 AERROR << "GetProjectMatrix failed";
536 return cyber::FAIL;
537 }
538 AINFO << "project_matrix_: " << project_matrix_;
539 AINFO << "pitch_diff_:" << pitch_diff_;
540 name_camera_pitch_angle_diff_map_[camera_names_[0]] = 0.f;
541 name_camera_pitch_angle_diff_map_[camera_names_[1]] =
542 static_cast<float>(pitch_diff_);
543
544 return cyber::SUCC;
545}
546
547int LaneDetectionComponent::InitMotionService() {
548 const std::string &channel_name_local = "/apollo/perception/motion_service";
549 std::function<void(const MotionServiceMsgType &)> motion_service_callback =
550 std::bind(&LaneDetectionComponent::OnMotionService, this,
551 std::placeholders::_1);
552 auto motion_service_reader =
553 node_->CreateReader(channel_name_local, motion_service_callback);
554 // initialize motion buffer
555 if (mot_buffer_ == nullptr) {
556 mot_buffer_.reset(new base::MotionBuffer(motion_buffer_size_));
557 } else {
558 mot_buffer_->set_capacity(motion_buffer_size_);
559 }
560 return cyber::SUCC;
561}
562
563int LaneDetectionComponent::InitCameraListeners() {
564 for (size_t i = 0; i < camera_names_.size(); ++i) {
565 const std::string &camera_name = camera_names_[i];
566 const std::string &channel_name = input_camera_channel_names_[i];
567 const std::string &listener_name = camera_name + "_fusion_camera_listener";
568 AINFO << "listener name: " << listener_name;
569
570 typedef std::shared_ptr<apollo::drivers::Image> ImageMsgType;
571 std::function<void(const ImageMsgType &)> camera_callback =
572 std::bind(&LaneDetectionComponent::OnReceiveImage, this,
573 std::placeholders::_1, camera_name);
574 auto camera_reader = node_->CreateReader(channel_name, camera_callback);
575 }
576 return cyber::SUCC;
577}
578
579void LaneDetectionComponent::SetCameraHeightAndPitch() {
580 camera_lane_pipeline_->SetCameraHeightAndPitch(
581 camera_height_map_, name_camera_pitch_angle_diff_map_,
582 default_camera_pitch_);
583}
584
585int LaneDetectionComponent::InternalProc(
586 const std::shared_ptr<apollo::drivers::Image const> &in_message,
587 const std::string &camera_name, apollo::common::ErrorCode *error_code,
588 SensorFrameMessage *prefused_message,
590 const double msg_timestamp =
591 in_message->measurement_time() + timestamp_offset_;
592 const int frame_size = static_cast<int>(camera_frames_.size());
593 camera::CameraFrame &camera_frame = camera_frames_[frame_id_ % frame_size];
594
595 prefused_message->timestamp_ = msg_timestamp;
596 prefused_message->seq_num_ = seq_num_;
597 prefused_message->process_stage_ = ProcessStage::MONOCULAR_CAMERA_DETECTION;
598 prefused_message->sensor_id_ = camera_name;
599 prefused_message->frame_ = base::FramePool::Instance().Get();
600 prefused_message->frame_->sensor_info = sensor_info_map_[camera_name];
601 prefused_message->frame_->timestamp = msg_timestamp;
602
603 // Get sensor to world pose from TF
604 Eigen::Affine3d camera2world_trans;
605 if (!camera2world_trans_wrapper_map_[camera_name]->GetSensor2worldTrans(
606 msg_timestamp, &camera2world_trans)) {
607 const std::string err_str =
608 absl::StrCat("failed to get camera to world pose, ts: ", msg_timestamp,
609 " camera_name: ", camera_name);
610 AERROR << err_str;
612 prefused_message->error_code_ = *error_code;
613 return cyber::FAIL;
614 }
615 Eigen::Affine3d world2camera = camera2world_trans.inverse();
616 prefused_message->frame_->sensor2world_pose = camera2world_trans;
617
618 // Fill camera frame
619 // frame_size != 0, see InitCameraFrames()
620 camera_frame.camera2world_pose = camera2world_trans;
621 camera_frame.data_provider = data_providers_map_[camera_name].get();
622 camera_frame.data_provider->FillImageData(
623 image_height_, image_width_,
624 reinterpret_cast<const uint8_t *>(in_message->data().data()),
625 in_message->encoding());
626
627 camera_frame.frame_id = frame_id_;
628 camera_frame.timestamp = msg_timestamp;
629 // get narrow to short projection matrix
630 if (camera_frame.data_provider->sensor_name() == camera_names_[1]) {
631 camera_frame.project_matrix = project_matrix_;
632 } else {
633 camera_frame.project_matrix.setIdentity();
634 }
635
636 ++frame_id_;
637 // Run camera perception pipeline
638 camera_lane_pipeline_->GetCalibrationService(
639 &camera_frame.calibration_service);
640
641 camera::CameraPerceptionOptions camera_perception_options;
642 if (!camera_lane_pipeline_->Perception(camera_perception_options,
643 &camera_frame)) {
644 AERROR << "camera_lane_pipeline_->Perception() failed msg_timestamp: "
645 << msg_timestamp;
647 prefused_message->error_code_ = *error_code;
648 return cyber::FAIL;
649 }
650 AINFO << "##" << camera_name << ": pitch "
651 << camera_frame.calibration_service->QueryPitchAngle()
652 << " | camera_grond_height "
653 << camera_frame.calibration_service->QueryCameraToGroundHeight();
654 prefused_message->frame_->objects = camera_frame.tracked_objects;
655
656 *error_code = apollo::common::ErrorCode::OK;
657 prefused_message->error_code_ = *error_code;
658
659 prefused_message->frame_->camera_frame_supplement.on_use = true;
660 if (FLAGS_obs_enable_visualization) {
661 camera::DataProvider::ImageOptions image_options;
662 image_options.target_color = base::Color::RGB;
663
664 // Use Blob to pass image data
665 prefused_message->frame_->camera_frame_supplement.image_blob.reset(
666 new base::Blob<uint8_t>);
667 camera_frame.data_provider->GetImageBlob(
668 image_options,
669 prefused_message->frame_->camera_frame_supplement.image_blob.get());
670 }
671
672 // Send msg for visualization
673 if (enable_visualization_) {
674 camera::DataProvider::ImageOptions image_options;
675 image_options.target_color = base::Color::BGR;
676 std::shared_ptr<base::Blob<uint8_t>> image_blob(new base::Blob<uint8_t>);
677 camera_frame.data_provider->GetImageBlob(image_options, image_blob.get());
678
679 cv::Mat output_image(image_height_, image_width_, CV_8UC3,
680 cv::Scalar(0, 0, 0));
681 base::Image8U out_image(image_height_, image_width_, base::Color::RGB);
682 camera_frame.data_provider->GetImage(image_options, &out_image);
683 memcpy(output_image.data, out_image.cpu_data(),
684 out_image.total() * sizeof(uint8_t));
685 visualize_.ShowResult_all_info_single_camera(output_image, camera_frame,
686 mot_buffer_, world2camera);
687 }
688
689 // send out lane message
690 // TODO(yg13): add lanes in world coordinates
691 std::shared_ptr<apollo::perception::PerceptionLanes> lanes_msg(
692 new (std::nothrow) apollo::perception::PerceptionLanes);
693 if (MakeProtobufMsg(msg_timestamp, camera_name, camera_frame,
694 lanes_msg.get()) != cyber::SUCC) {
695 AERROR << "make lanes_msg failed";
696 return cyber::FAIL;
697 }
698 writer_->Write(lanes_msg);
699
700 return cyber::SUCC;
701}
702
703int LaneDetectionComponent::ConvertLaneToCameraLaneline(
704 const base::LaneLine &lane_line,
705 apollo::perception::camera::CameraLaneLine *camera_laneline) {
706 if (camera_laneline == nullptr) {
707 AERROR << "camera_laneline is not available";
708 return false;
709 }
710 // fill the lane line attribute
711 apollo::perception::camera::LaneLineType line_type =
712 static_cast<apollo::perception::camera::LaneLineType>(lane_line.type);
713 camera_laneline->set_type(line_type);
714 apollo::perception::camera::LaneLinePositionType pos_type =
715 static_cast<apollo::perception::camera::LaneLinePositionType>(
716 lane_line.pos_type);
717 camera_laneline->set_pos_type(pos_type);
718 camera_laneline->set_track_id(lane_line.track_id);
719 camera_laneline->set_confidence(lane_line.confidence);
720 apollo::perception::camera::LaneLineUseType use_type =
721 static_cast<apollo::perception::camera::LaneLineUseType>(
722 lane_line.use_type);
723 camera_laneline->set_use_type(use_type);
724 // fill the curve camera coord
725 camera_laneline->mutable_curve_camera_coord()->set_longitude_min(
726 lane_line.curve_camera_coord.x_start);
727 camera_laneline->mutable_curve_camera_coord()->set_longitude_max(
728 lane_line.curve_camera_coord.x_end);
729 camera_laneline->mutable_curve_camera_coord()->set_a(
730 lane_line.curve_camera_coord.a);
731 camera_laneline->mutable_curve_camera_coord()->set_b(
732 lane_line.curve_camera_coord.b);
733 camera_laneline->mutable_curve_camera_coord()->set_c(
734 lane_line.curve_camera_coord.c);
735 camera_laneline->mutable_curve_camera_coord()->set_d(
736 lane_line.curve_camera_coord.d);
737 // fill the curve image coord
738 camera_laneline->mutable_curve_image_coord()->set_longitude_min(
739 lane_line.curve_image_coord.x_start);
740 camera_laneline->mutable_curve_image_coord()->set_longitude_max(
741 lane_line.curve_image_coord.x_end);
742 camera_laneline->mutable_curve_image_coord()->set_a(
743 lane_line.curve_image_coord.a);
744 camera_laneline->mutable_curve_image_coord()->set_b(
745 lane_line.curve_image_coord.b);
746 camera_laneline->mutable_curve_image_coord()->set_c(
747 lane_line.curve_image_coord.c);
748 camera_laneline->mutable_curve_image_coord()->set_d(
749 lane_line.curve_image_coord.d);
750 // fill the curve image point set
751 for (size_t i = 0; i < lane_line.curve_image_point_set.size(); i++) {
752 const base::Point2DF &image_point2d = lane_line.curve_image_point_set[i];
753 apollo::common::Point2D *lane_point_2d =
754 camera_laneline->add_curve_image_point_set();
755 lane_point_2d->set_x(image_point2d.x);
756 lane_point_2d->set_y(image_point2d.y);
757 }
758 // fill the curve camera point set
759 for (size_t i = 0; i < lane_line.curve_camera_point_set.size(); i++) {
760 const base::Point3DF &point3d = lane_line.curve_camera_point_set[i];
761 apollo::common::Point3D *lane_point_3d =
762 camera_laneline->add_curve_camera_point_set();
763 lane_point_3d->set_x(point3d.x);
764 lane_point_3d->set_y(point3d.y);
765 lane_point_3d->set_z(point3d.z);
766 }
767 // fill the line end point set
768 for (size_t i = 0; i < lane_line.image_end_point_set.size(); i++) {
769 const base::EndPoints &end_points = lane_line.image_end_point_set[i];
770 apollo::perception::camera::EndPoints *lane_end_points =
771 camera_laneline->add_image_end_point_set();
772 lane_end_points->mutable_start()->set_x(end_points.start.x);
773 lane_end_points->mutable_start()->set_y(end_points.start.y);
774 lane_end_points->mutable_end()->set_x(end_points.end.x);
775 lane_end_points->mutable_end()->set_y(end_points.end.y);
776 }
777 return cyber::SUCC;
778}
779
780int LaneDetectionComponent::MakeProtobufMsg(
781 double msg_timestamp, const std::string &camera_name,
782 const camera::CameraFrame &camera_frame,
784 if (lanes_msg == nullptr) {
785 AERROR << "lanes_msg is not available";
786 return false;
787 }
788 auto itr = std::find(camera_names_.begin(), camera_names_.end(), camera_name);
789 if (itr == camera_names_.end()) {
790 AERROR << "invalid camera_name: " << camera_name;
791 return cyber::FAIL;
792 }
793 int input_camera_channel_names_idx =
794 static_cast<int>(itr - camera_names_.begin());
795 int input_camera_channel_names_size =
796 static_cast<int>(input_camera_channel_names_.size());
797 if (input_camera_channel_names_idx < 0 ||
798 input_camera_channel_names_idx >= input_camera_channel_names_size) {
799 AERROR << "invalid input_camera_channel_names_idx: "
800 << input_camera_channel_names_idx
801 << " input_camera_channel_names_.size(): "
802 << input_camera_channel_names_.size();
803 return cyber::FAIL;
804 }
805 std::string source_channel_name =
806 input_camera_channel_names_[input_camera_channel_names_idx];
807 lanes_msg->set_source_topic(source_channel_name);
808
809 // Fill header info.
810 apollo::common::Header *header = lanes_msg->mutable_header();
811 header->set_camera_timestamp(static_cast<uint64_t>(msg_timestamp * 1.0e9));
812
813 // Fill the laneline objects
814 const std::vector<base::LaneLine> &lane_objects = camera_frame.lane_objects;
815 for (const auto &lane_obj : lane_objects) {
816 apollo::perception::camera::CameraLaneLine *camera_laneline =
817 lanes_msg->add_camera_laneline();
818 ConvertLaneToCameraLaneline(lane_obj, camera_laneline);
819 }
820
821 // Fill the calibrator information(pitch angle)
822 float pitch_angle = camera_frame.calibration_service->QueryPitchAngle();
823 lanes_msg->mutable_camera_calibrator()->set_pitch_angle(pitch_angle);
824 return cyber::SUCC;
825}
826
827} // namespace onboard
828} // namespace perception
829} // namespace apollo
static double NowInSeconds()
gets the current time in second.
Definition clock.cc:56
bool GetProtoConfig(T *config) const
std::shared_ptr< Node > node_
bool SetDirectory(const std::string &path)
Eigen::Matrix3d homography_im2car(std::string camera_name)
Definition visualizer.h:80
bool Init_all_info_single_camera(const std::vector< std::string > &camera_names, const std::string &visual_camera, const EigenMap< std::string, Eigen::Matrix3f > &intrinsic_map, const EigenMap< std::string, Eigen::Matrix4d > &extrinsic_map, const Eigen::Matrix4d &ex_lidar2imu, const double pitch_adj, const double yaw_adj, const double roll_adj, const int image_height, const int image_width)
void ShowResult_all_info_single_camera(const cv::Mat &img, const CameraFrame &frame, const base::MotionBufferPtr motion_buffer, const Eigen::Affine3d &world2camera)
std::shared_ptr< apollo::perception::MotionService > MotionServiceMsgType
Math-related util functions.
#define ACHECK(cond)
Definition log.h:80
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
#define EXEC_ALL_FUNS(type, obj, list)
Definition util.h:154
std::map< T, EigenType, std::less< T >, Eigen::aligned_allocator< std::pair< const T, EigenType > > > EigenMap
Definition eigen_defs.h:40
bool PathExists(const std::string &path)
Check if the path exists.
Definition file.cc:195
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
std::string GetAbsolutePath(const std::string &prefix, const std::string &relative_path)
Get absolute path by concatenating prefix and relative_path.
Definition file.cc:179
uint32_t height
Height of point cloud
boost::circular_buffer< VehicleStatus > MotionBuffer
std::shared_ptr< BaseCameraModel > BaseCameraModelPtr
Definition camera.h:75
Point3D< float > Point3DF
Definition point.h:98
Point2D< float > Point2DF
Definition point.h:87
std::shared_ptr< apollo::drivers::Image > ImageMsgType
FunctionInfo< LaneDetectionComponent > FunInfoType
class register implement
Definition arena_queue.h:37
Some string util functions.
#define FORMAT_TIMESTAMP(timestamp)
Definition string_util.h:29