Apollo 11.0
自动驾驶开放平台
traffic_light_region_proposal_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 <sys/stat.h>
19#include <unistd.h>
20
21#include <limits>
22#include <map>
23#include <utility>
24
25#include <boost/algorithm/string.hpp>
26
27#include "absl/strings/str_cat.h"
28
29#include "cyber/common/file.h"
30#include "cyber/common/log.h"
32#include "cyber/time/clock.h"
38
39namespace apollo {
40namespace perception {
41namespace trafficlight {
42
46
48 if (InitConfig() != cyber::SUCC) {
49 AERROR << "TrafficLightsPerceptionComponent InitConfig failed.";
50 return false;
51 }
52
53 if (InitAlgorithmPlugin() != cyber::SUCC) {
54 AERROR << "TrafficLightsPerceptionComponent InitAlgorithmPlugin failed.";
55 return false;
56 }
57
58 if (InitCameraFrame() != cyber::SUCC) {
59 AERROR << "TrafficLightsPerceptionComponent InitCameraFrame failed.";
60 return false;
61 }
62
63 if (InitCameraListeners() != cyber::SUCC) {
64 AERROR << "TrafficLightsPerceptionComponent InitCameraListeners failed.";
65 return false;
66 }
67
68 return true;
69}
70
71int TrafficLightsPerceptionComponent::InitConfig() {
73 if (!GetProtoConfig(&traffic_light_param)) {
74 AINFO << "load trafficlights perception component proto param failed";
75 return cyber::FAIL;
76 }
77
78 tf2_frame_id_ = traffic_light_param.tl_tf2_frame_id();
79 tf2_child_frame_id_ = traffic_light_param.tl_tf2_child_frame_id();
80 tf2_timeout_second_ = traffic_light_param.tf2_timeout_second();
81 AINFO << "tl_tf2_frame_id: " << tf2_frame_id_
82 << " tl_tf2_child_frame_id: " << tf2_child_frame_id_
83 << " tf2_buff_size: " << tf2_timeout_second_;
84
85 std::string camera_names_str = "";
86 camera_names_str = traffic_light_param.camera_names();
87 boost::algorithm::split(camera_names_, camera_names_str,
88 boost::algorithm::is_any_of(","));
89
90 std::string camera_channel_names_str = "";
91 camera_channel_names_str = traffic_light_param.camera_channel_names();
92 boost::algorithm::split(input_camera_channel_names_, camera_channel_names_str,
93 boost::algorithm::is_any_of(","));
94
95 gpu_id_ = traffic_light_param.gpu_id();
96 proposal_output_channel_name_ =
97 traffic_light_param.proposal_output_channel_name();
98 query_tf_interval_seconds_ = traffic_light_param.query_tf_interval_seconds();
99 valid_hdmap_interval_ = traffic_light_param.valid_hdmap_interval();
100 image_timestamp_offset_ = traffic_light_param.tl_image_timestamp_offset();
101 AINFO << " _image_timestamp_offset: " << image_timestamp_offset_;
102
103 max_process_image_fps_ = traffic_light_param.max_process_image_fps();
104 proc_interval_seconds_ = 1.0 / max_process_image_fps_;
105 AINFO << "_proc_interval_seconds: " << proc_interval_seconds_;
106
107 image_sys_ts_diff_threshold_ =
108 traffic_light_param.image_sys_ts_diff_threshold();
109 preprocessor_init_options_.sync_interval_seconds =
110 static_cast<float>(traffic_light_param.sync_interval_seconds());
111
112 tl_preprocessor_name_ = traffic_light_param.plugin_param().name();
113
114 default_image_border_size_ = traffic_light_param.default_image_border_size();
115
116 traffic_detect_writer_ =
117 node_->CreateWriter<TrafficDetectMessage>(proposal_output_channel_name_);
118
119 return cyber::SUCC;
120}
121
122int TrafficLightsPerceptionComponent::InitAlgorithmPlugin() {
123 // init preprocessor
124 trafficlight::BaseTLPreprocessor* preprocessor =
125 trafficlight::BaseTLPreprocessorRegisterer::GetInstanceByName(
126 tl_preprocessor_name_);
127 CHECK_NOTNULL(preprocessor);
128 preprocessor_.reset(preprocessor);
129
130 preprocessor_init_options_.camera_names = camera_names_;
131 if (!preprocessor_->Init(preprocessor_init_options_)) {
132 AERROR << "TrafficLightsPerceptionComponent init preprocessor failed";
133 return cyber::FAIL;
134 }
135 const auto camera_names_by_descending_focal_len =
136 preprocessor_->GetCameraNamesByDescendingFocalLen();
137 if (camera_names_by_descending_focal_len.empty()) {
138 AERROR << "empty camera_names in preprocessor";
139 return cyber::FAIL;
140 }
141 if (camera_names_.size() != input_camera_channel_names_.size() ||
142 camera_names_.empty()) {
143 AERROR << "invalid camera_names config";
144 return cyber::FAIL;
145 }
146 SensorManager* sensor_manager = SensorManager::Instance();
147 for (size_t i = 0; i < camera_names_.size(); ++i) {
148 if (!sensor_manager->IsSensorExist(camera_names_[i])) {
149 AERROR << ("sensor_name: " + camera_names_[i] + " not exists.");
150 return cyber::FAIL;
151 }
152
153 // init transform wrappers
154 std::string tf2_camera_child_frame_id =
155 sensor_manager->GetFrameId(camera_names_[i]);
156 std::shared_ptr<TransformWrapper> trans_wrapper(new TransformWrapper);
157 trans_wrapper->Init(tf2_camera_child_frame_id);
158 camera2world_trans_wrapper_map_[camera_names_[i]] = trans_wrapper;
159
160 if (camera_names_[i] == camera_names_by_descending_focal_len.back()) {
161 image_border_sizes_[camera_names_[i]] = 0;
162 } else {
163 image_border_sizes_[camera_names_[i]] = default_image_border_size_;
164 }
165 }
166
167 // init hdmaps
168 hd_map_ = map::HDMapInput::Instance();
169 if (hd_map_ == nullptr) {
170 AERROR << "PreprocessComponent get hdmap failed.";
171 return cyber::FAIL;
172 }
173
174 if (!hd_map_->Init()) {
175 AERROR << "PreprocessComponent init hd-map failed.";
176 return cyber::FAIL;
177 }
178
179 return cyber::SUCC;
180}
181
182int TrafficLightsPerceptionComponent::InitCameraListeners() {
183 // init camera listeners
184 for (size_t i = 0; i < camera_names_.size(); ++i) {
185 const auto& camera_name = camera_names_[i];
186 const auto& camera_channel_name = input_camera_channel_names_[i];
187 const std::string camera_listener_name = "tl_" + camera_name + "_listener";
188
189 typedef const std::shared_ptr<apollo::drivers::Image> ImageMsgType;
190 std::function<void(const ImageMsgType&)> sub_camera_callback =
191 std::bind(&TrafficLightsPerceptionComponent::OnReceiveImage, this,
192 std::placeholders::_1, camera_name);
193 auto sub_camera_reader =
194 node_->CreateReader(camera_channel_name, sub_camera_callback);
195 last_sub_camera_image_ts_[camera_name] = 0.0;
196 }
197
198 return cyber::SUCC;
199}
200
201int TrafficLightsPerceptionComponent::InitCameraFrame() {
202 data_provider_init_options_.image_height = image_height_;
203 data_provider_init_options_.image_width = image_width_;
204
205 data_provider_init_options_.device_id = gpu_id_;
206 AINFO << "trafficlights data_provider_init_options_.device_id: "
207 << data_provider_init_options_.device_id;
208 data_provider_init_options_.do_undistortion = enable_undistortion_;
209
210 // init data_providers for each camrea
211 for (const auto& camera_name : camera_names_) {
212 data_provider_init_options_.sensor_name = camera_name;
213 std::shared_ptr<camera::DataProvider> data_provider(
214 new camera::DataProvider);
215 if (!data_provider->Init(data_provider_init_options_)) {
216 AERROR << "trafficlights init data_provider failed. "
217 << " camera_name: " << camera_name;
218 return cyber::FAIL;
219 }
220 data_providers_map_[camera_name] = data_provider;
221 }
222
223 return cyber::SUCC;
224}
225
226void TrafficLightsPerceptionComponent::OnReceiveImage(
227 const std::shared_ptr<apollo::drivers::Image> msg,
228 const std::string& camera_name) {
230 std::lock_guard<std::mutex> lck(mutex_);
231 double receive_img_timestamp = Clock::NowInSeconds();
232 double image_msg_ts = msg->measurement_time();
233 image_msg_ts += image_timestamp_offset_;
234 last_sub_camera_image_ts_[camera_name] = image_msg_ts;
235
236 if (!CheckCameraImageStatus(image_msg_ts, check_image_status_interval_thresh_,
237 camera_name)) {
238 AERROR << "CheckCameraImageStatus failed";
239 return;
240 }
241 // trafficlight preprocess msg
242 std::shared_ptr<TrafficDetectMessage> preprocess_message(
243 new (std::nothrow) TrafficDetectMessage);
244 preprocess_message->timestamp_ = image_msg_ts;
245
246 auto& frame = preprocess_message->traffic_light_frame_;
247 frame.reset(new camera::TrafficLightFrame);
248 frame->timestamp = image_msg_ts;
249
250 trafficlight::TLPreprocessorOption preprocess_option;
251 preprocess_option.image_borders_size = &image_border_sizes_;
252
253 // query pose and signals, add cached camera selection by lights' projections
254 if (!UpdateCameraSelection(image_msg_ts, preprocess_option, frame)) {
255 AWARN << "add_cached_camera_selection failed, ts: " << image_msg_ts;
256 }
257
258 // skipping frame according to last proc image timestamp
259 if (last_proc_image_ts_ > 0.0 &&
260 receive_img_timestamp - last_proc_image_ts_ < proc_interval_seconds_) {
261 AINFO << "skip current image, img_ts: " << FORMAT_TIMESTAMP(image_msg_ts)
262 << " , receive_img_timestamp: "
263 << FORMAT_TIMESTAMP(receive_img_timestamp)
264 << " ,_last_proc_image_ts: " << FORMAT_TIMESTAMP(last_proc_image_ts_)
265 << " , _proc_interval_seconds: "
266 << FORMAT_TIMESTAMP(proc_interval_seconds_);
267 return;
268 }
269 // sync image with cached projections
270 bool sync_image_ok =
271 preprocessor_->SyncInformation(image_msg_ts, camera_name);
272
273 if (!sync_image_ok) {
274 AINFO << "PreprocessComponent not publish image, ts:" << image_msg_ts
275 << ", camera_name: " << camera_name;
276 // SendSimulationMsg();
277 return;
278 }
279
280 // Fill camera frame
281 camera::DataProvider::ImageOptions image_options;
282 image_options.target_color = base::Color::RGB;
283 frame->data_provider = data_providers_map_.at(camera_name);
284 frame->data_provider->FillImageData(
285 image_height_, image_width_,
286 reinterpret_cast<const uint8_t*>(msg->data().data()), msg->encoding());
287 frame->timestamp = image_msg_ts;
288 // caros monitor -- image system time diff
289 const auto& diff_image_sys_ts = image_msg_ts - receive_img_timestamp;
290 if (fabs(diff_image_sys_ts) > image_sys_ts_diff_threshold_) {
291 const std::string metric_name = "perception traffic_light exception";
292 const std::string debug_string =
293 absl::StrCat("diff_image_sys_ts:", diff_image_sys_ts,
294 ",camera_id:", camera_name, ",camera_ts:", image_msg_ts);
295 AWARN << "image_ts - system_ts(in seconds): " << diff_image_sys_ts
296 << ". Check if image timestamp drifts."
297 << ", camera_id: " + camera_name
298 << ", debug_string: " << debug_string;
299 }
300
301 if (!VerifyLightsProjection(image_msg_ts, preprocess_option, camera_name,
302 frame, preprocess_message)) {
303 AINFO << "VerifyLightsProjection on image failed, ts: " << image_msg_ts
304 << ", camera_name: " << camera_name
305 << " last_query_tf_ts_: " << last_query_tf_ts_
306 << " need update_camera_selection immediately,"
307 << " reset last_query_tf_ts_ to -1";
308 last_query_tf_ts_ = -1.0;
309 }
310 last_proc_image_ts_ = Clock::NowInSeconds();
311
312 preprocess_message->stoplines_ = stoplines_;
313
314 bool send_message_ret = traffic_detect_writer_->Write(preprocess_message);
315 AINFO << "send out preprocess msg, ts: " << image_msg_ts
316 << "ret: " << send_message_ret;
317}
318
319void TrafficLightsPerceptionComponent::GenerateTrafficLights(
320 const std::vector<apollo::hdmap::Signal>& signals,
321 std::vector<base::TrafficLightPtr>* traffic_lights) {
322 traffic_lights->clear();
323 for (auto signal : signals) {
325 light.reset(new base::TrafficLight);
326 light->id = signal.id().id();
327 for (int i = 0; i < signal.boundary().point_size(); ++i) {
328 base::PointXYZID point;
329 point.x = signal.boundary().point(i).x();
330 point.y = signal.boundary().point(i).y();
331 point.z = signal.boundary().point(i).z();
332 light->region.points.push_back(point);
333 }
334
335 int cur_semantic = 0;
336
337 light->semantic = cur_semantic;
338 traffic_lights->push_back(light);
339 stoplines_ = signal.stop_line();
340 }
341}
342
343bool TrafficLightsPerceptionComponent::QueryPoseAndSignals(
344 const double ts, camera::CarPose* pose,
345 std::vector<apollo::hdmap::Signal>* signals) {
346 // get pose
347 if (!GetCarPose(ts, pose)) {
348 AINFO << "query_pose_and_signals failed to get car pose, ts:" << ts;
349 return false;
350 }
351
352 if (!hd_map_) {
353 AERROR << "hd_map_ not init.";
354 return false;
355 }
356 // get signals
357 Eigen::Vector3d car_position = pose->getCarPosition();
358 if (!hd_map_->GetSignals(car_position, forward_distance_to_query_signals,
359 signals)) {
360 if (ts - last_signals_ts_ < valid_hdmap_interval_) {
361 *signals = last_signals_;
362 AWARN << "query_pose_and_signals failed to get signals info. "
363 << "Now use last info. ts:" << ts << " pose:" << *pose
364 << " signals.size(): " << signals->size();
365 } else {
366 AERROR << "query_pose_and_signals failed to get signals info. "
367 << "ts:" << ts << " pose:" << *pose;
368 }
369 } else {
370 AINFO << "query_pose_and_signals succeeded, signals.size(): "
371 << signals->size();
372 // here need mutex lock_guard, added at the beginning of OnReceiveImage()
373 last_signals_ts_ = ts;
374 last_signals_ = *signals;
375 }
376 return true;
377}
378
379bool TrafficLightsPerceptionComponent::VerifyLightsProjection(
380 const double& ts, const trafficlight::TLPreprocessorOption& option,
381 const std::string& camera_name,
382 std::shared_ptr<camera::TrafficLightFrame> frame,
383 std::shared_ptr<TrafficDetectMessage> msg) {
384 camera::CarPose* pose_ptr = new camera::CarPose();
385 auto& pose = *pose_ptr;
386 std::vector<apollo::hdmap::Signal> signals;
387 if (!QueryPoseAndSignals(ts, pose_ptr, &signals)) {
388 AERROR << "query_pose_and_signals failed, ts: " << ts;
389 return false;
390 }
391 auto& carpose_ptr = msg->carpose_;
392 carpose_ptr.reset(pose_ptr);
393
394 GenerateTrafficLights(signals, &frame->traffic_lights);
395
396 if (!preprocessor_->UpdateLightsProjection(pose, option, camera_name,
397 &frame->traffic_lights)) {
398 AWARN << "verify_lights_projection failed to update_lights_projection, "
399 << " ts: " << ts;
400 return false;
401 }
402
403 AINFO << "VerifyLightsProjection success " << frame->traffic_lights.size();
404
405 return true;
406}
407
408bool TrafficLightsPerceptionComponent::UpdateCameraSelection(
409 double timestamp, const trafficlight::TLPreprocessorOption& option,
410 std::shared_ptr<camera::TrafficLightFrame> frame) {
411 const double current_ts = Clock::NowInSeconds();
412 if (last_query_tf_ts_ > 0.0 &&
413 current_ts - last_query_tf_ts_ < query_tf_interval_seconds_) {
414 AINFO << "skip current tf msg, img_ts: " << FORMAT_TIMESTAMP(timestamp)
415 << " , last_query_tf_ts_: " << FORMAT_TIMESTAMP(last_query_tf_ts_);
416 return true;
417 }
418 AINFO << "start select camera";
419
420 camera::CarPose pose;
421 std::vector<apollo::hdmap::Signal> signals;
422 if (!QueryPoseAndSignals(timestamp, &pose, &signals)) {
423 AINFO << "query_pose_and_signals failed, ts: "
424 << FORMAT_TIMESTAMP(timestamp);
425 return false;
426 }
427 last_query_tf_ts_ = current_ts;
428
429 GenerateTrafficLights(signals, &frame->traffic_lights);
430 AINFO << "hd map signals " << frame->traffic_lights.size();
431
432 if (!preprocessor_->UpdateCameraSelection(pose, option,
433 &frame->traffic_lights)) {
434 AERROR << "add_cached_lights_projections failed, ts: "
435 << FORMAT_TIMESTAMP(timestamp);
436 } else {
437 AINFO << "add_cached_lights_projections succeed, ts: "
438 << FORMAT_TIMESTAMP(timestamp);
439 }
440
441 for (auto& light : frame->traffic_lights) {
442 AINFO << "x " << light->region.projection_roi.x << " y "
443 << light->region.projection_roi.y << " w "
444 << light->region.projection_roi.width << " h "
445 << light->region.projection_roi.height;
446 }
447 return true;
448}
449
450bool TrafficLightsPerceptionComponent::CheckCameraImageStatus(
451 double timestamp, double interval, const std::string& camera_name) {
452 bool camera_ok = true;
453 std::string no_image_camera_names = "";
454 for (const auto& pr : last_sub_camera_image_ts_) {
455 const auto cam_name = pr.first;
456 double last_sub_camera_ts = pr.second;
457 // should be 0.0, change to 1 in case of float precision
458 if (last_sub_camera_ts < 1.0 || timestamp - last_sub_camera_ts > interval) {
459 preprocessor_->SetCameraWorkingFlag(cam_name, false);
460 AWARN << "camera is probably not working"
461 << " , current ts: " << FORMAT_TIMESTAMP(timestamp)
462 << " , last_sub_camera_ts: " << FORMAT_TIMESTAMP(last_sub_camera_ts)
463 << " , camera_name: " << cam_name;
464 camera_ok = false;
465 AINFO << "camera status:" << camera_ok;
466 no_image_camera_names += (" " + cam_name);
467 }
468 }
469
470 bool is_camera_working = false;
471 if (!preprocessor_->GetCameraWorkingFlag(camera_name, &is_camera_working)) {
472 AERROR << "get_camera_is_working_flag ts: " << FORMAT_TIMESTAMP(timestamp)
473 << " camera_name: " << camera_name;
474 return false;
475 }
476
477 if (!is_camera_working) {
478 if (!preprocessor_->SetCameraWorkingFlag(camera_name, true)) {
479 AERROR << "set_camera_is_working_flag ts: " << FORMAT_TIMESTAMP(timestamp)
480 << " camera_name: " << camera_name;
481 return false;
482 }
483 }
484 return true;
485}
486
487bool TrafficLightsPerceptionComponent::GetCarPose(const double timestamp,
488 camera::CarPose* pose) {
489 Eigen::Matrix4d pose_matrix;
490 // get pose car(gps) to world
491 if (!GetPoseFromTF(timestamp, tf2_frame_id_, tf2_child_frame_id_,
492 &pose_matrix)) {
493 AERROR << "get pose from tf failed, child_frame_id: "
494 << tf2_child_frame_id_;
495 return false;
496 }
497 pose->timestamp_ = timestamp;
498 pose->pose_ = pose_matrix;
499
500 int state = 0;
501 bool ret = true;
502 Eigen::Affine3d affine3d_trans;
503 for (const auto& camera_name : camera_names_) {
504 const auto trans_wrapper = camera2world_trans_wrapper_map_[camera_name];
505 ret = trans_wrapper->GetSensor2worldTrans(timestamp, &affine3d_trans);
506 pose_matrix = affine3d_trans.matrix();
507 if (!ret) {
508 pose->ClearCameraPose(camera_name);
509 AERROR << "get pose from tf failed, camera_name: " << camera_name;
510 } else {
511 pose->c2w_poses_[camera_name] = pose_matrix;
512 state += 1;
513 }
514 }
515 return state > 0;
516}
517
518bool TrafficLightsPerceptionComponent::GetPoseFromTF(
519 const double timestamp, const std::string& frame_id,
520 const std::string& child_frame_id, Eigen::Matrix4d* pose_matrix) {
521 apollo::cyber::Time query_time(timestamp);
522 std::string err_string;
523 if (!tf2_buffer_->canTransform(frame_id, child_frame_id, query_time,
524 static_cast<float>(tf2_timeout_second_),
525 &err_string)) {
526 AERROR << "Can not find transform. " << FORMAT_TIMESTAMP(timestamp)
527 << " frame_id: " << frame_id << " child_frame_id: " << child_frame_id
528 << " Error info: " << err_string;
529 return false;
530 }
531 apollo::transform::TransformStamped stamped_transform;
532 try {
533 stamped_transform =
534 tf2_buffer_->lookupTransform(frame_id, child_frame_id, query_time);
535 Eigen::Translation3d translation(
536 stamped_transform.transform().translation().x(),
537 stamped_transform.transform().translation().y(),
538 stamped_transform.transform().translation().z());
539 Eigen::Quaterniond rotation(stamped_transform.transform().rotation().qw(),
540 stamped_transform.transform().rotation().qx(),
541 stamped_transform.transform().rotation().qy(),
542 stamped_transform.transform().rotation().qz());
543 *pose_matrix = (translation * rotation).matrix();
544 ADEBUG << "get pose: " << *pose_matrix;
545 } catch (tf2::TransformException& ex) {
546 AERROR << ex.what();
547 return false;
548 }
549 return true;
550}
551
552} // namespace trafficlight
553} // namespace perception
554} // namespace apollo
Set the behavior of the
a singleton clock that can be used to get the current timestamp.
Definition clock.h:39
static double NowInSeconds()
gets the current time in second.
Definition clock.cc:56
bool GetProtoConfig(T *config) const
std::shared_ptr< Node > node_
Cyber has builtin time type Time.
Definition time.h:31
bool GetSignals(const Eigen::Vector3d &pointd, double forward_distance, std::vector< apollo::hdmap::Signal > *signals)
bool Init() override
Initialize configuration files, algorithm plug-ins, callback functions and create listening channels.
virtual bool canTransform(const std::string &target_frame, const std::string &source_frame, const cyber::Time &target_time, const float timeout_second=0.01f, std::string *errstr=nullptr) const
Test if a transform is possible
Definition buffer.cc:195
virtual TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const cyber::Time &time, const float timeout_second=0.01f) const
Get the transform between two frames by frame ID.
Definition buffer.cc:168
Math-related util functions.
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
#define AWARN
Definition log.h:43
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
std::string frame_id
Point cloud frame id
std::shared_ptr< TrafficLight > TrafficLightPtr
Point< double > PointXYZID
Definition point.h:60
std::shared_ptr< apollo::drivers::Image > ImageMsgType
class register implement
Definition arena_queue.h:37
Definition future.h:29
#define PERF_FUNCTION(...)
Definition profiler.h:54
Some string util functions.
#define FORMAT_TIMESTAMP(timestamp)
Definition string_util.h:29
optional apollo::common::Quaternion rotation
optional apollo::common::Point3D translation