From: fengyuentau Date: Thu, 24 Nov 2022 02:20:04 +0000 (+0800) Subject: batched nms impl X-Git-Tag: accepted/tizen/unified/20230127.161057~1^2~69^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9fded9ca537e3022b361fd8eaed10dd5d4ffe103;p=platform%2Fupstream%2Fopencv.git batched nms impl --- diff --git a/modules/dnn/include/opencv2/dnn/dnn.hpp b/modules/dnn/include/opencv2/dnn/dnn.hpp index 29d6cfa..affcf78 100644 --- a/modules/dnn/include/opencv2/dnn/dnn.hpp +++ b/modules/dnn/include/opencv2/dnn/dnn.hpp @@ -1194,6 +1194,27 @@ CV__DNN_INLINE_NS_BEGIN CV_OUT std::vector& indices, const float eta = 1.f, const int top_k = 0); + /** @brief Performs batched non maximum suppression on given boxes and corresponding scores across different classes. + + * @param bboxes a set of bounding boxes to apply NMS. + * @param scores a set of corresponding confidences. + * @param class_ids a set of corresponding class ids. Ids are integer and usually start from 0. + * @param score_threshold a threshold used to filter boxes by score. + * @param nms_threshold a threshold used in non maximum suppression. + * @param indices the kept indices of bboxes after NMS. + * @param eta a coefficient in adaptive threshold formula: \f$nms\_threshold_{i+1}=eta\cdot nms\_threshold_i\f$. + * @param top_k if `>0`, keep at most @p top_k picked indices. + */ + CV_EXPORTS void NMSBoxesBatched(const std::vector& bboxes, const std::vector& scores, const std::vector& class_ids, + const float score_threshold, const float nms_threshold, + CV_OUT std::vector& indices, + const float eta = 1.f, const int top_k = 0); + + CV_EXPORTS_W void NMSBoxesBatched(const std::vector& bboxes, const std::vector& scores, const std::vector& class_ids, + const float score_threshold, const float nms_threshold, + CV_OUT std::vector& indices, + const float eta = 1.f, const int top_k = 0); + /** * @brief Enum of Soft NMS methods. * @see softNMSBoxes diff --git a/modules/dnn/src/nms.cpp b/modules/dnn/src/nms.cpp index d321cfe..c51a630 100644 --- a/modules/dnn/src/nms.cpp +++ b/modules/dnn/src/nms.cpp @@ -58,6 +58,61 @@ void NMSBoxes(const std::vector& bboxes, const std::vector& NMSFast_(bboxes, scores, score_threshold, nms_threshold, eta, top_k, indices, rotatedRectIOU); } +template +static inline void NMSBoxesBatchedImpl(const std::vector& bboxes, + const std::vector& scores, const std::vector& class_ids, + const float score_threshold, const float nms_threshold, + std::vector& indices, const float eta, const int top_k) +{ + double x1, y1, x2, y2, max_coord = 0; + for (int i = 0; i < bboxes.size(); i++) + { + x1 = bboxes[i].x; + y1 = bboxes[i].y; + x2 = x1 + bboxes[i].width; + y2 = y1 + bboxes[i].height; + + max_coord = std::max(x1, max_coord); + max_coord = std::max(y1, max_coord); + max_coord = std::max(x2, max_coord); + max_coord = std::max(y2, max_coord); + } + + // calculate offset and add offset to each bbox + std::vector bboxes_offset; + double offset; + for (int i = 0; i < bboxes.size(); i++) + { + offset = class_ids[i] * (max_coord + 1); + bboxes_offset.push_back( + Rect_t(bboxes[i].x + offset, bboxes[i].y + offset, + bboxes[i].width, bboxes[i].height) + ); + } + + NMSFast_(bboxes_offset, scores, score_threshold, nms_threshold, eta, top_k, indices, rectOverlap); +} + +void NMSBoxesBatched(const std::vector& bboxes, + const std::vector& scores, const std::vector& class_ids, + const float score_threshold, const float nms_threshold, + std::vector& indices, const float eta, const int top_k) +{ + CV_Assert_N(bboxes.size() == scores.size(), scores.size() == class_ids.size(), nms_threshold >= 0, eta > 0); + + NMSBoxesBatchedImpl(bboxes, scores, class_ids, score_threshold, nms_threshold, indices, eta, top_k); +} + +void NMSBoxesBatched(const std::vector& bboxes, + const std::vector& scores, const std::vector& class_ids, + const float score_threshold, const float nms_threshold, + std::vector& indices, const float eta, const int top_k) +{ + CV_Assert_N(bboxes.size() == scores.size(), scores.size() == class_ids.size(), nms_threshold >= 0, eta > 0); + + NMSBoxesBatchedImpl(bboxes, scores, class_ids, score_threshold, nms_threshold, indices, eta, top_k); +} + void softNMSBoxes(const std::vector& bboxes, const std::vector& scores, std::vector& updated_scores, diff --git a/modules/dnn/test/test_nms.cpp b/modules/dnn/test/test_nms.cpp index 5ba2402..6149125 100644 --- a/modules/dnn/test/test_nms.cpp +++ b/modules/dnn/test/test_nms.cpp @@ -37,6 +37,36 @@ TEST(NMS, Accuracy) ASSERT_EQ(indices[i], ref_indices[i]); } +TEST(BatchedNMS, Accuracy) +{ + //reference results obtained using tf.image.non_max_suppression with iou_threshold=0.5 + std::string dataPath = findDataFile("dnn/batched_nms_reference.yml"); + FileStorage fs(dataPath, FileStorage::READ); + + std::vector bboxes; + std::vector scores; + std::vector idxs; + std::vector ref_indices; + + fs["boxes"] >> bboxes; + fs["probs"] >> scores; + fs["idxs"] >> idxs; + fs["output"] >> ref_indices; + + const float nms_thresh = .5f; + const float score_thresh = .05f; + std::vector indices; + cv::dnn::NMSBoxesBatched(bboxes, scores, idxs, score_thresh, nms_thresh, indices); + + ASSERT_EQ(ref_indices.size(), indices.size()); + + std::sort(indices.begin(), indices.end()); + std::sort(ref_indices.begin(), ref_indices.end()); + + for(size_t i = 0; i < indices.size(); i++) + ASSERT_EQ(indices[i], ref_indices[i]); +} + TEST(SoftNMS, Accuracy) { //reference results are obtained using TF v2.7 tf.image.non_max_suppression_with_scores