22#include <opencv2/highgui/highgui.hpp>
23#include <opencv2/imgproc/imgproc.hpp>
24#include <opencv2/opencv.hpp>
26#include "modules/perception/traffic_light_tracking/proto/traffic_light_tracking_component.pb.h"
37namespace trafficlight {
39using apollo::perception::onboard::FLAGS_start_visualizer;
52 {cv::Scalar(255, 255, 255),
"UNKNOWN",
"UNKNOWN traffic light"}},
54 {cv::Scalar(0, 0, 255),
"RED",
"RED traffic light"}},
56 {cv::Scalar(0, 255, 0),
"GREEN",
"GREEN traffic light"}},
58 {cv::Scalar(0, 255, 255),
"YELLOW",
"YELLOW traffic light"}}};
63 AERROR <<
"TrafficLightTrackComponent InitConfig failed.";
68 AERROR <<
"TrafficLightTrackComponent InitAlgorithmPlugin failed.";
73 AERROR <<
"TrafficLightTrackComponent InitV2XListener failed.";
81 const std::shared_ptr<TrafficDetectMessage>& message) {
83 auto time_imags = std::to_string(message->timestamp_);
84 AINFO <<
"Enter tracking component, message timestamp: " << time_imags;
86 bool status = InternalProc(message);
91int TrafficLightTrackComponent::InitConfig() {
94 AINFO <<
"load trafficlights tracking component proto param failed";
98 v2x_trafficlights_input_channel_name_ =
102 tl_tracker_name_ = plugin_param.name();
103 config_path_ = plugin_param.config_path();
104 config_file_ = plugin_param.config_file();
105 AINFO <<
"tl_tracker_name: " << tl_tracker_name_
106 <<
" config_path: " << config_path_ <<
" config_file: " << config_file_;
110 v2x_msg_buffer_.set_capacity(max_v2x_msg_buff_size_);
115bool TrafficLightTrackComponent::InitAlgorithmPlugin() {
116 trafficlight::BaseTrafficLightTracker* tracker =
117 trafficlight::BaseTrafficLightTrackerRegisterer::GetInstanceByName(
119 CHECK_NOTNULL(tracker);
120 tracker_.reset(tracker);
121 ACHECK(tracker_ !=
nullptr);
126 if (!tracker_->Init(tracker_init_options_)) {
127 AERROR <<
"Trafficlight tracking init failed";
134int TrafficLightTrackComponent::InitV2XListener() {
135 typedef const std::shared_ptr<apollo::v2x::IntersectionTrafficLightData>
136 V2XTrafficLightsMsgType;
137 std::function<void(
const V2XTrafficLightsMsgType&)> sub_v2x_tl_callback =
138 std::bind(&TrafficLightTrackComponent::OnReceiveV2XMsg,
this,
139 std::placeholders::_1);
140 auto sub_v2x_reader =
node_->CreateReader(
141 v2x_trafficlights_input_channel_name_, sub_v2x_tl_callback);
145bool TrafficLightTrackComponent::InternalProc(
146 const std::shared_ptr<TrafficDetectMessage const>& message) {
148 bool status = tracker_->Track(message->traffic_light_frame_.get());
151 auto frame = message->traffic_light_frame_;
152 AINFO << "Enter SyncV2XTrafficLights founction.";
153 SyncV2XTrafficLights(frame.get());
154 stoplines_ = message->stoplines_;
156 std::shared_ptr<TrafficLightDetection> out_msg(new TrafficLightDetection);
157 auto& camera_name = frame->data_provider->sensor_name();
158 AINFO << "Enter TransformOutputMessage founction.";
159 if (!TransformOutputMessage(frame.get(), camera_name, &out_msg, message)) {
160 AERROR <<
"transform_output_message failed, msg_time: "
161 << message->timestamp_;
166 writer_->Write(out_msg);
167 AINFO <<
"Send trafficlight tracking output message.";
172void TrafficLightTrackComponent::OnReceiveV2XMsg(
173 const std::shared_ptr<apollo::v2x::IntersectionTrafficLightData> v2x_msg) {
174 std::lock_guard<std::mutex> lck(mutex_);
175 v2x_msg_buffer_.push_back(*v2x_msg);
178void TrafficLightTrackComponent::SyncV2XTrafficLights(
179 camera::TrafficLightFrame* frame) {
180 const double camera_frame_timestamp = frame->timestamp;
182 for (
auto itr = v2x_msg_buffer_.rbegin(); itr != v2x_msg_buffer_.rend();
184 double v2x_timestamp = itr->header().timestamp_sec();
186 if (std::fabs(camera_frame_timestamp - v2x_timestamp) <
187 v2x_sync_interval_seconds_) {
188 const int v2x_lights_num =
189 itr->road_traffic_light(0).single_traffic_light_size();
190 const auto& v2x_lights = itr->road_traffic_light(0);
191 for (
int i = 0; i < v2x_lights_num; ++i) {
192 const auto& v2x_light = v2x_lights.single_traffic_light(i);
194 if (light->id != v2x_light.id()) {
199 switch (v2x_light.color()) {
222 AINFO <<
"Sync V2X success. update color from "
223 <<
static_cast<int>(light->status.color) <<
" to "
224 <<
static_cast<int>(v2x_color) <<
"; signal id: " << light->id;
225 light->status.color = v2x_color;
226 light->status.blink = blink;
232 for (
auto& light : frame->traffic_lights) {
233 sync_single_light(light);
237double TrafficLightTrackComponent::stopline_distance(
238 const Eigen::Matrix4d& cam_pose) {
239 if (stoplines_.empty()) {
240 AWARN <<
"compute car to stopline's distance failed(no stopline). "
241 <<
"cam_pose:" << cam_pose;
245 if (stopline.
segment().empty()) {
246 AWARN <<
"compute car to stopline's distance"
247 <<
" failed(stopline has no segment line). "
248 <<
"cam_pose:" << cam_pose
249 <<
" stopline:" << stopline.ShortDebugString();
252 if (!stopline.
segment(0).has_line_segment()) {
253 AWARN <<
"compute car to stopline's distance "
254 <<
"failed(stopline has no segment). "
255 <<
"cam_pose:" << cam_pose
256 <<
" stopline:" << stopline.ShortDebugString();
260 if (stopline.
segment(0).line_segment().point().empty()) {
261 AWARN <<
"compute car to stopline's distance "
262 <<
"failed(stopline has no point). "
263 <<
"cam_pose:" << cam_pose
264 <<
" stopline:" << stopline.ShortDebugString();
268 Eigen::Vector3d stopline_pt(stopline.
segment(0).line_segment().point(0).x(),
269 stopline.
segment(0).line_segment().point(0).y(),
270 stopline.
segment(0).line_segment().point(0).z());
271 Eigen::Vector3d stopline_pt_cam =
272 (cam_pose.inverse() *
273 Eigen::Vector4d(stopline_pt(0), stopline_pt(1), stopline_pt(2), 1.0))
276 return stopline_pt_cam(2);
279bool TrafficLightTrackComponent::TransformOutputMessage(
280 camera::TrafficLightFrame* frame,
const std::string& camera_name,
281 std::shared_ptr<TrafficLightDetection>* out_msg,
282 const std::shared_ptr<TrafficDetectMessage const>& message) {
283 auto& lights = frame->traffic_lights;
284 auto* header = (*out_msg)->mutable_header();
286 header->set_timestamp_sec(publish_time);
292 uint64_t ts_int64 =
static_cast<uint64_t
>(frame->timestamp * 1e9);
293 header->set_camera_timestamp(ts_int64);
295 (*out_msg)->set_camera_name(camera_name);
300 double max_r_conf = 0;
304 double max_g_conf = 0;
308 double max_y_conf = 0;
314 for (
int i = 0; i < static_cast<int>(lights.size()); i++) {
315 switch (lights.at(i)->status.color) {
318 if (std::abs(lights.at(i)->status.confidence) <
319 std::numeric_limits<double>::min()) {
324 cnt_r_ += lights.at(i)->status.confidence;
325 if (lights.at(i)->status.confidence >= max_r_conf) {
327 max_r_conf = lights.at(i)->status.confidence;
332 if (std::abs(lights.at(i)->status.confidence) <
333 std::numeric_limits<double>::min()) {
338 cnt_g_ += lights.at(i)->status.confidence;
339 if (lights.at(i)->status.confidence >= max_g_conf) {
341 max_g_conf = lights.at(i)->status.confidence;
346 if (std::abs(lights.at(i)->status.confidence) <
347 std::numeric_limits<double>::min()) {
352 cnt_y_ += lights.at(i)->status.confidence;
353 if (lights.at(i)->status.confidence >= max_y_conf) {
355 max_y_conf = lights.at(i)->status.confidence;
359 cnt_u_ += lights.at(i)->status.confidence;
368 int max_light_id = -1;
369 if (cnt_r_ >= cnt_g_ && cnt_r_ >= cnt_y_ && cnt_r_ > 0) {
370 max_light_id = max_r_id;
371 }
else if (cnt_y_ > cnt_r_ && cnt_y_ >= cnt_g_) {
372 max_light_id = max_y_id;
373 }
else if (cnt_g_ > cnt_r_ && cnt_g_ > cnt_y_) {
374 max_light_id = max_g_id;
375 }
else if (cnt_r_ == 0 && cnt_g_ == 0 && cnt_y_ == 0) {
376 max_light_id = max_n_id;
380 if (max_light_id > 0) {
381 std::swap(lights[0], lights[max_light_id]);
384 if (max_light_id >= 0) {
385 for (
size_t i = 0; i < lights.size(); i++) {
387 (*out_msg)->add_traffic_light();
388 light_result->set_id(lights.at(i)->id);
389 light_result->set_confidence(lights.at(0)->status.confidence);
390 light_result->set_color(
391 static_cast<apollo::perception::TrafficLight_Color
>(
392 lights.at(0)->status.color));
393 light_result->set_blink(lights.at(0)->status.blink);
396 (*out_msg)->set_contain_lights(lights.size() > 0);
397 detected_trafficlight_color_ = lights.at(0)->status.color;
400 AINFO <<
"Enter TransformDebugMessage founction.";
402 if (!TransformDebugMessage(frame, out_msg, message)) {
403 AERROR <<
"ProcComponent::Proc failed to transform debug msg.";
410bool TrafficLightTrackComponent::TransformDebugMessage(
411 const camera::TrafficLightFrame* frame,
412 std::shared_ptr<apollo::perception::TrafficLightDetection>* out_msg,
413 const std::shared_ptr<TrafficDetectMessage const>& in_message) {
414 const auto& lights = frame->traffic_lights;
416 TrafficLightDebug* light_debug = (*out_msg)->mutable_traffic_light_debug();
419 light_debug->set_signal_num(
static_cast<int>(lights.size()));
421 if (!lights.empty() && !lights[0]->region.debug_roi.empty()) {
422 const auto& debug_roi = lights[0]->region.debug_roi;
424 TransRect2Box(debug_roi[0], light_debug->mutable_cropbox());
427 for (
auto iter = debug_roi.begin() + 1; iter != debug_roi.end(); ++iter) {
428 TransRect2Box(*iter, light_debug->add_box());
429 TransRect2Box(*iter, light_debug->add_debug_roi());
433 for (
const auto& light : lights) {
435 auto* box = light_debug->add_box();
436 TransRect2Box(light->region.detection_roi, box);
437 box->set_color(
static_cast<TrafficLight_Color
>(light->status.color));
438 box->set_selected(
true);
441 TransRect2Box(light->region.projection_roi, light_debug->add_box());
442 TransRect2Box(light->region.projection_roi,
443 light_debug->add_projected_roi());
446 TransRect2Box(light->region.debug_roi[0], light_debug->add_crop_roi());
449 auto* rectified_roi = light_debug->add_rectified_roi();
450 TransRect2Box(light->region.detection_roi, rectified_roi);
451 rectified_roi->set_color(
452 static_cast<TrafficLight_Color
>(light->status.color));
453 rectified_roi->set_selected(
true);
456 if (lights.size() > 0) {
457 auto& pose_ptr = in_message->carpose_;
458 Eigen::Matrix4d cam_pose;
459 auto& camera_name = frame->data_provider->sensor_name();
460 cam_pose = pose_ptr->c2w_poses_.at(camera_name);
461 light_debug->set_distance_to_stop_line(stopline_distance(cam_pose));
464 if (FLAGS_start_visualizer) {
465 Visualize(*frame, lights);
471void TrafficLightTrackComponent::TransRect2Box(
475 box->set_width(rect.width);
476 box->set_height(rect.height);
479void TrafficLightTrackComponent::Visualize(
480 const camera::TrafficLightFrame& frame,
481 const std::vector<base::TrafficLightPtr>& lights)
const {
483 std::string tl_string;
486 if (lights.empty()) {
489 cv::Mat output_image(image_height_, image_width_, CV_8UC3,
490 cv::Scalar(0, 0, 0));
492 camera::DataProvider::ImageOptions image_options;
494 frame.data_provider->GetImage(image_options, &out_image);
495 memcpy(output_image.data, out_image.cpu_data(),
496 out_image.total() *
sizeof(uint8_t));
498 for (
const auto& light : lights) {
500 const auto& crop_roi = light->region.debug_roi[0];
501 const cv::Rect rect_crop(crop_roi.x, crop_roi.y, crop_roi.width,
503 if (light == lights[0])
504 cv::rectangle(output_image, rect_crop, cv::Scalar(255, 255, 255), 2);
506 cv::rectangle(output_image, rect_crop, cv::Scalar(255, 255, 255));
509 const auto& projection_roi = light->region.projection_roi;
510 const cv::Rect projection_rect(projection_roi.x, projection_roi.y,
511 projection_roi.width, projection_roi.height);
512 cv::rectangle(output_image, projection_rect, cv::Scalar(255, 0, 0), 3);
515 const auto& rectified_roi = light->region.detection_roi;
516 const cv::Rect rectified_rect(rectified_roi.x, rectified_roi.y,
517 rectified_roi.width, rectified_roi.height);
519 std::map<base::TLColor, TLInfo>::iterator itor =
522 tl_color = itor->second.tl_color_;
523 tl_string = itor->second.tl_string_;
525 tl_color = cv::Scalar(255, 255, 255);
526 tl_string =
"UNKNOWN";
528 snprintf(str,
sizeof(str),
"ID:%s C:%.3lf", light->id.c_str(),
529 light->status.confidence);
530 cv::rectangle(output_image, rectified_rect, tl_color, 2);
531 cv::putText(output_image, str,
532 cv::Point(rectified_roi.x + 30,
533 rectified_roi.y + rectified_roi.height + 30),
534 cv::FONT_HERSHEY_DUPLEX, 1.0, tl_color, 2);
538 std::map<base::TLColor, TLInfo>::iterator itor =
539 s_tl_infos.find(detected_trafficlight_color_);
541 tl_color = itor->second.tl_color_;
542 tl_string = itor->second.tl_string_ex_;
544 tl_color = cv::Scalar(255, 255, 255);
545 tl_string =
"UNKNOWN traffic light";
547 double all = cnt_r_ + cnt_g_ + cnt_y_ + cnt_u_;
551 cv::putText(output_image, tl_string, cv::Point(10, 90),
552 cv::FONT_HERSHEY_DUPLEX, 2.0, tl_color, 3);
554 snprintf(str,
sizeof(str),
"Red lights:%.2f", cnt_r_ / all);
555 cv::putText(output_image, str, cv::Point(10, 150), cv::FONT_HERSHEY_DUPLEX,
556 1.5, cv::Scalar(0, 0, 255), 3);
557 snprintf(str,
sizeof(str),
"Green lights:%.2f", cnt_g_ / all);
558 cv::putText(output_image, str, cv::Point(10, 200), cv::FONT_HERSHEY_DUPLEX,
559 1.5, cv::Scalar(0, 255, 0), 3);
560 snprintf(str,
sizeof(str),
"Yellow lights:%.2f", cnt_y_ / all);
561 cv::putText(output_image, str, cv::Point(10, 250), cv::FONT_HERSHEY_DUPLEX,
562 1.5, cv::Scalar(0, 255, 255), 3);
563 snprintf(str,
sizeof(str),
"Unknown lights:%.2f", cnt_u_ / all);
564 cv::putText(output_image, str, cv::Point(10, 300), cv::FONT_HERSHEY_DUPLEX,
565 1.5, cv::Scalar(255, 255, 255), 3);
567 std::string folder =
"/apollo/data/debug_vis/";
569 AINFO <<
"EnsureDirectory folder " << folder <<
" error.";
571 cv::resize(output_image, output_image, cv::Size(), 0.5, 0.5);
572 cv::imwrite(absl::StrCat(folder, std::to_string(frame.timestamp),
".jpg"),
a singleton clock that can be used to get the current timestamp.
static double NowInSeconds()
gets the current time in second.
bool GetProtoConfig(T *config) const
std::shared_ptr< Node > node_
std::string tl_string_ex_
bool Proc(const std::shared_ptr< TrafficDetectMessage > &message) override
bool EnsureDirectory(const std::string &directory_path)
Check if a specified directory specified by directory_path exists.
std::shared_ptr< TrafficLight > TrafficLightPtr
std::map< base::TLColor, TLInfo > s_tl_infos
#define PERF_FUNCTION(...)
repeated CurveSegment segment
optional string v2x_trafficlights_input_channel_name
optional string traffic_light_output_channel_name
optional perception::PluginParam plugin_param