tea_detect.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. #include "tea_detect.h"
  2. #include <opencv.hpp>
  3. #include <numeric>
  4. using namespace cv;
  5. using namespace std;
  6. namespace graft_cv {
  7. RetinaDrop::RetinaDrop(CGcvLogger* pLogger, float obj_th, float nms_th)
  8. :m_model_loaded(false)
  9. {
  10. BATCH_SIZE = 1;
  11. INPUT_CHANNEL = 3;
  12. IMAGE_WIDTH = 640; // default 640
  13. IMAGE_HEIGHT = 640; // default 640
  14. m_obj_threshold = obj_th;//default 0.6;
  15. m_nms_threshold = nms_th; //default0.4;
  16. m_anchor_num = 2;
  17. m_bbox_head = 4;
  18. m_variance[0] = 0.1f;
  19. m_variance[1] = 0.2f;
  20. //m_img_mean(123.0, 104.0, 117.0)
  21. m_img_mean[0] = 123.0;
  22. m_img_mean[1] = 104.0;
  23. m_img_mean[2] = 117.0;
  24. m_img_mean[3] = 0;
  25. //cv::Size size_detection(640, 640)
  26. m_size_detection.width = IMAGE_WIDTH;
  27. m_size_detection.height = IMAGE_HEIGHT;
  28. m_feature_steps = {8,16,32};
  29. m_pLogger = pLogger;
  30. for (const int step : m_feature_steps) {
  31. assert(step != 0);
  32. int feature_map = IMAGE_HEIGHT / step;
  33. m_feature_maps.push_back(feature_map);
  34. int feature_size = feature_map * feature_map;
  35. m_feature_sizes.push_back(feature_size);
  36. }
  37. m_anchor_sizes = { { 16,32 } ,{ 64,128},{ 256, 512 }};
  38. m_sum_of_feature = std::accumulate(m_feature_sizes.begin(), m_feature_sizes.end(), 0) * m_anchor_num;
  39. generate_anchors();
  40. if (m_pLogger) {
  41. m_pLogger->INFO(string("RetinaDrop object initialized"));
  42. }
  43. }
  44. RetinaDrop::~RetinaDrop() = default;
  45. bool RetinaDrop::IsModelLoaded() {
  46. return m_model_loaded;
  47. };
  48. void RetinaDrop::SetThreshold(float object_threshold, float nms_threshold)
  49. {
  50. this->m_obj_threshold = object_threshold;
  51. this->m_nms_threshold = nms_threshold;
  52. }
  53. bool RetinaDrop::LoadModel(std::string onnx_path) {
  54. if (m_pLogger) {
  55. m_pLogger->INFO(string("Loading detection model: ")+onnx_path);
  56. }
  57. else { std::cout << "Loading detection model: " << onnx_path<<std::endl; }
  58. try {
  59. m_model = cv::dnn::readNetFromONNX(onnx_path);
  60. if (m_pLogger) {m_pLogger->INFO(string("Detection model loaded"));}
  61. m_model_loaded = true;
  62. return m_model_loaded;
  63. }
  64. catch (...)
  65. {
  66. if (m_pLogger) { m_pLogger->ERRORINFO(string("loading model failed")); }
  67. }
  68. return false;
  69. }
  70. std::vector<Bbox> RetinaDrop::RunModel(cv::Mat& img, CGcvLogger* pInstanceLogger)
  71. {
  72. std::vector<Bbox> result;
  73. if (img.empty()) {
  74. if (pInstanceLogger) {
  75. pInstanceLogger->ERRORINFO(string("RunModel(), input image is empty"));
  76. }
  77. throw(string("image is empty"));
  78. }
  79. if (!m_model_loaded) {
  80. pInstanceLogger->ERRORINFO(string("model is NOT loaded"));
  81. }
  82. cv::Mat blob = cv::dnn::blobFromImage(
  83. img,
  84. 1.0,
  85. m_size_detection,
  86. m_img_mean);
  87. m_model.setInput(blob);
  88. std::vector<std::string> outNames = m_model.getUnconnectedOutLayersNames();
  89. vector<Mat>outputs;// location(1x16800x4), confidence(1x16800x2), keypoint(1x16800x2)
  90. if (pInstanceLogger) {
  91. pInstanceLogger->INFO(string("RunModel(), before forward()"));
  92. }
  93. m_model.forward(outputs, outNames);
  94. std::vector<RetinaDrop::DropRes> rects;
  95. int n = post_process(img, outputs,rects);
  96. for (const auto& rect : rects) {
  97. Bbox box;
  98. box.score = rect.confidence;
  99. box.x1 = (int)rect.drop_box.x1;
  100. box.y1 = (int)rect.drop_box.y1;
  101. box.x2 = (int)rect.drop_box.x2;
  102. box.y2 = (int)rect.drop_box.y2;
  103. box.ppoint[0] = rect.keypoints[0].x;
  104. box.ppoint[1] = rect.keypoints[0].y;
  105. box.ppoint[2] = rect.keypoints[1].x;
  106. box.ppoint[3] = rect.keypoints[1].y;
  107. box.ppoint[4] = rect.keypoints[2].x;
  108. box.ppoint[5] = rect.keypoints[2].y;
  109. box.ppoint[6] = rect.keypoints[3].x;
  110. box.ppoint[7] = rect.keypoints[3].y;
  111. box.ppoint[8] = rect.keypoints[4].x;
  112. box.ppoint[9] = rect.keypoints[4].y;
  113. box.operate_point[0] = 0.0;
  114. box.operate_point[1] = 0.0;
  115. box.operate_angle = 0.0;
  116. box.area = 0.0;
  117. box.status = 0;
  118. result.push_back(box);
  119. }
  120. if (pInstanceLogger) {
  121. stringstream buff;
  122. buff << "detected object: " << n;
  123. pInstanceLogger->INFO(buff.str());
  124. }
  125. return result;
  126. }
  127. void RetinaDrop::generate_anchors() {
  128. m_refer_matrix = cv::Mat(m_sum_of_feature, m_bbox_head, CV_32FC1);
  129. int line = 0;
  130. for (size_t feature_map = 0; feature_map < m_feature_maps.size(); feature_map++) {
  131. for (int height = 0; height < m_feature_maps[feature_map]; ++height) {
  132. for (int width = 0; width < m_feature_maps[feature_map]; ++width) {
  133. for (int anchor = 0; anchor < m_anchor_sizes[feature_map].size(); ++anchor) {
  134. auto* row = m_refer_matrix.ptr<float>(line);
  135. row[0] = (float)(width+0.5) * m_feature_steps[feature_map]/(float)IMAGE_WIDTH;
  136. row[1] = (float)(height+0.5) * m_feature_steps[feature_map]/(float)IMAGE_HEIGHT;
  137. row[2] = m_anchor_sizes[feature_map][anchor]/(float)IMAGE_WIDTH;
  138. row[3] = m_anchor_sizes[feature_map][anchor]/(float)IMAGE_HEIGHT;
  139. line++;
  140. }
  141. }
  142. }
  143. }
  144. }
  145. int RetinaDrop::post_process(
  146. cv::Mat &src_img,
  147. vector<cv::Mat> &result_matrix,
  148. std::vector<RetinaDrop::DropRes>& valid_result
  149. )
  150. {
  151. valid_result.clear();
  152. std::vector<DropRes> result;
  153. for (int item = 0; item < m_sum_of_feature; ++item) {
  154. float* cur_bbox = (float*)result_matrix[0].data + item * 4;//result_matrix[0].step;
  155. float* cur_conf = (float*)result_matrix[2].data + item * 2;//result_matrix[1].step;
  156. float* cur_keyp = (float*)result_matrix[1].data + item * 10;//result_matrix[2].step;
  157. if (cur_conf[1] > m_obj_threshold) {
  158. DropRes headbox;
  159. headbox.confidence = cur_conf[1];
  160. auto* anchor = m_refer_matrix.ptr<float>(item);
  161. auto* keyp = cur_keyp;
  162. float cx, cy, kx, ky;
  163. cx = anchor[0] + cur_bbox[0] * m_variance[0] * anchor[2];
  164. cy = anchor[1] + cur_bbox[1] * m_variance[0] * anchor[3];
  165. kx = anchor[2] * exp(cur_bbox[2] * m_variance[1]);
  166. ky = anchor[3] * exp(cur_bbox[3] * m_variance[1]);
  167. cx -= kx / 2.0f;
  168. cy -= ky / 2.0f;
  169. kx += cx;
  170. ky += cy;
  171. headbox.drop_box.x1 = cx * src_img.cols;
  172. headbox.drop_box.y1 = cy * src_img.rows;
  173. headbox.drop_box.x2 = kx * src_img.cols;
  174. headbox.drop_box.y2 = ky * src_img.rows;
  175. for (int ki = 0; ki < 5; ++ki) {
  176. float kp_x = anchor[0] + keyp[2*ki] * m_variance[0] * anchor[2];
  177. float kp_y = anchor[1] + keyp[2*ki+1] * m_variance[0] * anchor[3];
  178. kp_x *= src_img.cols;
  179. kp_y *= src_img.rows;
  180. headbox.keypoints.push_back(cv::Point2f(kp_x, kp_y));
  181. }
  182. /*float kp_x = anchor[0] + keyp[0] * m_variance[0] * anchor[2];
  183. float kp_y = anchor[1] + keyp[1] * m_variance[0] * anchor[3];
  184. kp_x *= src_img.cols;
  185. kp_y *= src_img.rows;
  186. headbox.keypoints = {
  187. cv::Point2f(kp_x,kp_y)
  188. };*/
  189. result.push_back(headbox);
  190. }
  191. }
  192. vector<int> keep;
  193. nms_detect(result,keep);
  194. for (size_t i = 0; i < keep.size(); ++i) {
  195. valid_result.push_back(result[keep[i]]);
  196. }
  197. return (int)valid_result.size();
  198. }
  199. void RetinaDrop::nms_detect(
  200. std::vector<DropRes> & detections,
  201. vector<int> & keep)
  202. {
  203. keep.clear();
  204. if (detections.size() == 1) {
  205. keep.push_back(0);
  206. return;
  207. }
  208. sort(detections.begin(), detections.end(),
  209. [=](const DropRes& left, const DropRes& right) {
  210. return left.confidence > right.confidence;
  211. });
  212. vector<int> order;
  213. for (size_t i = 0; i < detections.size(); ++i) { order.push_back((int)i); }
  214. while (order.size()) {
  215. int i = order[0];
  216. keep.push_back(i);
  217. vector<int> del_idx;
  218. for (size_t j = 1; j < order.size(); ++j) {
  219. float iou = iou_calculate(
  220. detections[i].drop_box,
  221. detections[order[j]].drop_box);
  222. if (iou > m_nms_threshold) {
  223. del_idx.push_back((int)j);
  224. }
  225. }
  226. vector<int> order_update;
  227. for (size_t j = 1; j < order.size(); ++j) {
  228. vector<int>::iterator it = find(del_idx.begin(), del_idx.end(), j);
  229. if (it == del_idx.end()) {
  230. order_update.push_back(order[j]);
  231. }
  232. }
  233. order.clear();
  234. order.assign(order_update.begin(), order_update.end());
  235. }
  236. }
  237. float RetinaDrop::iou_calculate(
  238. const RetinaDrop::DropBox & det_a,
  239. const RetinaDrop::DropBox & det_b)
  240. {
  241. float aa = (det_a.x2 - det_a.x1 + 1) * (det_a.y2 - det_a.y1 + 1);
  242. float ab = (det_b.x2 - det_b.x1 + 1) * (det_b.y2 - det_b.y1 + 1);
  243. float xx1 = max(det_a.x1, det_b.x1);
  244. float yy1 = max(det_a.y1, det_b.y1);
  245. float xx2 = min(det_a.x2, det_b.x2);
  246. float yy2 = min(det_a.y2, det_b.y2);
  247. float w = (float)max(0.0, xx2 - xx1 + 1.0);
  248. float h = (float)max(0.0, yy2 - yy1 + 1.0);
  249. float inter = w * h;
  250. float ovr = inter / (aa + ab - inter);
  251. return ovr;
  252. }
  253. float RetinaDrop::GetNmsThreshold() { return m_nms_threshold; }
  254. //////////////////////////////////////////////////////////////////////////////////
  255. //////////////////////////////////////////////////////////////////////////////////
  256. YoloDrop::YoloDrop(CGcvLogger* pLogger, float obj_th, float nms_th)
  257. :m_model_loaded(false)
  258. {
  259. m_infer = Inference(const std::string &onnxModelPath, const cv::Size2f &modelInputShape, const std::string &classesTxtFile, const bool &runWithCuda = true);
  260. BATCH_SIZE = 1;
  261. INPUT_CHANNEL = 3;
  262. IMAGE_WIDTH = 640; // default 640
  263. IMAGE_HEIGHT = 640; // default 640
  264. m_obj_threshold = obj_th;//default 0.6;
  265. m_nms_threshold = nms_th; //default0.4;
  266. m_anchor_num = 2;
  267. m_bbox_head = 4;
  268. m_variance[0] = 0.1f;
  269. m_variance[1] = 0.2f;
  270. //m_img_mean(123.0, 104.0, 117.0)
  271. m_img_mean[0] = 123.0;
  272. m_img_mean[1] = 104.0;
  273. m_img_mean[2] = 117.0;
  274. m_img_mean[3] = 0;
  275. //cv::Size size_detection(640, 640)
  276. m_size_detection.width = IMAGE_WIDTH;
  277. m_size_detection.height = IMAGE_HEIGHT;
  278. m_feature_steps = { 8,16,32 };
  279. m_pLogger = pLogger;
  280. for (const int step : m_feature_steps) {
  281. assert(step != 0);
  282. int feature_map = IMAGE_HEIGHT / step;
  283. m_feature_maps.push_back(feature_map);
  284. int feature_size = feature_map * feature_map;
  285. m_feature_sizes.push_back(feature_size);
  286. }
  287. m_anchor_sizes = { { 16,32 } ,{ 64,128 },{ 256, 512 } };
  288. m_sum_of_feature = std::accumulate(m_feature_sizes.begin(), m_feature_sizes.end(), 0) * m_anchor_num;
  289. generate_anchors();
  290. if (m_pLogger) {
  291. m_pLogger->INFO(string("YoloDrop object initialized"));
  292. }
  293. }
  294. YoloDrop::~YoloDrop() = default;
  295. bool YoloDrop::IsModelLoaded() {
  296. return m_model_loaded;
  297. };
  298. void YoloDrop::SetThreshold(float object_threshold, float nms_threshold)
  299. {
  300. this->m_obj_threshold = object_threshold;
  301. this->m_nms_threshold = nms_threshold;
  302. }
  303. bool YoloDrop::LoadModel(std::string onnx_path) {
  304. if (m_pLogger) {
  305. m_pLogger->INFO(string("Loading detection model: ") + onnx_path);
  306. }
  307. else { std::cout << "Loading detection model: " << onnx_path << std::endl; }
  308. try {
  309. m_model = cv::dnn::readNetFromONNX(onnx_path);
  310. if (m_pLogger) { m_pLogger->INFO(string("Detection model loaded")); }
  311. m_model_loaded = true;
  312. return m_model_loaded;
  313. }
  314. catch (...)
  315. {
  316. if (m_pLogger) { m_pLogger->ERRORINFO(string("loading model failed")); }
  317. }
  318. return false;
  319. }
  320. std::vector<Bbox> YoloDrop::RunModel(cv::Mat& img, CGcvLogger* pInstanceLogger)
  321. {
  322. std::vector<Bbox> result;
  323. if (img.empty()) {
  324. if (pInstanceLogger) {
  325. pInstanceLogger->ERRORINFO(string("RunModel(), input image is empty"));
  326. }
  327. throw(string("image is empty"));
  328. }
  329. if (!m_model_loaded) {
  330. pInstanceLogger->ERRORINFO(string("model is NOT loaded"));
  331. }
  332. cv::Mat blob = cv::dnn::blobFromImage(
  333. img,
  334. 1.0,
  335. m_size_detection,
  336. m_img_mean);
  337. m_model.setInput(blob);
  338. std::vector<std::string> outNames = m_model.getUnconnectedOutLayersNames();
  339. vector<Mat>outputs;// location(1x16800x4), confidence(1x16800x2), keypoint(1x16800x2)
  340. if (pInstanceLogger) {
  341. pInstanceLogger->INFO(string("RunModel(), before forward()"));
  342. }
  343. m_model.forward(outputs, outNames);
  344. std::vector<YoloDrop::DropRes> rects;
  345. int n = post_process(img, outputs, rects);
  346. for (const auto& rect : rects) {
  347. Bbox box;
  348. box.score = rect.confidence;
  349. box.x1 = (int)rect.drop_box.x1;
  350. box.y1 = (int)rect.drop_box.y1;
  351. box.x2 = (int)rect.drop_box.x2;
  352. box.y2 = (int)rect.drop_box.y2;
  353. box.ppoint[0] = rect.keypoints[0].x;
  354. box.ppoint[1] = rect.keypoints[0].y;
  355. box.ppoint[2] = rect.keypoints[1].x;
  356. box.ppoint[3] = rect.keypoints[1].y;
  357. box.ppoint[4] = rect.keypoints[2].x;
  358. box.ppoint[5] = rect.keypoints[2].y;
  359. box.ppoint[6] = rect.keypoints[3].x;
  360. box.ppoint[7] = rect.keypoints[3].y;
  361. box.ppoint[8] = rect.keypoints[4].x;
  362. box.ppoint[9] = rect.keypoints[4].y;
  363. box.operate_point[0] = 0.0;
  364. box.operate_point[1] = 0.0;
  365. box.operate_angle = 0.0;
  366. box.area = 0.0;
  367. box.status = 0;
  368. result.push_back(box);
  369. }
  370. if (pInstanceLogger) {
  371. stringstream buff;
  372. buff << "detected object: " << n;
  373. pInstanceLogger->INFO(buff.str());
  374. }
  375. return result;
  376. }
  377. void YoloDrop::generate_anchors() {
  378. m_refer_matrix = cv::Mat(m_sum_of_feature, m_bbox_head, CV_32FC1);
  379. int line = 0;
  380. for (size_t feature_map = 0; feature_map < m_feature_maps.size(); feature_map++) {
  381. for (int height = 0; height < m_feature_maps[feature_map]; ++height) {
  382. for (int width = 0; width < m_feature_maps[feature_map]; ++width) {
  383. for (int anchor = 0; anchor < m_anchor_sizes[feature_map].size(); ++anchor) {
  384. auto* row = m_refer_matrix.ptr<float>(line);
  385. row[0] = (float)(width + 0.5) * m_feature_steps[feature_map] / (float)IMAGE_WIDTH;
  386. row[1] = (float)(height + 0.5) * m_feature_steps[feature_map] / (float)IMAGE_HEIGHT;
  387. row[2] = m_anchor_sizes[feature_map][anchor] / (float)IMAGE_WIDTH;
  388. row[3] = m_anchor_sizes[feature_map][anchor] / (float)IMAGE_HEIGHT;
  389. line++;
  390. }
  391. }
  392. }
  393. }
  394. }
  395. int YoloDrop::post_process(
  396. cv::Mat &src_img,
  397. vector<cv::Mat> &result_matrix,
  398. std::vector<YoloDrop::DropRes>& valid_result
  399. )
  400. {
  401. valid_result.clear();
  402. std::vector<DropRes> result;
  403. for (int item = 0; item < m_sum_of_feature; ++item) {
  404. float* cur_bbox = (float*)result_matrix[0].data + item * 4;//result_matrix[0].step;
  405. float* cur_conf = (float*)result_matrix[2].data + item * 2;//result_matrix[1].step;
  406. float* cur_keyp = (float*)result_matrix[1].data + item * 10;//result_matrix[2].step;
  407. if (cur_conf[1] > m_obj_threshold) {
  408. DropRes headbox;
  409. headbox.confidence = cur_conf[1];
  410. auto* anchor = m_refer_matrix.ptr<float>(item);
  411. auto* keyp = cur_keyp;
  412. float cx, cy, kx, ky;
  413. cx = anchor[0] + cur_bbox[0] * m_variance[0] * anchor[2];
  414. cy = anchor[1] + cur_bbox[1] * m_variance[0] * anchor[3];
  415. kx = anchor[2] * exp(cur_bbox[2] * m_variance[1]);
  416. ky = anchor[3] * exp(cur_bbox[3] * m_variance[1]);
  417. cx -= kx / 2.0f;
  418. cy -= ky / 2.0f;
  419. kx += cx;
  420. ky += cy;
  421. headbox.drop_box.x1 = cx * src_img.cols;
  422. headbox.drop_box.y1 = cy * src_img.rows;
  423. headbox.drop_box.x2 = kx * src_img.cols;
  424. headbox.drop_box.y2 = ky * src_img.rows;
  425. for (int ki = 0; ki < 5; ++ki) {
  426. float kp_x = anchor[0] + keyp[2 * ki] * m_variance[0] * anchor[2];
  427. float kp_y = anchor[1] + keyp[2 * ki + 1] * m_variance[0] * anchor[3];
  428. kp_x *= src_img.cols;
  429. kp_y *= src_img.rows;
  430. headbox.keypoints.push_back(cv::Point2f(kp_x, kp_y));
  431. }
  432. /*float kp_x = anchor[0] + keyp[0] * m_variance[0] * anchor[2];
  433. float kp_y = anchor[1] + keyp[1] * m_variance[0] * anchor[3];
  434. kp_x *= src_img.cols;
  435. kp_y *= src_img.rows;
  436. headbox.keypoints = {
  437. cv::Point2f(kp_x,kp_y)
  438. };*/
  439. result.push_back(headbox);
  440. }
  441. }
  442. vector<int> keep;
  443. nms_detect(result, keep);
  444. for (size_t i = 0; i < keep.size(); ++i) {
  445. valid_result.push_back(result[keep[i]]);
  446. }
  447. return (int)valid_result.size();
  448. }
  449. void YoloDrop::nms_detect(
  450. std::vector<DropRes> & detections,
  451. vector<int> & keep)
  452. {
  453. keep.clear();
  454. if (detections.size() == 1) {
  455. keep.push_back(0);
  456. return;
  457. }
  458. sort(detections.begin(), detections.end(),
  459. [=](const DropRes& left, const DropRes& right) {
  460. return left.confidence > right.confidence;
  461. });
  462. vector<int> order;
  463. for (size_t i = 0; i < detections.size(); ++i) { order.push_back((int)i); }
  464. while (order.size()) {
  465. int i = order[0];
  466. keep.push_back(i);
  467. vector<int> del_idx;
  468. for (size_t j = 1; j < order.size(); ++j) {
  469. float iou = iou_calculate(
  470. detections[i].drop_box,
  471. detections[order[j]].drop_box);
  472. if (iou > m_nms_threshold) {
  473. del_idx.push_back((int)j);
  474. }
  475. }
  476. vector<int> order_update;
  477. for (size_t j = 1; j < order.size(); ++j) {
  478. vector<int>::iterator it = find(del_idx.begin(), del_idx.end(), j);
  479. if (it == del_idx.end()) {
  480. order_update.push_back(order[j]);
  481. }
  482. }
  483. order.clear();
  484. order.assign(order_update.begin(), order_update.end());
  485. }
  486. }
  487. float YoloDrop::iou_calculate(
  488. const YoloDrop::DropBox & det_a,
  489. const YoloDrop::DropBox & det_b)
  490. {
  491. float aa = (det_a.x2 - det_a.x1 + 1) * (det_a.y2 - det_a.y1 + 1);
  492. float ab = (det_b.x2 - det_b.x1 + 1) * (det_b.y2 - det_b.y1 + 1);
  493. float xx1 = max(det_a.x1, det_b.x1);
  494. float yy1 = max(det_a.y1, det_b.y1);
  495. float xx2 = min(det_a.x2, det_b.x2);
  496. float yy2 = min(det_a.y2, det_b.y2);
  497. float w = (float)max(0.0, xx2 - xx1 + 1.0);
  498. float h = (float)max(0.0, yy2 - yy1 + 1.0);
  499. float inter = w * h;
  500. float ovr = inter / (aa + ab - inter);
  501. return ovr;
  502. }
  503. float YoloDrop::GetNmsThreshold() { return m_nms_threshold; }
  504. }