28#include <boost/bind.hpp>
29#include <boost/function.hpp>
30#include <opencv2/opencv.hpp>
40#include "opencv2/opencv.hpp"
44namespace trafficlight {
46void TrafficLightTLDetectorYolox::AddShapeYolox(
47 std::map<std::string, std::vector<int>>* shape_map,
48 const google::protobuf::RepeatedPtrField<common::ModelBlob>& model_blobs) {
49 for (
const auto& blob : model_blobs) {
50 std::vector<int> shape(blob.shape().begin(), blob.shape().end());
51 shape_map->insert(std::make_pair(blob.name(), shape));
58 AERROR <<
"Read proto_config failed! " << config_file;
62 AINFO <<
"Traffic light detection param: " << detection_param_.DebugString();
64 const auto& model_info = detection_param_.
info();
65 std::string model_path =
GetModelPath(model_info.name());
66 AINFO <<
"Traffic light detection model_path: " << model_path;
68 std::string proto_file =
GetModelFile(model_path, model_info.proto_file().file());
69 AINFO <<
"Traffic light detection proto_file: " << proto_file;
71 std::string weight_file =
GetModelFile(model_path, model_info.weight_file().file());
72 AINFO <<
"Traffic light detection weight_file: " << weight_file;
75 BASE_GPU_CHECK(cudaSetDevice(gpu_id_));
82 const auto& framework = model_info.framework();
83 AINFO <<
"framework: " << framework;
85 std::string plugin_name = model_info.infer_plugin();
86 static const std::string class_namespace =
"apollo::perception::inference::";
87 if (model_info.has_infer_plugin() && !plugin_name.empty()) {
88 plugin_name = class_namespace + plugin_name;
91 detect_net_->set_model_info(proto_file, input_names_, output_names_);
92 AINFO <<
"trafficlight detect_net_ load plugin success: " << plugin_name;
95 framework, proto_file, weight_file, output_names_, input_names_, model_path));
98 ACHECK(detect_net_.get() !=
nullptr) <<
"Failed to init trafficlight yolox inference instance";
103 cls_th_ = detection_param_.
cls_th();
107 CHECK_GT(resize_height, 0);
108 CHECK_GT(resize_width, 0);
112 AINFO <<
"TrafficLightTLDetectorYolox net input base blobs: "
114 input_names_.begin(),
117 [](std::string& sum,
const std::string& s) { return sum +
" " + s; });
119 AINFO <<
"TrafficLightTLDetectorYolox net output base blobs: "
121 output_names_.begin(),
124 [](std::string& sum,
const std::string& s) { return sum +
" " + s; });
126 detect_net_->set_gpu_id(options.
gpu_id);
127 detect_net_->set_max_batch_size(max_batch_size_ * 2);
129 std::map<std::string, std::vector<int>> shape_map;
130 AddShapeYolox(&shape_map, model_info.inputs());
131 AddShapeYolox(&shape_map, model_info.outputs());
133 if (!detect_net_->Init(shape_map)) {
134 AERROR << model_info.name() <<
"init failed!";
148 select_.
Init(resize_width, resize_height);
154 DetectHeadByModel(frame);
165 detected_bboxes_.clear();
166 detected_heads_.clear();
167 bbox_project_camera_.clear();
169 pad_resize_params_.clear();
170 detected_light_ids_.clear();
174 AINFO <<
"no hdmap lights to detect";
177 if (cudaSetDevice(gpu_id_) != cudaSuccess) {
178 AERROR <<
"Failed To Set Device To: " << gpu_id_;
183 std::vector<base::TrafficLightPtr> lights_ref = frame->
traffic_lights;
184 AINFO <<
"detect lights num: " << lights_ref.size() <<
" lights";
187 int batch_num = (
static_cast<int>(lights_ref.size()) + max_batch_size_ - 1) / max_batch_size_;
188 auto input_image_blob = detect_net_->get_blob(input_names_[0]);
189 auto output_loc_blob = detect_net_->get_blob(output_names_[0]);
190 auto output_conf_blob = detect_net_->get_blob(output_names_[1]);
191 auto output_cls_blob = detect_net_->get_blob(output_names_[2]);
194 const int& provider_img_width = data_provider->src_width();
195 const int& provider_img_height = data_provider->src_height();
197 for (
auto& light : lights_ref) {
199 light->region.detection_roi = light->region.projection_roi;
200 light->region.debug_roi.clear();
201 light->region.debug_roi_detect_scores.clear();
202 light->region.debug_roi.push_back(debug_rect);
203 light->region.debug_roi_detect_scores.push_back(0.0f);
206 for (
auto& light : lights_ref) {
207 if (light->region.outside_image
209 || light->region.projection_roi.Area() <= 0) {
210 light->region.projection_roi.x = 0;
211 light->region.projection_roi.y = 0;
212 light->region.projection_roi.width = 0;
213 light->region.projection_roi.height = 0;
216 AINFO <<
"Crop Box Detection";
218 for (
int batch_id = 0; batch_id < batch_num; batch_id++) {
220 int batch_begin = batch_id * max_batch_size_;
221 int batch_end = (batch_id + 1) * max_batch_size_ <
static_cast<int>(lights_ref.size())
222 ? (batch_id + 1) * max_batch_size_
223 :
static_cast<int>(lights_ref.size());
225 int batch_size = batch_end - batch_begin;
226 int resize_index = 0;
229 input_image_blob->Reshape(batch_size, 3, resize_height_, resize_width_);
230 int box_num = output_loc_blob->shape(1);
231 output_loc_blob->Reshape({batch_size, box_num, 4});
232 output_conf_blob->Reshape({batch_size, box_num});
233 output_cls_blob->Reshape({batch_size, box_num});
236 bbox_project_camera_.reserve(batch_size);
237 pad_resize_params_.reserve(batch_size);
238 detected_light_ids_.reserve(batch_size);
241 for (
int light_id = batch_begin; light_id < batch_end; ++light_id) {
242 auto& light_hdmap = lights_ref[light_id];
244 detected_light_ids_.push_back(light_hdmap->id);
247 const int& img_width = data_provider->src_width();
248 const int& img_height = data_provider->src_height();
250 crop_->getCropBox(img_width, img_height, light_hdmap, &cbox);
251 AINFO <<
"get crop box success " << cbox.x <<
" " << cbox.y <<
" " << cbox.width <<
" " << cbox.height
252 <<
" light id: " << light_hdmap->id;
253 if (cbox.width == 0 && cbox.height == 0) {
257 light_hdmap->region.debug_roi[0] = cbox;
258 light_hdmap->region.crop_roi = cbox;
260 data_provider_image_option_.
crop_roi = cbox;
261 data_provider_image_option_.
do_crop =
true;
264 data_provider->GetImage(data_provider_image_option_, &image);
278 int crop_roi_width = light_hdmap->region.crop_roi.width;
279 int crop_roi_height = light_hdmap->region.crop_roi.height;
287 if (crop_roi_width > crop_roi_height) {
289 bottom_pad = crop_roi_width - crop_roi_height;
290 }
else if (crop_roi_height > crop_roi_width) {
292 right_pad = crop_roi_height - crop_roi_width;
295 int dst_height = crop_roi_height + top_pad + bottom_pad;
296 int dst_width = crop_roi_width + left_pad + right_pad;
299 base::Image8U tmp_image = padding_image_container_(
base::RectI(0, 0, dst_width, dst_height));
301 float scale = resize_width_ * 1.0 / dst_width;
307 data_provider->src_width(),
308 data_provider->src_height(),
310 pad_resize_params_.push_back(prp);
313 image, &tmp_image, img_width, left_pad, right_pad, top_pad, bottom_pad, 114, stream_,
true);
317 inference::ResizeGPU(tmp_image, input_image_blob, dst_width, resize_index, 0, 0, 0,
false, 1.0);
322 AINFO <<
"infer start";
323 PERF_BLOCK(
"traffic_light_detection_inference")
324 cudaDeviceSynchronize();
325 detect_net_->Infer();
326 cudaDeviceSynchronize();
328 AINFO << "infer end";
331 GetCandidateHeads(batch_id, &detected_bboxes_, lights_ref);
332 AINFO << "detected_bboxes_GetCandidateHeads";
333 AINFO << detected_bboxes_.size();
336 auto& camera_name = frame->data_provider->sensor_name();
337 NMS(&detected_bboxes_, camera_name);
338 AINFO << "Dump output done! Get Box Num: " << detected_bboxes_.size();
340 for (
size_t j = 0; j < detected_bboxes_.size(); ++j) {
341 base::RectI& region = detected_bboxes_[j]->region.detection_roi;
342 float score = detected_bboxes_[j]->region.detect_score;
343 lights_ref[0]->region.debug_roi.push_back(region);
344 lights_ref[0]->region.debug_roi_detect_scores.push_back(score);
347 AINFO <<
"start select";
349 AINFO <<
"select success";
353bool TrafficLightTLDetectorYolox::GetCandidateHeads(
355 std::vector<base::TrafficLightPtr>* lights,
356 std::vector<base::TrafficLightPtr>& lights_ref) {
357 auto output_loc_blob = detect_net_->get_blob(output_names_[0]);
358 auto output_conf_blob = detect_net_->get_blob(output_names_[1]);
359 auto output_cls_blob = detect_net_->get_blob(output_names_[2]);
361 int batch_size = output_loc_blob->shape()[0];
362 int anchor_num = output_cls_blob->shape()[1];
364 auto conf_data_cpu = output_conf_blob->cpu_data();
365 auto bbx_data_cpu = output_loc_blob->cpu_data();
366 auto cls_data_cpu =
reinterpret_cast<const int*
>(output_cls_blob->cpu_data());
368 const int bbox_dims = 4;
370 for (
int i = 0; i < batch_size; i++) {
371 auto conf = conf_data_cpu + i * anchor_num;
372 for (
int j = 0; j < anchor_num; j++) {
374 if (conf[j] >= cls_th_) {
381 int light_idx = batch_id * max_batch_size_ + i;
387 PadResizeParam prp = pad_resize_params_[light_idx];
389 float x = bbx_data_cpu[i * anchor_num * bbox_dims + j * bbox_dims];
390 float y = bbx_data_cpu[i * anchor_num * bbox_dims + j * bbox_dims + 1];
391 float w = bbx_data_cpu[i * anchor_num * bbox_dims + j * bbox_dims + 2];
392 float h = bbx_data_cpu[i * anchor_num * bbox_dims + j * bbox_dims + 3];
394 double head_area = (w / prp.scale) * (h / prp.scale);
396 if (head_area < min_head_area_) {
397 AINFO <<
"filter small roi: " << head_area;
402 int shape_idx = i * anchor_num + j;
407 tmp->region.detection_roi.width =
static_cast<int>(w / prp.scale);
408 tmp->region.detection_roi.height =
static_cast<int>(h / prp.scale);
409 tmp->region.detection_roi.x =
static_cast<int>(
410 x / prp.scale - prp.left_pad + lights_ref[light_idx]->region.crop_roi.x
411 - tmp->region.detection_roi.width / 2.);
412 tmp->region.detection_roi.y =
static_cast<int>(
413 y / prp.scale - prp.top_pad + lights_ref[light_idx]->region.crop_roi.y
414 - tmp->region.detection_roi.height / 2.);
415 tmp->region.detect_score = conf[j];
416 tmp->region.is_detected =
true;
417 tmp->id = detected_light_ids_[light_idx];
420 || tmp->region.detection_roi.Area() <= 0) {
421 AINFO <<
"Invalid width or height or x or y: " << tmp->region.detection_roi.width <<
" | "
422 << tmp->region.detection_roi.height <<
" | " << tmp->region.detection_roi.x <<
" | "
423 << tmp->region.detection_roi.y;
427 camera::RefineBox(tmp->region.detection_roi, prp.roi_width, prp.roi_height, &(tmp->region.detection_roi));
429 AINFO <<
"push lights: " << tmp->region.detection_roi.x <<
" " << tmp->region.detection_roi.y <<
" "
430 << tmp->region.detection_roi.width <<
" " << tmp->region.detection_roi.height <<
" "
431 << tmp->region.detect_score;
432 lights->push_back(tmp);
439void TrafficLightTLDetectorYolox::NMS(std::vector<base::TrafficLightPtr>* lights,
const std::string camera_name) {
441 for (
size_t i = 0; i < lights->size(); i++) {
443 const std::string& light_project_camera = camera_name;
444 detected_heads_[light_project_camera].push_back(light);
448 for (
auto& lights_each_camera : detected_heads_) {
449 std::vector<base::TrafficLightPtr> lights_for_each_camera = lights_each_camera.second;
450 ApplyOverlapNMS(&lights_for_each_camera);
451 ApplyNMS(&lights_for_each_camera);
452 for (
auto light : lights_for_each_camera) {
453 (*lights).push_back(light);
455 AINFO <<
"nms light: " << light->region.detection_roi.x <<
" " << light->region.detection_roi.y <<
" "
456 << light->region.detection_roi.width <<
" " << light->region.detection_roi.height <<
" "
457 << light->region.detect_score;
462void TrafficLightTLDetectorYolox::ApplyOverlapNMS(std::vector<base::TrafficLightPtr>* lights) {
465 std::vector<std::pair<int, int>> score_index_vec(lights->size());
466 for (
size_t i = 0; i < lights->size(); i++) {
467 score_index_vec[i].first
468 = lights->at(i)->region.detection_roi.width * lights->at(i)->region.detection_roi.height;
469 score_index_vec[i].second = i;
472 score_index_vec.begin(),
473 score_index_vec.end(),
474 [](
const std::pair<int, int>& pr1,
const std::pair<int, int>& pr2) { return pr1.first < pr2.first; });
476 std::vector<int> kept_indices;
477 while (score_index_vec.size()) {
478 const int& idx = score_index_vec.back().second;
480 for (
size_t k = 0; k < kept_indices.size(); k++) {
481 const int& kept_idx = kept_indices[k];
482 const auto& rect1 = lights->at(idx)->region.detection_roi;
483 const auto& rect2 = lights->at(kept_idx)->region.detection_roi;
484 float overlap =
static_cast<float>((rect1 & rect2).Area()) / rect1.Area();
486 keep = std::fabs(overlap) < 0.7;
492 kept_indices.push_back(idx);
494 score_index_vec.pop_back();
497 auto parted_itr = std::stable_partition(lights->begin(), lights->end(), [&](
const base::TrafficLightPtr& light) {
498 return std::find(kept_indices.begin(), kept_indices.end(), idx++) != kept_indices.end();
500 lights->erase(parted_itr, lights->end());
503void TrafficLightTLDetectorYolox::ApplyNMS(std::vector<base::TrafficLightPtr>* lights) {
505 std::vector<std::pair<float, int>> score_index_vec(lights->size());
506 for (
size_t i = 0; i < lights->size(); ++i) {
507 score_index_vec[i].first = lights->at(i)->region.detect_score;
508 score_index_vec[i].second = i;
511 score_index_vec.begin(),
512 score_index_vec.end(),
513 [](
const std::pair<float, int>& pr1,
const std::pair<float, int>& pr2) { return pr1.first < pr2.first; });
515 std::vector<int> kept_indices;
516 while (score_index_vec.size() != 0) {
517 const int idx = score_index_vec.back().second;
519 for (
size_t k = 0; k < kept_indices.size(); ++k) {
520 const int kept_idx = kept_indices[k];
521 const auto& rect1 = lights->at(idx)->region.detection_roi;
522 const auto& rect2 = lights->at(kept_idx)->region.detection_roi;
523 float overlap =
static_cast<float>((rect1 & rect2).Area()) / (rect1 | rect2).Area();
527 keep = std::fabs(overlap) < 0.7;
533 kept_indices.push_back(idx);
535 score_index_vec.pop_back();
539 auto parted_itr = std::stable_partition(lights->begin(), lights->end(), [&](
const base::TrafficLightPtr& light) {
540 return std::find(kept_indices.begin(), kept_indices.end(), idx++) != kept_indices.end();
542 lights->erase(parted_itr, lights->end());
#define REGISTER_TRAFFIC_LIGHT_DETECTOR(name)
static PluginManager * Instance()
get singleton instance of PluginManager
std::shared_ptr< Base > CreateInstance(const std::string &derived_class)
create plugin instance of derived class based on Base
A wrapper around Blob holders serving as the basic computational unit for images.
void SelectTrafficLights(const std::vector< base::TrafficLightPtr > &refined_bboxes, std::vector< base::TrafficLightPtr > *hdmap_bboxes)
Choose traffic lights using Gaussian calculation scores.
bool Init(int rows, int cols)
Initialize select object parameters.
bool Detect(camera::TrafficLightFrame *frame) override
Detect traffic light from image.
bool Init(const TrafficLightDetectorInitOptions &options) override
Initialize traffic light detector parameters.
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,...
std::shared_ptr< TrafficLight > TrafficLightPtr
bool OutOfValidRegion(const base::BBox2D< T > box, const T width, const T height, const T border_size=0)
void RefineBox(const base::Rect< T > &box_in, const T width, const T height, base::Rect< T > *box_out)
std::vector< std::string > GetBlobNames(const google::protobuf::RepeatedPtrField< common::ModelBlob > &model_blobs)
bool ImageZeroPadding(const base::Image8U &src, base::Image8U *dst, int stepwidth, int left_pad, int right_pad, int top_pad, int bottom_pad, int value, cudaStream_t stream, bool same_order)
Inference * CreateInferenceByName(const std::string &frame_work, const std::string &proto_file, const std::string &weight_file, const std::vector< std::string > &outputs, const std::vector< std::string > &inputs, const std::string &model_root)
bool ResizeGPU(const base::Image8U &src, std::shared_ptr< apollo::perception::base::Blob< float > > dst, int stepwidth, int start_axis)
std::string GetModelFile(const std::string &model_name, const std::string &file_name)
Get the model file path by model path and file name
std::string GetConfigFile(const std::string &config_path, const std::string &config_file)
std::string GetModelPath(const std::string &model_name)
Get the model path by model name, search from APOLLO_MODEL_PATH
std::vector< base::TrafficLightPtr > traffic_lights
std::shared_ptr< camera::DataProvider > data_provider
optional int32 max_batch_size
optional int32 resize_image_hight
optional common::ModelInfo info
optional float crop_scale
optional int32 min_crop_size
optional int32 resize_image_width
optional int32 crop_method