detection.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * License); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. #pragma once
  20. #include <algorithm>
  21. #include <cmath>
  22. #include <cstdint>
  23. #include <string>
  24. #include <vector>
  25. // #include "types.hpp"
  26. #include <opencv2/opencv.hpp>
  27. #include <opencv2/imgproc.hpp>
  28. #include <opencv2/highgui.hpp>
  29. // #include <chrono>
  30. namespace detection
  31. {
  32. typedef struct
  33. {
  34. int grid0;
  35. int grid1;
  36. int stride;
  37. } GridAndStride;
  38. // typedef struct
  39. // {
  40. // cv::Rect_<float> rect;
  41. // int label;
  42. // float prob;
  43. // } Object;
  44. typedef struct
  45. {
  46. cv::Rect_<float> rect;
  47. int label;
  48. float prob;
  49. // cv::Point2f landmark[5];
  50. /* for yolov5-seg */
  51. cv::Mat mask;
  52. std::vector<float> mask_feat;
  53. std::vector<float> kps_feat;
  54. } Object;
  55. static inline float sigmoid(float x)
  56. {
  57. return static_cast<float>(1.f / (1.f + exp(-x)));
  58. }
  59. static float softmax(const float *src, float *dst, int length)
  60. {
  61. const float alpha = *std::max_element(src, src + length);
  62. float denominator = 0;
  63. float dis_sum = 0;
  64. for (int i = 0; i < length; ++i)
  65. {
  66. dst[i] = exp(src[i] - alpha);
  67. denominator += dst[i];
  68. }
  69. for (int i = 0; i < length; ++i)
  70. {
  71. dst[i] /= denominator;
  72. dis_sum += i * dst[i];
  73. }
  74. return dis_sum;
  75. }
  76. static inline float intersection_area(const Object &a, const Object &b)
  77. {
  78. cv::Rect_<float> inter = a.rect & b.rect;
  79. return inter.area();
  80. }
  81. static void qsort_descent_inplace(std::vector<Object> &faceobjects, int left, int right)
  82. {
  83. int i = left;
  84. int j = right;
  85. float p = faceobjects[(left + right) / 2].prob;
  86. while (i <= j)
  87. {
  88. while (faceobjects[i].prob > p)
  89. i++;
  90. while (faceobjects[j].prob < p)
  91. j--;
  92. if (i <= j)
  93. {
  94. // swap
  95. std::swap(faceobjects[i], faceobjects[j]);
  96. i++;
  97. j--;
  98. }
  99. }
  100. // #pragma omp parallel sections
  101. {
  102. // #pragma omp section
  103. {
  104. if (left < j)
  105. qsort_descent_inplace(faceobjects, left, j);
  106. }
  107. // #pragma omp section
  108. {
  109. if (i < right)
  110. qsort_descent_inplace(faceobjects, i, right);
  111. }
  112. }
  113. }
  114. static void qsort_descent_inplace(std::vector<Object> &faceobjects)
  115. {
  116. if (faceobjects.empty())
  117. return;
  118. qsort_descent_inplace(faceobjects, 0, faceobjects.size() - 1);
  119. }
  120. static void nms_sorted_bboxes(const std::vector<Object> &faceobjects, std::vector<int> &picked, float nms_threshold)
  121. {
  122. picked.clear();
  123. const int n = faceobjects.size();
  124. std::vector<float> areas(n);
  125. for (int i = 0; i < n; i++)
  126. {
  127. areas[i] = faceobjects[i].rect.area();
  128. }
  129. for (int i = 0; i < n; i++)
  130. {
  131. const Object &a = faceobjects[i];
  132. int keep = 1;
  133. for (int j = 0; j < (int)picked.size(); j++)
  134. {
  135. const Object &b = faceobjects[picked[j]];
  136. // intersection over union
  137. float inter_area = intersection_area(a, b);
  138. float union_area = areas[i] + areas[picked[j]] - inter_area;
  139. // float IoU = inter_area / union_area
  140. if (inter_area / union_area > nms_threshold)
  141. keep = 0;
  142. }
  143. if (keep)
  144. picked.push_back(i);
  145. }
  146. }
  147. static void generate_grids_and_stride(const int target_w, const int target_h, std::vector<int> &strides,
  148. std::vector<GridAndStride> &grid_strides)
  149. {
  150. for (auto stride : strides)
  151. {
  152. int num_grid_w = target_w / stride;
  153. int num_grid_h = target_h / stride;
  154. for (int g1 = 0; g1 < num_grid_h; g1++)
  155. {
  156. for (int g0 = 0; g0 < num_grid_w; g0++)
  157. {
  158. GridAndStride gs;
  159. gs.grid0 = g0;
  160. gs.grid1 = g1;
  161. gs.stride = stride;
  162. grid_strides.push_back(gs);
  163. }
  164. }
  165. }
  166. }
  167. void reverse_letterbox(std::vector<Object> &proposal, std::vector<Object> &objects, int letterbox_rows, int letterbox_cols, int src_rows,
  168. int src_cols)
  169. {
  170. float scale_letterbox;
  171. int resize_rows;
  172. int resize_cols;
  173. if ((letterbox_rows * 1.0 / src_rows) < (letterbox_cols * 1.0 / src_cols))
  174. {
  175. scale_letterbox = letterbox_rows * 1.0 / src_rows;
  176. }
  177. else
  178. {
  179. scale_letterbox = letterbox_cols * 1.0 / src_cols;
  180. }
  181. resize_cols = int(scale_letterbox * src_cols);
  182. resize_rows = int(scale_letterbox * src_rows);
  183. int tmp_h = (letterbox_rows - resize_rows) / 2;
  184. int tmp_w = (letterbox_cols - resize_cols) / 2;
  185. float ratio_x = (float)src_rows / resize_rows;
  186. float ratio_y = (float)src_cols / resize_cols;
  187. int count = proposal.size();
  188. objects.resize(count);
  189. for (int i = 0; i < count; i++)
  190. {
  191. objects[i] = proposal[i];
  192. float x0 = (objects[i].rect.x);
  193. float y0 = (objects[i].rect.y);
  194. float x1 = (objects[i].rect.x + objects[i].rect.width);
  195. float y1 = (objects[i].rect.y + objects[i].rect.height);
  196. x0 = (x0 - tmp_w) * ratio_x;
  197. y0 = (y0 - tmp_h) * ratio_y;
  198. x1 = (x1 - tmp_w) * ratio_x;
  199. y1 = (y1 - tmp_h) * ratio_y;
  200. x0 = std::max(std::min(x0, (float)(src_cols - 1)), 0.f);
  201. y0 = std::max(std::min(y0, (float)(src_rows - 1)), 0.f);
  202. x1 = std::max(std::min(x1, (float)(src_cols - 1)), 0.f);
  203. y1 = std::max(std::min(y1, (float)(src_rows - 1)), 0.f);
  204. objects[i].rect.x = x0;
  205. objects[i].rect.y = y0;
  206. objects[i].rect.width = x1 - x0;
  207. objects[i].rect.height = y1 - y0;
  208. }
  209. }
  210. static void get_out_bbox_kps(std::vector<Object> &proposals, std::vector<Object> &objects, const float nms_threshold, int letterbox_rows, int letterbox_cols, int src_rows, int src_cols)
  211. {
  212. qsort_descent_inplace(proposals);
  213. std::vector<int> picked;
  214. nms_sorted_bboxes(proposals, picked, nms_threshold);
  215. /* yolov8 draw the result */
  216. float scale_letterbox;
  217. int resize_rows;
  218. int resize_cols;
  219. if ((letterbox_rows * 1.0 / src_rows) < (letterbox_cols * 1.0 / src_cols))
  220. {
  221. scale_letterbox = letterbox_rows * 1.0 / src_rows;
  222. }
  223. else
  224. {
  225. scale_letterbox = letterbox_cols * 1.0 / src_cols;
  226. }
  227. resize_cols = int(scale_letterbox * src_cols);
  228. resize_rows = int(scale_letterbox * src_rows);
  229. int tmp_h = (letterbox_rows - resize_rows) / 2;
  230. int tmp_w = (letterbox_cols - resize_cols) / 2;
  231. float ratio_x = (float)src_rows / resize_rows;
  232. float ratio_y = (float)src_cols / resize_cols;
  233. int count = picked.size();
  234. objects.resize(count);
  235. for (int i = 0; i < count; i++)
  236. {
  237. objects[i] = proposals[picked[i]];
  238. float x0 = (objects[i].rect.x);
  239. float y0 = (objects[i].rect.y);
  240. float x1 = (objects[i].rect.x + objects[i].rect.width);
  241. float y1 = (objects[i].rect.y + objects[i].rect.height);
  242. x0 = (x0 - tmp_w) * ratio_x;
  243. y0 = (y0 - tmp_h) * ratio_y;
  244. x1 = (x1 - tmp_w) * ratio_x;
  245. y1 = (y1 - tmp_h) * ratio_y;
  246. x0 = std::max(std::min(x0, (float)(src_cols - 1)), 0.f);
  247. y0 = std::max(std::min(y0, (float)(src_rows - 1)), 0.f);
  248. x1 = std::max(std::min(x1, (float)(src_cols - 1)), 0.f);
  249. y1 = std::max(std::min(y1, (float)(src_rows - 1)), 0.f);
  250. objects[i].rect.x = x0;
  251. objects[i].rect.y = y0;
  252. objects[i].rect.width = x1 - x0;
  253. objects[i].rect.height = y1 - y0;
  254. for (int j = 0; j < int(objects[i].kps_feat.size() / 3); j++)
  255. {
  256. objects[i].kps_feat[j * 3] = std::max(
  257. std::min((objects[i].kps_feat[j * 3] - tmp_w) * ratio_x, (float)(src_cols - 1)), 0.f);
  258. objects[i].kps_feat[j * 3 + 1] = std::max(
  259. std::min((objects[i].kps_feat[j * 3 + 1] - tmp_h) * ratio_y, (float)(src_rows - 1)), 0.f);
  260. }
  261. }
  262. }
  263. void get_out_bbox(std::vector<Object> &proposals, std::vector<Object> &objects, const float nms_threshold, int letterbox_rows,
  264. int letterbox_cols, int src_rows, int src_cols)
  265. {
  266. qsort_descent_inplace(proposals);
  267. std::vector<int> picked;
  268. nms_sorted_bboxes(proposals, picked, nms_threshold);
  269. /* yolov5 draw the result */
  270. float scale_letterbox;
  271. int resize_rows;
  272. int resize_cols;
  273. if ((letterbox_rows * 1.0 / src_rows) < (letterbox_cols * 1.0 / src_cols))
  274. {
  275. scale_letterbox = letterbox_rows * 1.0 / src_rows;
  276. }
  277. else
  278. {
  279. scale_letterbox = letterbox_cols * 1.0 / src_cols;
  280. }
  281. resize_cols = int(scale_letterbox * src_cols);
  282. resize_rows = int(scale_letterbox * src_rows);
  283. int tmp_h = (letterbox_rows - resize_rows) / 2;
  284. int tmp_w = (letterbox_cols - resize_cols) / 2;
  285. float ratio_x = (float)src_rows / resize_rows;
  286. float ratio_y = (float)src_cols / resize_cols;
  287. int count = picked.size();
  288. objects.resize(count);
  289. for (int i = 0; i < count; i++)
  290. {
  291. objects[i] = proposals[picked[i]];
  292. float x0 = (objects[i].rect.x);
  293. float y0 = (objects[i].rect.y);
  294. float x1 = (objects[i].rect.x + objects[i].rect.width);
  295. float y1 = (objects[i].rect.y + objects[i].rect.height);
  296. x0 = (x0 - tmp_w) * ratio_x;
  297. y0 = (y0 - tmp_h) * ratio_y;
  298. x1 = (x1 - tmp_w) * ratio_x;
  299. y1 = (y1 - tmp_h) * ratio_y;
  300. x0 = std::max(std::min(x0, (float)(src_cols - 1)), 0.f);
  301. y0 = std::max(std::min(y0, (float)(src_rows - 1)), 0.f);
  302. x1 = std::max(std::min(x1, (float)(src_cols - 1)), 0.f);
  303. y1 = std::max(std::min(y1, (float)(src_rows - 1)), 0.f);
  304. objects[i].rect.x = x0;
  305. objects[i].rect.y = y0;
  306. objects[i].rect.width = x1 - x0;
  307. objects[i].rect.height = y1 - y0;
  308. }
  309. }
  310. static void generate_proposals_yolov8_pose_native(int stride, const float *feat, const float *feat_kps, float prob_threshold, std::vector<Object> &objects,
  311. int letterbox_cols, int letterbox_rows, const int num_point = 17, int cls_num = 1)
  312. {
  313. int feat_w = letterbox_cols / stride;
  314. int feat_h = letterbox_rows / stride;
  315. int reg_max = 16;
  316. auto feat_ptr = feat;
  317. std::vector<float> dis_after_sm(reg_max, 0.f);
  318. for (int h = 0; h <= feat_h - 1; h++)
  319. {
  320. for (int w = 0; w <= feat_w - 1; w++)
  321. {
  322. // process cls score
  323. int class_index = 0;
  324. float class_score = -FLT_MAX;
  325. for (int s = 0; s <= cls_num - 1; s++)
  326. {
  327. float score = feat_ptr[s + 4 * reg_max];
  328. if (score > class_score)
  329. {
  330. class_index = s;
  331. class_score = score;
  332. }
  333. }
  334. float box_prob = sigmoid(class_score);
  335. if (box_prob > prob_threshold)
  336. {
  337. float pred_ltrb[4];
  338. for (int k = 0; k < 4; k++)
  339. {
  340. float dis = softmax(feat_ptr + k * reg_max, dis_after_sm.data(), reg_max);
  341. pred_ltrb[k] = dis * stride;
  342. }
  343. float pb_cx = (w + 0.5f) * stride;
  344. float pb_cy = (h + 0.5f) * stride;
  345. float x0 = pb_cx - pred_ltrb[0];
  346. float y0 = pb_cy - pred_ltrb[1];
  347. float x1 = pb_cx + pred_ltrb[2];
  348. float y1 = pb_cy + pred_ltrb[3];
  349. x0 = std::max(std::min(x0, (float)(letterbox_cols - 1)), 0.f);
  350. y0 = std::max(std::min(y0, (float)(letterbox_rows - 1)), 0.f);
  351. x1 = std::max(std::min(x1, (float)(letterbox_cols - 1)), 0.f);
  352. y1 = std::max(std::min(y1, (float)(letterbox_rows - 1)), 0.f);
  353. Object obj;
  354. obj.rect.x = x0;
  355. obj.rect.y = y0;
  356. obj.rect.width = x1 - x0;
  357. obj.rect.height = y1 - y0;
  358. obj.label = class_index;
  359. obj.prob = box_prob;
  360. obj.kps_feat.clear();
  361. for (int k = 0; k < num_point; k++)
  362. {
  363. float kps_x = (feat_kps[k * 3] * 2.f + w) * stride;
  364. float kps_y = (feat_kps[k * 3 + 1] * 2.f + h) * stride;
  365. float kps_s = sigmoid(feat_kps[k * 3 + 2]);
  366. obj.kps_feat.push_back(kps_x);
  367. obj.kps_feat.push_back(kps_y);
  368. obj.kps_feat.push_back(kps_s);
  369. }
  370. objects.push_back(obj);
  371. }
  372. feat_ptr += (cls_num + 4 * reg_max);
  373. feat_kps += 3 * num_point;
  374. }
  375. }
  376. }
  377. static void generate_proposals_yolov8_seg_native(int stride, const float *feat, const float *feat_seg, float prob_threshold, std::vector<Object> &objects,
  378. int letterbox_cols, int letterbox_rows, int cls_num = 80, int mask_proto_dim = 32)
  379. {
  380. int feat_w = letterbox_cols / stride;
  381. int feat_h = letterbox_rows / stride;
  382. int reg_max = 16;
  383. auto feat_ptr = feat;
  384. auto feat_seg_ptr = feat_seg;
  385. std::vector<float> dis_after_sm(reg_max, 0.f);
  386. for (int h = 0; h <= feat_h - 1; h++)
  387. {
  388. for (int w = 0; w <= feat_w - 1; w++)
  389. {
  390. // process cls score
  391. int class_index = 0;
  392. float class_score = -FLT_MAX;
  393. for (int s = 0; s < cls_num; s++)
  394. {
  395. float score = feat_ptr[s + 4 * reg_max];
  396. if (score > class_score)
  397. {
  398. class_index = s;
  399. class_score = score;
  400. }
  401. }
  402. float box_prob = sigmoid(class_score);
  403. if (box_prob > prob_threshold)
  404. {
  405. float pred_ltrb[4];
  406. for (int k = 0; k < 4; k++)
  407. {
  408. float dis = softmax(feat_ptr + k * reg_max, dis_after_sm.data(), reg_max);
  409. pred_ltrb[k] = dis * stride;
  410. }
  411. float pb_cx = (w + 0.5f) * stride;
  412. float pb_cy = (h + 0.5f) * stride;
  413. float x0 = pb_cx - pred_ltrb[0];
  414. float y0 = pb_cy - pred_ltrb[1];
  415. float x1 = pb_cx + pred_ltrb[2];
  416. float y1 = pb_cy + pred_ltrb[3];
  417. x0 = std::max(std::min(x0, (float)(letterbox_cols - 1)), 0.f);
  418. y0 = std::max(std::min(y0, (float)(letterbox_rows - 1)), 0.f);
  419. x1 = std::max(std::min(x1, (float)(letterbox_cols - 1)), 0.f);
  420. y1 = std::max(std::min(y1, (float)(letterbox_rows - 1)), 0.f);
  421. Object obj;
  422. obj.rect.x = x0;
  423. obj.rect.y = y0;
  424. obj.rect.width = x1 - x0;
  425. obj.rect.height = y1 - y0;
  426. obj.label = class_index;
  427. obj.prob = box_prob;
  428. obj.mask_feat.resize(mask_proto_dim);
  429. memcpy(obj.mask_feat.data(), feat_seg_ptr, sizeof(float) * mask_proto_dim);
  430. // for (int k = 0; k < mask_proto_dim; k++)
  431. // {
  432. // obj.mask_feat[k] = feat_seg_ptr[k];
  433. // }
  434. objects.push_back(obj);
  435. }
  436. feat_ptr += cls_num + 4 * reg_max;
  437. feat_seg_ptr += mask_proto_dim;
  438. }
  439. }
  440. }
  441. void get_out_bbox_mask(std::vector<Object> &proposals, std::vector<Object> &objects, const float *mask_proto, int mask_proto_dim, int mask_stride, const float nms_threshold, int letterbox_rows, int letterbox_cols, int src_rows, int src_cols)
  442. {
  443. qsort_descent_inplace(proposals);
  444. std::vector<int> picked;
  445. nms_sorted_bboxes(proposals, picked, nms_threshold);
  446. /* yolov5 draw the result */
  447. float scale_letterbox;
  448. int resize_rows;
  449. int resize_cols;
  450. if ((letterbox_rows * 1.0 / src_rows) < (letterbox_cols * 1.0 / src_cols))
  451. {
  452. scale_letterbox = letterbox_rows * 1.0 / src_rows;
  453. }
  454. else
  455. {
  456. scale_letterbox = letterbox_cols * 1.0 / src_cols;
  457. }
  458. resize_cols = int(scale_letterbox * src_cols);
  459. resize_rows = int(scale_letterbox * src_rows);
  460. int tmp_h = (letterbox_rows - resize_rows) / 2;
  461. int tmp_w = (letterbox_cols - resize_cols) / 2;
  462. float ratio_x = (float)src_rows / resize_rows;
  463. float ratio_y = (float)src_cols / resize_cols;
  464. int mask_proto_h = int(letterbox_rows / mask_stride);
  465. int mask_proto_w = int(letterbox_cols / mask_stride);
  466. int count = picked.size();
  467. objects.resize(count);
  468. for (int i = 0; i < count; i++)
  469. {
  470. objects[i] = proposals[picked[i]];
  471. float x0 = (objects[i].rect.x);
  472. float y0 = (objects[i].rect.y);
  473. float x1 = (objects[i].rect.x + objects[i].rect.width);
  474. float y1 = (objects[i].rect.y + objects[i].rect.height);
  475. /* naive RoiAlign by opencv */
  476. int hstart = std::floor(objects[i].rect.y / mask_stride);
  477. int hend = std::ceil(objects[i].rect.y / mask_stride + objects[i].rect.height / mask_stride);
  478. int wstart = std::floor(objects[i].rect.x / mask_stride);
  479. int wend = std::ceil(objects[i].rect.x / mask_stride + objects[i].rect.width / mask_stride);
  480. hstart = std::min(std::max(hstart, 0), mask_proto_h);
  481. wstart = std::min(std::max(wstart, 0), mask_proto_w);
  482. hend = std::min(std::max(hend, 0), mask_proto_h);
  483. wend = std::min(std::max(wend, 0), mask_proto_w);
  484. int mask_w = wend - wstart;
  485. int mask_h = hend - hstart;
  486. cv::Mat mask = cv::Mat(mask_h, mask_w, CV_32FC1);
  487. if (mask_w > 0 && mask_h > 0)
  488. {
  489. std::vector<cv::Range> roi_ranges;
  490. roi_ranges.push_back(cv::Range(0, 1));
  491. roi_ranges.push_back(cv::Range::all());
  492. roi_ranges.push_back(cv::Range(hstart, hend));
  493. roi_ranges.push_back(cv::Range(wstart, wend));
  494. cv::Mat mask_protos = cv::Mat(mask_proto_dim, mask_proto_h * mask_proto_w, CV_32FC1, (float *)mask_proto);
  495. int sz[] = {1, mask_proto_dim, mask_proto_h, mask_proto_w};
  496. cv::Mat mask_protos_reshape = mask_protos.reshape(1, 4, sz);
  497. cv::Mat protos = mask_protos_reshape(roi_ranges).clone().reshape(0, {mask_proto_dim, mask_w * mask_h});
  498. cv::Mat mask_proposals = cv::Mat(1, mask_proto_dim, CV_32FC1, (float *)objects[i].mask_feat.data());
  499. cv::Mat masks_feature = (mask_proposals * protos);
  500. /* sigmoid */
  501. cv::exp(-masks_feature.reshape(1, {mask_h, mask_w}), mask);
  502. mask = 1.0 / (1.0 + mask);
  503. }
  504. x0 = (x0 - tmp_w) * ratio_x;
  505. y0 = (y0 - tmp_h) * ratio_y;
  506. x1 = (x1 - tmp_w) * ratio_x;
  507. y1 = (y1 - tmp_h) * ratio_y;
  508. x0 = std::max(std::min(x0, (float)(src_cols - 1)), 0.f);
  509. y0 = std::max(std::min(y0, (float)(src_rows - 1)), 0.f);
  510. x1 = std::max(std::min(x1, (float)(src_cols - 1)), 0.f);
  511. y1 = std::max(std::min(y1, (float)(src_rows - 1)), 0.f);
  512. objects[i].rect.x = x0;
  513. objects[i].rect.y = y0;
  514. objects[i].rect.width = x1 - x0;
  515. objects[i].rect.height = y1 - y0;
  516. cv::resize(mask, mask, cv::Size((int)objects[i].rect.width, (int)objects[i].rect.height));
  517. objects[i].mask = mask > 0.5;
  518. // cv::Mat mask_8bit;
  519. // objects[i].mask.convertTo(mask_8bit, CV_8U, 255.0);
  520. // // 获取当前时间戳
  521. // auto timestamp = std::chrono::system_clock::now();
  522. // auto seconds = std::chrono::duration_cast<std::chrono::seconds>(timestamp.time_since_epoch()).count();
  523. // // 使用时间戳作为文件名
  524. // std::string filename = "output_" + std::to_string(seconds)+"_"+std::to_string(objects[i].label)+ ".jpg";
  525. // // 保存为 JPEG 文件
  526. // cv::imwrite(filename, mask_8bit);
  527. }
  528. }
  529. } // namespace detection