object_detector.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. // Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <sstream>
  15. // for setprecision
  16. #include <chrono>
  17. #include <iomanip>
  18. #include "include/object_detector.h"
  19. using namespace paddle_infer;
  20. namespace PaddleDetection {
  21. // Load Model and create model predictor
  22. void ObjectDetector::LoadModel(const std::string& model_dir,
  23. const int batch_size,
  24. const std::string& run_mode) {
  25. paddle_infer::Config config;
  26. std::string prog_file = model_dir + OS_PATH_SEP + "model.pdmodel";
  27. std::string params_file = model_dir + OS_PATH_SEP + "model.pdiparams";
  28. config.SetModel(prog_file, params_file);
  29. if (this->device_ == "GPU") {
  30. config.EnableUseGpu(200, this->gpu_id_);
  31. config.SwitchIrOptim(true);
  32. // use tensorrt
  33. if (run_mode != "paddle") {
  34. auto precision = paddle_infer::Config::Precision::kFloat32;
  35. if (run_mode == "trt_fp32") {
  36. precision = paddle_infer::Config::Precision::kFloat32;
  37. } else if (run_mode == "trt_fp16") {
  38. precision = paddle_infer::Config::Precision::kHalf;
  39. } else if (run_mode == "trt_int8") {
  40. precision = paddle_infer::Config::Precision::kInt8;
  41. } else {
  42. printf(
  43. "run_mode should be 'paddle', 'trt_fp32', 'trt_fp16' or "
  44. "'trt_int8'");
  45. }
  46. // set tensorrt
  47. config.EnableTensorRtEngine(1 << 30,
  48. batch_size,
  49. this->min_subgraph_size_,
  50. precision,
  51. false,
  52. this->trt_calib_mode_);
  53. // set use dynamic shape
  54. if (this->use_dynamic_shape_) {
  55. // set DynamicShsape for image tensor
  56. const std::vector<int> min_input_shape = {
  57. 1, 3, this->trt_min_shape_, this->trt_min_shape_};
  58. const std::vector<int> max_input_shape = {
  59. 1, 3, this->trt_max_shape_, this->trt_max_shape_};
  60. const std::vector<int> opt_input_shape = {
  61. 1, 3, this->trt_opt_shape_, this->trt_opt_shape_};
  62. const std::map<std::string, std::vector<int>> map_min_input_shape = {
  63. {"image", min_input_shape}};
  64. const std::map<std::string, std::vector<int>> map_max_input_shape = {
  65. {"image", max_input_shape}};
  66. const std::map<std::string, std::vector<int>> map_opt_input_shape = {
  67. {"image", opt_input_shape}};
  68. config.SetTRTDynamicShapeInfo(
  69. map_min_input_shape, map_max_input_shape, map_opt_input_shape);
  70. std::cout << "TensorRT dynamic shape enabled" << std::endl;
  71. }
  72. }
  73. } else if (this->device_ == "XPU") {
  74. config.EnableXpu(10 * 1024 * 1024);
  75. } else {
  76. config.DisableGpu();
  77. if (this->use_mkldnn_) {
  78. config.EnableMKLDNN();
  79. // cache 10 different shapes for mkldnn to avoid memory leak
  80. config.SetMkldnnCacheCapacity(10);
  81. }
  82. config.SetCpuMathLibraryNumThreads(this->cpu_math_library_num_threads_);
  83. }
  84. config.SwitchUseFeedFetchOps(false);
  85. config.SwitchIrOptim(true);
  86. config.DisableGlogInfo();
  87. // Memory optimization
  88. config.EnableMemoryOptim();
  89. predictor_ = std::move(CreatePredictor(config));
  90. }
  91. // Visualiztion MaskDetector results
  92. cv::Mat VisualizeResult(
  93. const cv::Mat& img,
  94. const std::vector<PaddleDetection::ObjectResult>& results,
  95. const std::vector<std::string>& lables,
  96. const std::vector<int>& colormap,
  97. const bool is_rbox = false) {
  98. cv::Mat vis_img = img.clone();
  99. int img_h = vis_img.rows;
  100. int img_w = vis_img.cols;
  101. for (int i = 0; i < results.size(); ++i) {
  102. // Configure color and text size
  103. std::ostringstream oss;
  104. oss << std::setiosflags(std::ios::fixed) << std::setprecision(4);
  105. oss << lables[results[i].class_id] << " ";
  106. oss << results[i].confidence;
  107. std::string text = oss.str();
  108. int c1 = colormap[3 * results[i].class_id + 0];
  109. int c2 = colormap[3 * results[i].class_id + 1];
  110. int c3 = colormap[3 * results[i].class_id + 2];
  111. cv::Scalar roi_color = cv::Scalar(c1, c2, c3);
  112. int font_face = cv::FONT_HERSHEY_COMPLEX_SMALL;
  113. double font_scale = 0.5f;
  114. float thickness = 0.5;
  115. cv::Size text_size =
  116. cv::getTextSize(text, font_face, font_scale, thickness, nullptr);
  117. cv::Point origin;
  118. if (is_rbox) {
  119. // Draw object, text, and background
  120. for (int k = 0; k < 4; k++) {
  121. cv::Point pt1 = cv::Point(results[i].rect[(k * 2) % 8],
  122. results[i].rect[(k * 2 + 1) % 8]);
  123. cv::Point pt2 = cv::Point(results[i].rect[(k * 2 + 2) % 8],
  124. results[i].rect[(k * 2 + 3) % 8]);
  125. cv::line(vis_img, pt1, pt2, roi_color, 2);
  126. }
  127. } else {
  128. int w = results[i].rect[2] - results[i].rect[0];
  129. int h = results[i].rect[3] - results[i].rect[1];
  130. cv::Rect roi = cv::Rect(results[i].rect[0], results[i].rect[1], w, h);
  131. // Draw roi object, text, and background
  132. cv::rectangle(vis_img, roi, roi_color, 2);
  133. // Draw mask
  134. std::vector<int> mask_v = results[i].mask;
  135. if (mask_v.size() > 0) {
  136. cv::Mat mask = cv::Mat(img_h, img_w, CV_32S);
  137. std::memcpy(mask.data, mask_v.data(), mask_v.size() * sizeof(int));
  138. cv::Mat colored_img = vis_img.clone();
  139. std::vector<cv::Mat> contours;
  140. cv::Mat hierarchy;
  141. mask.convertTo(mask, CV_8U);
  142. cv::findContours(
  143. mask, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);
  144. cv::drawContours(colored_img,
  145. contours,
  146. -1,
  147. roi_color,
  148. -1,
  149. cv::LINE_8,
  150. hierarchy,
  151. 100);
  152. cv::Mat debug_roi = vis_img;
  153. colored_img = 0.4 * colored_img + 0.6 * vis_img;
  154. colored_img.copyTo(vis_img, mask);
  155. }
  156. }
  157. origin.x = results[i].rect[0];
  158. origin.y = results[i].rect[1];
  159. // Configure text background
  160. cv::Rect text_back = cv::Rect(results[i].rect[0],
  161. results[i].rect[1] - text_size.height,
  162. text_size.width,
  163. text_size.height);
  164. // Draw text, and background
  165. cv::rectangle(vis_img, text_back, roi_color, -1);
  166. cv::putText(vis_img,
  167. text,
  168. origin,
  169. font_face,
  170. font_scale,
  171. cv::Scalar(255, 255, 255),
  172. thickness);
  173. }
  174. return vis_img;
  175. }
  176. void ObjectDetector::Preprocess(const cv::Mat& ori_im) {
  177. // Clone the image : keep the original mat for postprocess
  178. cv::Mat im = ori_im.clone();
  179. cv::cvtColor(im, im, cv::COLOR_BGR2RGB);
  180. preprocessor_.Run(&im, &inputs_);
  181. }
  182. void ObjectDetector::Postprocess(
  183. const std::vector<cv::Mat> mats,
  184. std::vector<PaddleDetection::ObjectResult>* result,
  185. std::vector<int> bbox_num,
  186. std::vector<float> output_data_,
  187. std::vector<int> output_mask_data_,
  188. bool is_rbox = false) {
  189. result->clear();
  190. int start_idx = 0;
  191. int total_num = std::accumulate(bbox_num.begin(), bbox_num.end(), 0);
  192. int out_mask_dim = -1;
  193. if (config_.mask_) {
  194. out_mask_dim = output_mask_data_.size() / total_num;
  195. }
  196. for (int im_id = 0; im_id < mats.size(); im_id++) {
  197. cv::Mat raw_mat = mats[im_id];
  198. int rh = 1;
  199. int rw = 1;
  200. if (config_.arch_ == "Face") {
  201. rh = raw_mat.rows;
  202. rw = raw_mat.cols;
  203. }
  204. for (int j = start_idx; j < start_idx + bbox_num[im_id]; j++) {
  205. if (is_rbox) {
  206. // Class id
  207. int class_id = static_cast<int>(round(output_data_[0 + j * 10]));
  208. // Confidence score
  209. float score = output_data_[1 + j * 10];
  210. int x1 = (output_data_[2 + j * 10] * rw);
  211. int y1 = (output_data_[3 + j * 10] * rh);
  212. int x2 = (output_data_[4 + j * 10] * rw);
  213. int y2 = (output_data_[5 + j * 10] * rh);
  214. int x3 = (output_data_[6 + j * 10] * rw);
  215. int y3 = (output_data_[7 + j * 10] * rh);
  216. int x4 = (output_data_[8 + j * 10] * rw);
  217. int y4 = (output_data_[9 + j * 10] * rh);
  218. PaddleDetection::ObjectResult result_item;
  219. result_item.rect = {x1, y1, x2, y2, x3, y3, x4, y4};
  220. result_item.class_id = class_id;
  221. result_item.confidence = score;
  222. result->push_back(result_item);
  223. } else {
  224. // Class id
  225. int class_id = static_cast<int>(round(output_data_[0 + j * 6]));
  226. // Confidence score
  227. float score = output_data_[1 + j * 6];
  228. int xmin = (output_data_[2 + j * 6] * rw);
  229. int ymin = (output_data_[3 + j * 6] * rh);
  230. int xmax = (output_data_[4 + j * 6] * rw);
  231. int ymax = (output_data_[5 + j * 6] * rh);
  232. int wd = xmax - xmin;
  233. int hd = ymax - ymin;
  234. PaddleDetection::ObjectResult result_item;
  235. result_item.rect = {xmin, ymin, xmax, ymax};
  236. result_item.class_id = class_id;
  237. result_item.confidence = score;
  238. if (config_.mask_) {
  239. std::vector<int> mask;
  240. for (int k = 0; k < out_mask_dim; ++k) {
  241. if (output_mask_data_[k + j * out_mask_dim] > -1) {
  242. mask.push_back(output_mask_data_[k + j * out_mask_dim]);
  243. }
  244. }
  245. result_item.mask = mask;
  246. }
  247. result->push_back(result_item);
  248. }
  249. }
  250. start_idx += bbox_num[im_id];
  251. }
  252. }
  253. void ObjectDetector::Predict(const std::vector<cv::Mat> imgs,
  254. const double threshold,
  255. const int warmup,
  256. const int repeats,
  257. std::vector<PaddleDetection::ObjectResult>* result,
  258. std::vector<int>* bbox_num,
  259. std::vector<double>* times) {
  260. auto preprocess_start = std::chrono::steady_clock::now();
  261. int batch_size = imgs.size();
  262. // in_data_batch
  263. std::vector<float> in_data_all;
  264. std::vector<float> im_shape_all(batch_size * 2);
  265. std::vector<float> scale_factor_all(batch_size * 2);
  266. std::vector<const float*> output_data_list_;
  267. std::vector<int> out_bbox_num_data_;
  268. std::vector<int> out_mask_data_;
  269. // in_net img for each batch
  270. std::vector<cv::Mat> in_net_img_all(batch_size);
  271. // Preprocess image
  272. for (int bs_idx = 0; bs_idx < batch_size; bs_idx++) {
  273. cv::Mat im = imgs.at(bs_idx);
  274. Preprocess(im);
  275. im_shape_all[bs_idx * 2] = inputs_.im_shape_[0];
  276. im_shape_all[bs_idx * 2 + 1] = inputs_.im_shape_[1];
  277. scale_factor_all[bs_idx * 2] = inputs_.scale_factor_[0];
  278. scale_factor_all[bs_idx * 2 + 1] = inputs_.scale_factor_[1];
  279. // TODO: reduce cost time
  280. in_data_all.insert(
  281. in_data_all.end(), inputs_.im_data_.begin(), inputs_.im_data_.end());
  282. // collect in_net img
  283. in_net_img_all[bs_idx] = inputs_.in_net_im_;
  284. }
  285. // Pad Batch if batch size > 1
  286. if (batch_size > 1 && CheckDynamicInput(in_net_img_all)) {
  287. in_data_all.clear();
  288. std::vector<cv::Mat> pad_img_all = PadBatch(in_net_img_all);
  289. int rh = pad_img_all[0].rows;
  290. int rw = pad_img_all[0].cols;
  291. int rc = pad_img_all[0].channels();
  292. for (int bs_idx = 0; bs_idx < batch_size; bs_idx++) {
  293. cv::Mat pad_img = pad_img_all[bs_idx];
  294. pad_img.convertTo(pad_img, CV_32FC3);
  295. std::vector<float> pad_data;
  296. pad_data.resize(rc * rh * rw);
  297. float* base = pad_data.data();
  298. for (int i = 0; i < rc; ++i) {
  299. cv::extractChannel(
  300. pad_img, cv::Mat(rh, rw, CV_32FC1, base + i * rh * rw), i);
  301. }
  302. in_data_all.insert(in_data_all.end(), pad_data.begin(), pad_data.end());
  303. }
  304. // update in_net_shape
  305. inputs_.in_net_shape_ = {static_cast<float>(rh), static_cast<float>(rw)};
  306. }
  307. auto preprocess_end = std::chrono::steady_clock::now();
  308. // Prepare input tensor
  309. auto input_names = predictor_->GetInputNames();
  310. for (const auto& tensor_name : input_names) {
  311. auto in_tensor = predictor_->GetInputHandle(tensor_name);
  312. if (tensor_name == "image") {
  313. int rh = inputs_.in_net_shape_[0];
  314. int rw = inputs_.in_net_shape_[1];
  315. in_tensor->Reshape({batch_size, 3, rh, rw});
  316. in_tensor->CopyFromCpu(in_data_all.data());
  317. } else if (tensor_name == "im_shape") {
  318. in_tensor->Reshape({batch_size, 2});
  319. in_tensor->CopyFromCpu(im_shape_all.data());
  320. } else if (tensor_name == "scale_factor") {
  321. in_tensor->Reshape({batch_size, 2});
  322. in_tensor->CopyFromCpu(scale_factor_all.data());
  323. }
  324. }
  325. // Run predictor
  326. std::vector<std::vector<float>> out_tensor_list;
  327. std::vector<std::vector<int>> output_shape_list;
  328. bool is_rbox = false;
  329. int reg_max = 7;
  330. int num_class = 80;
  331. // warmup
  332. for (int i = 0; i < warmup; i++) {
  333. predictor_->Run();
  334. // Get output tensor
  335. auto output_names = predictor_->GetOutputNames();
  336. for (int j = 0; j < output_names.size(); j++) {
  337. auto output_tensor = predictor_->GetOutputHandle(output_names[j]);
  338. std::vector<int> output_shape = output_tensor->shape();
  339. int out_num = std::accumulate(
  340. output_shape.begin(), output_shape.end(), 1, std::multiplies<int>());
  341. if (config_.mask_ && (j == 2)) {
  342. out_mask_data_.resize(out_num);
  343. output_tensor->CopyToCpu(out_mask_data_.data());
  344. } else if (output_tensor->type() == paddle_infer::DataType::INT32) {
  345. out_bbox_num_data_.resize(out_num);
  346. output_tensor->CopyToCpu(out_bbox_num_data_.data());
  347. } else {
  348. std::vector<float> out_data;
  349. out_data.resize(out_num);
  350. output_tensor->CopyToCpu(out_data.data());
  351. out_tensor_list.push_back(out_data);
  352. }
  353. }
  354. }
  355. auto inference_start = std::chrono::steady_clock::now();
  356. for (int i = 0; i < repeats; i++) {
  357. predictor_->Run();
  358. // Get output tensor
  359. out_tensor_list.clear();
  360. output_shape_list.clear();
  361. auto output_names = predictor_->GetOutputNames();
  362. for (int j = 0; j < output_names.size(); j++) {
  363. auto output_tensor = predictor_->GetOutputHandle(output_names[j]);
  364. std::vector<int> output_shape = output_tensor->shape();
  365. int out_num = std::accumulate(
  366. output_shape.begin(), output_shape.end(), 1, std::multiplies<int>());
  367. output_shape_list.push_back(output_shape);
  368. if (config_.mask_ && (j == 2)) {
  369. out_mask_data_.resize(out_num);
  370. output_tensor->CopyToCpu(out_mask_data_.data());
  371. } else if (output_tensor->type() == paddle_infer::DataType::INT32) {
  372. out_bbox_num_data_.resize(out_num);
  373. output_tensor->CopyToCpu(out_bbox_num_data_.data());
  374. } else {
  375. std::vector<float> out_data;
  376. out_data.resize(out_num);
  377. output_tensor->CopyToCpu(out_data.data());
  378. out_tensor_list.push_back(out_data);
  379. }
  380. }
  381. }
  382. auto inference_end = std::chrono::steady_clock::now();
  383. auto postprocess_start = std::chrono::steady_clock::now();
  384. // Postprocessing result
  385. result->clear();
  386. bbox_num->clear();
  387. if (config_.arch_ == "PicoDet") {
  388. for (int i = 0; i < out_tensor_list.size(); i++) {
  389. if (i == 0) {
  390. num_class = output_shape_list[i][2];
  391. }
  392. if (i == config_.fpn_stride_.size()) {
  393. reg_max = output_shape_list[i][2] / 4 - 1;
  394. }
  395. float* buffer = new float[out_tensor_list[i].size()];
  396. memcpy(buffer,
  397. &out_tensor_list[i][0],
  398. out_tensor_list[i].size() * sizeof(float));
  399. output_data_list_.push_back(buffer);
  400. }
  401. PaddleDetection::PicoDetPostProcess(
  402. result,
  403. output_data_list_,
  404. config_.fpn_stride_,
  405. inputs_.im_shape_,
  406. inputs_.scale_factor_,
  407. config_.nms_info_["score_threshold"].as<float>(),
  408. config_.nms_info_["nms_threshold"].as<float>(),
  409. num_class,
  410. reg_max);
  411. bbox_num->push_back(result->size());
  412. } else {
  413. is_rbox = output_shape_list[0][output_shape_list[0].size() - 1] % 10 == 0;
  414. Postprocess(imgs,
  415. result,
  416. out_bbox_num_data_,
  417. out_tensor_list[0],
  418. out_mask_data_,
  419. is_rbox);
  420. for (int k = 0; k < out_bbox_num_data_.size(); k++) {
  421. int tmp = out_bbox_num_data_[k];
  422. bbox_num->push_back(tmp);
  423. }
  424. }
  425. auto postprocess_end = std::chrono::steady_clock::now();
  426. std::chrono::duration<float> preprocess_diff =
  427. preprocess_end - preprocess_start;
  428. times->push_back(static_cast<double>(preprocess_diff.count() * 1000));
  429. std::chrono::duration<float> inference_diff = inference_end - inference_start;
  430. times->push_back(
  431. static_cast<double>(inference_diff.count() / repeats * 1000));
  432. std::chrono::duration<float> postprocess_diff =
  433. postprocess_end - postprocess_start;
  434. times->push_back(static_cast<double>(postprocess_diff.count() * 1000));
  435. }
  436. std::vector<int> GenerateColorMap(int num_class) {
  437. auto colormap = std::vector<int>(3 * num_class, 0);
  438. for (int i = 0; i < num_class; ++i) {
  439. int j = 0;
  440. int lab = i;
  441. while (lab) {
  442. colormap[i * 3] |= (((lab >> 0) & 1) << (7 - j));
  443. colormap[i * 3 + 1] |= (((lab >> 1) & 1) << (7 - j));
  444. colormap[i * 3 + 2] |= (((lab >> 2) & 1) << (7 - j));
  445. ++j;
  446. lab >>= 3;
  447. }
  448. }
  449. return colormap;
  450. }
  451. } // namespace PaddleDetection