Apollo 11.0
自动驾驶开放平台
detection.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 <utility>
20
21#include "cyber/common/file.h"
22#include "cyber/common/log.h"
30
31namespace apollo {
32namespace perception {
33namespace trafficlight {
34
36 max_batch_size_(4), param_blob_length_(6), mean_{0, 0, 0}, gpu_id_(0) {}
37
39 std::string config_file = GetConfigFile(options.config_path, options.config_file);
40
41 if (!cyber::common::GetProtoFromFile(config_file, &detection_param_)) {
42 AERROR << "Failed to load traffic light detection parameters: " << config_file;
43 return false;
44 }
45
46 AINFO << "Traffic light detection param: " << detection_param_.DebugString();
47
48 const auto &model_info = detection_param_.info();
49 std::string model_path = GetModelPath(model_info.name());
50 AINFO << "Traffic light detection model_path: " << model_path;
51
52 std::string proto_file = GetModelFile(model_path, model_info.proto_file().file());
53 AINFO << "Traffic light detection proto_file: " << proto_file;
54
55 std::string weight_file = GetModelFile(model_path, model_info.weight_file().file());
56 AINFO << "Traffic light detection weight_file: " << weight_file;
57
58 if (detection_param_.is_bgr()) {
59 data_provider_image_option_.target_color = base::Color::BGR;
60 mean_[0] = detection_param_.mean_b();
61 mean_[1] = detection_param_.mean_g();
62 mean_[2] = detection_param_.mean_r();
63 } else {
64 data_provider_image_option_.target_color = base::Color::RGB;
65 mean_[0] = detection_param_.mean_r();
66 mean_[1] = detection_param_.mean_g();
67 mean_[2] = detection_param_.mean_b();
68 }
69
70 // Network input and output names
71 net_inputs_ = inference::GetBlobNames(model_info.inputs());
72 net_outputs_ = inference::GetBlobNames(model_info.outputs());
73
74 const auto &model_type = model_info.framework();
75 AINFO << "model_type: " << model_type;
76
78 model_type, proto_file, weight_file, net_outputs_, net_inputs_, model_path));
79
80 AINFO << "rt_net_ create succeed";
81 rt_net_->set_gpu_id(options.gpu_id);
82 AINFO << "set gpu id " << options.gpu_id;
83 gpu_id_ = options.gpu_id;
84
85 int resize_height = detection_param_.min_crop_size();
86 int resize_width = detection_param_.min_crop_size();
87 max_batch_size_ = detection_param_.max_batch_size();
88 param_blob_length_ = 6;
89
90 CHECK_GT(resize_height, 0);
91 CHECK_GT(resize_width, 0);
92 CHECK_GT(max_batch_size_, 0);
93
94 std::map<std::string, std::vector<int>> input_reshape;
95 inference::AddShape(&input_reshape, model_info.inputs());
96
97 if (!rt_net_->Init(input_reshape)) {
98 AINFO << "net init fail.";
99 return false;
100 }
101 AINFO << "net init success.";
102
103 mean_buffer_.reset(new base::Blob<float>(1, resize_height, resize_height, 3));
104
105 param_blob_ = rt_net_->get_blob(net_inputs_[1]);
106 float *param_data = param_blob_->mutable_cpu_data();
107 for (int i = 0; i < max_batch_size_; ++i) {
108 auto offset = i * param_blob_length_;
109 param_data[offset + 0] = static_cast<float>(resize_width);
110 param_data[offset + 1] = static_cast<float>(resize_height);
111 param_data[offset + 2] = 1;
112 param_data[offset + 3] = 1;
113 param_data[offset + 4] = 0;
114 param_data[offset + 5] = 0;
115 }
116
117 switch (detection_param_.crop_method()) {
118 default:
119 case 0:
120 crop_.reset(new CropBox(detection_param_.crop_scale(), detection_param_.min_crop_size()));
121 break;
122 case 1:
123 crop_.reset(new CropBoxWholeImage());
124 break;
125 }
126
127 select_.Init(resize_width, resize_height);
128 image_.reset(new base::Image8U(resize_height, resize_width, base::Color::BGR));
129 return true;
130}
131
132// TODO(chenjiahao): temporarily do inference serially for multiple
133// traffic lights, because so far batch size can only be 1
134bool TrafficLightDetection::Inference(std::vector<base::TrafficLightPtr> *lights, camera::DataProvider *data_provider) {
135 if (cudaSetDevice(gpu_id_) != cudaSuccess) {
136 AERROR << "Failed to set device to " << gpu_id_;
137 return false;
138 }
139 auto batch_num = lights->size();
140 for (size_t i = 0; i < batch_num; ++i) {
141 crop_box_list_.clear();
142 resize_scale_list_.clear();
143 int img_width = data_provider->src_width();
144 int img_height = data_provider->src_height();
145 int resize_index = 0;
146 auto input_img_blob = rt_net_->get_blob(net_inputs_[0]);
147 auto input_param = rt_net_->get_blob(net_inputs_[1]);
148
149 input_img_blob->Reshape(
150 1,
151 static_cast<int>(detection_param_.min_crop_size()),
152 static_cast<int>(detection_param_.min_crop_size()),
153 3);
154 param_blob_->Reshape(1, 6, 1, 1);
155 float *param_data = param_blob_->mutable_cpu_data();
156 param_data[0] = static_cast<float>(detection_param_.min_crop_size());
157 param_data[1] = static_cast<float>(detection_param_.min_crop_size());
158 param_data[2] = 1;
159 param_data[3] = 1;
160 param_data[4] = 0;
161 param_data[5] = 0;
162
163 AINFO << "reshape inputblob " << input_img_blob->shape_string();
164
165 base::TrafficLightPtr light = lights->at(i);
166 base::RectI cbox;
167 crop_->getCropBox(img_width, img_height, light, &cbox);
168 AINFO << "get crop box success " << cbox.x << " " << cbox.y << " " << cbox.width << " " << cbox.height;
169
170 if (!camera::OutOfValidRegion(cbox, img_width, img_height) && cbox.Area() > 0) {
171 crop_box_list_.push_back(cbox);
172 light->region.debug_roi[0] = cbox;
173 light->region.crop_roi = cbox;
174
175 data_provider_image_option_.do_crop = true;
176 data_provider_image_option_.crop_roi = cbox;
177 data_provider_image_option_.target_color = base::Color::BGR;
178 data_provider->GetImage(data_provider_image_option_, image_.get());
179 AINFO << "get image data success ";
180
181 float resize_scale = static_cast<float>(detection_param_.min_crop_size())
182 / static_cast<float>(std::min(cbox.width, cbox.height));
183 resize_scale_list_.push_back(resize_scale);
184
186 *image_, input_img_blob, img_width, resize_index, mean_[0], mean_[1], mean_[2], true, 1.0);
187 resize_index++;
188 }
189
190 // inference
191 PERF_BLOCK("traffic_light_detection_inference")
192 cudaDeviceSynchronize();
193 rt_net_->Infer();
194 cudaDeviceSynchronize();
196 AINFO << "rt_net run success";
197
198 // dump the output
199 SelectOutputBoxes(crop_box_list_, resize_scale_list_, resize_scale_list_, &detected_bboxes_);
200 }
201
202 ApplyNMS(&detected_bboxes_);
203
204 return true;
205}
206
208 if (frame->traffic_lights.empty()) {
209 AINFO << "no lights to detect";
210 return true;
211 }
212
213 const auto &data_provider = frame->data_provider.get();
214 auto input_blob = rt_net_->get_blob(net_inputs_[0]);
215 int img_width = data_provider->src_width();
216 int img_height = data_provider->src_height();
217 std::vector<base::TrafficLightPtr> &lights_ref = frame->traffic_lights;
218
219 AINFO << "detection input " << lights_ref.size() << " lights";
220
221 selected_bboxes_.clear();
222 detected_bboxes_.clear();
223
224 for (auto &light : lights_ref) {
225 base::RectI debug_rect(0, 0, 0, 0);
226 light->region.detection_roi = light->region.projection_roi;
227 light->region.debug_roi.clear();
228 light->region.debug_roi_detect_scores.clear();
229 light->region.debug_roi.push_back(debug_rect);
230 light->region.debug_roi_detect_scores.push_back(0.0f);
231 }
232
233 for (auto &light : lights_ref) {
234 if (light->region.outside_image || camera::OutOfValidRegion(light->region.projection_roi, img_width, img_height)
235 || light->region.projection_roi.Area() <= 0) {
236 light->region.projection_roi.x = 0;
237 light->region.projection_roi.y = 0;
238 light->region.projection_roi.width = 0;
239 light->region.projection_roi.height = 0;
240 }
241 }
242
243 PERF_BLOCK("traffic_light_detector_inference")
244 Inference(&lights_ref, data_provider);
246
247 AINFO << "Dump output Done! Get box num:" << detected_bboxes_.size();
248
249 for (size_t j = 0; j < detected_bboxes_.size(); ++j) {
250 base::RectI &region = detected_bboxes_[j]->region.detection_roi;
251 float score = detected_bboxes_[j]->region.detect_score;
252 lights_ref[0]->region.debug_roi.push_back(region);
253 lights_ref[0]->region.debug_roi_detect_scores.push_back(score);
254 }
255
256 AINFO << "start select";
257 select_.SelectTrafficLights(detected_bboxes_, &lights_ref);
258 AINFO << "select success";
259
260 AINFO << "detection success";
261 return true;
262}
263
265 const std::vector<base::RectI> &crop_box_list,
266 const std::vector<float> &resize_scale_list_col,
267 const std::vector<float> &resize_scale_list_row,
268 std::vector<base::TrafficLightPtr> *lights) {
269 auto output_blob = rt_net_->get_blob(net_outputs_[0]);
270 auto model_type = detection_param_.info().framework();
271 int result_box_num, each_box_length;
272 if (model_type == common::TensorRT) {
273 result_box_num = output_blob->shape(1);
274 each_box_length = output_blob->shape(2);
275 } else {
276 result_box_num = output_blob->shape(0);
277 each_box_length = output_blob->shape(1);
278 }
279
280 AINFO << "output blob size " << output_blob->shape(0) << " " << output_blob->shape(1) << " "
281 << output_blob->shape(2) << " " << output_blob->shape(3);
282 AINFO << "result box number: " << result_box_num << " each box length: " << each_box_length;
283
284 for (int candidate_id = 0; candidate_id < result_box_num; candidate_id++) {
285 const float *result_data = output_blob->cpu_data() + candidate_id * each_box_length;
286 int img_id = static_cast<int>(result_data[0]);
287 if (img_id < 0) {
288 continue;
289 } else if (img_id >= static_cast<int>(crop_box_list.size())) {
290 AINFO << "img id " << img_id << " > " << crop_box_list.size();
291 continue;
292 }
294 float inflate_col = 1 / resize_scale_list_col.at(img_id);
295 float inflate_row = 1 / resize_scale_list_row.at(img_id);
296 float x1 = result_data[1];
297 float y1 = result_data[2];
298 float x2 = result_data[3];
299 float y2 = result_data[4];
300 std::vector<float> score{result_data[5], result_data[6], result_data[7], result_data[8]};
301 for (int i = 0; i < 9; ++i) {
302 ADEBUG << "result_data " << result_data[i];
303 }
304
305 std::vector<float>::iterator biggest = std::max_element(std::begin(score), std::end(score));
306 tmp->region.detect_class_id = base::TLDetectionClass(std::distance(std::begin(score), biggest) - 1);
307
308 if (static_cast<int>(tmp->region.detect_class_id) >= 0) {
309 tmp->region.detection_roi.x = static_cast<int>(x1 * inflate_col);
310 tmp->region.detection_roi.y = static_cast<int>(y1 * inflate_row);
311 tmp->region.detection_roi.width = static_cast<int>((x2 - x1 + 1) * inflate_col);
312 tmp->region.detection_roi.height = static_cast<int>((y2 - y1 + 1) * inflate_row);
313 tmp->region.detect_score = *biggest;
314
316 tmp->region.detection_roi, crop_box_list.at(img_id).width, crop_box_list.at(img_id).height)
317 || tmp->region.detection_roi.Area() <= 0) {
318 AINFO << "Invalid width or height or x or y: " << tmp->region.detection_roi.width << " | "
319 << tmp->region.detection_roi.height << " | " << tmp->region.detection_roi.x << " | "
320 << tmp->region.detection_roi.y;
321 AINFO << " max width " << crop_box_list.at(img_id).width << " max height "
322 << crop_box_list.at(img_id).height << " at img_id " << img_id;
323 continue;
324 }
325
327 tmp->region.detection_roi,
328 crop_box_list.at(img_id).width,
329 crop_box_list.at(img_id).height,
330 &(tmp->region.detection_roi));
331 tmp->region.detection_roi.x += crop_box_list.at(img_id).x;
332 tmp->region.detection_roi.y += crop_box_list.at(img_id).y;
333 tmp->region.is_detected = true;
334 AINFO << "detect roi x " << tmp->region.detection_roi.x << " " << tmp->region.detection_roi.y << " "
335 << tmp->region.detection_roi.width << " " << tmp->region.detection_roi.height;
336
337 lights->push_back(tmp);
338 } else {
339 AWARN << "Invalid class id: " << static_cast<int>(tmp->region.detect_class_id);
340 }
341 }
342
343 return true;
344}
345
346void TrafficLightDetection::ApplyNMS(std::vector<base::TrafficLightPtr> *lights, double iou_thresh) {
347 if (lights == nullptr) {
348 AERROR << "lights are not available";
349 return;
350 }
351
352 // (score, index) pairs sorted by detect score
353 std::vector<std::pair<float, int>> score_index_vec(lights->size());
354 for (size_t i = 0; i < lights->size(); ++i) {
355 score_index_vec[i].first = lights->at(i)->region.detect_score;
356 score_index_vec[i].second = static_cast<int>(i);
357 }
358 std::stable_sort(
359 score_index_vec.begin(),
360 score_index_vec.end(),
361 [](const std::pair<float, int> &pr1, const std::pair<float, int> &pr2) { return pr1.first < pr2.first; });
362
363 std::vector<int> kept_indices;
364 while (!score_index_vec.empty()) {
365 const int idx = score_index_vec.back().second;
366 bool keep = true;
367 for (size_t k = 0; k < kept_indices.size(); ++k) {
368 const int kept_idx = kept_indices[k];
369 const auto &rect1 = lights->at(idx)->region.detection_roi;
370 const auto &rect2 = lights->at(kept_idx)->region.detection_roi;
371 float overlap = static_cast<float>((rect1 & rect2).Area() / (rect1 | rect2).Area());
372 // if current bbox has large overlap(>=iou_thresh) with any
373 // kept bbox, drop it
374 keep = std::fabs(overlap) < iou_thresh;
375 if (!keep) {
376 break;
377 }
378 }
379 if (keep) {
380 kept_indices.push_back(idx);
381 }
382 score_index_vec.pop_back();
383 }
384
385 int idx = 0;
386 auto parted_itr = std::stable_partition(lights->begin(), lights->end(), [&](const base::TrafficLightPtr &light) {
387 return std::find(kept_indices.begin(), kept_indices.end(), idx++) != kept_indices.end();
388 });
389 lights->erase(parted_itr, lights->end());
390}
391
393
394} // namespace trafficlight
395} // namespace perception
396} // namespace apollo
#define REGISTER_TRAFFIC_LIGHT_DETECTOR(name)
A wrapper around SyncedMemory holders serving as the basic computational unit for images,...
Definition blob.h:88
A wrapper around Blob holders serving as the basic computational unit for images.
Definition image_8u.h:44
bool GetImage(const ImageOptions &options, base::Image8U *image)
void SelectTrafficLights(const std::vector< base::TrafficLightPtr > &refined_bboxes, std::vector< base::TrafficLightPtr > *hdmap_bboxes)
Choose traffic lights using Gaussian calculation scores.
Definition select.cc:41
bool Init(int rows, int cols)
Initialize select object parameters.
Definition select.cc:24
bool Inference(std::vector< base::TrafficLightPtr > *lights, camera::DataProvider *data_provider)
Model inference process.
Definition detection.cc:134
bool Detect(camera::TrafficLightFrame *frame) override
Detect traffic light from image.
Definition detection.cc:207
bool Init(const TrafficLightDetectorInitOptions &options) override
Initialize traffic light detector parameters.
Definition detection.cc:38
TrafficLightDetection()
Construct a new traffic light detection object.
Definition detection.cc:35
bool SelectOutputBoxes(const std::vector< base::RectI > &crop_box_list, const std::vector< float > &resize_scale_list_col, const std::vector< float > &resize_scale_list_row, std::vector< base::TrafficLightPtr > *lights)
Dump output of inference results.
Definition detection.cc:264
void ApplyNMS(std::vector< base::TrafficLightPtr > *lights, double iou_thresh=0.6)
Filter overlapping boxes using NMS.
Definition detection.cc:346
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
#define AWARN
Definition log.h:43
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::shared_ptr< TrafficLight > TrafficLightPtr
bool OutOfValidRegion(const base::BBox2D< T > box, const T width, const T height, const T border_size=0)
Definition util.h:74
void RefineBox(const base::Rect< T > &box_in, const T width, const T height, base::Rect< T > *box_out)
Definition util.h:92
std::vector< std::string > GetBlobNames(const google::protobuf::RepeatedPtrField< common::ModelBlob > &model_blobs)
Definition model_util.cc:23
void AddShape(std::map< std::string, std::vector< int > > *shape_map, const google::protobuf::RepeatedPtrField< common::ModelBlob > &model_blobs)
Definition model_util.cc:32
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
Definition util.cc:55
std::string GetConfigFile(const std::string &config_path, const std::string &config_file)
Definition util.cc:80
std::string GetModelPath(const std::string &model_name)
Get the model path by model name, search from APOLLO_MODEL_PATH
Definition util.cc:44
class register implement
Definition arena_queue.h:37
#define PERF_BLOCK_END
Definition profiler.h:53
#define PERF_BLOCK(...)
Definition profiler.h:52
std::vector< base::TrafficLightPtr > traffic_lights
std::shared_ptr< camera::DataProvider > data_provider