1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Merge pull request #28749 from Prasadayus:NMS-empty-detection-fix

Nms empty detection fix #28749

Requires opencv_extra: https://github.com/opencv/opencv_extra/pull/1330

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Prasad Ayush Kumar
2026-04-02 21:07:23 +05:30
committed by GitHub
parent e59506bbf5
commit 47ac80995f
6 changed files with 51 additions and 1 deletions
+2
View File
@@ -867,6 +867,8 @@ void broadcast(InputArray _src, InputArray _shape, OutputArray _dst) {
// impl
_dst.create(dims_shape, shape.ptr<int>(), src.type());
Mat dst = _dst.getMat();
if (dst.total() == 0)
return;
std::vector<int> is_same_shape(dims_shape, 0);
for (int i = 0; i < static_cast<int>(shape_src.size()); ++i) {
if (shape_src[i] == ptr_shape[i]) {
+10
View File
@@ -311,20 +311,30 @@ void reshapeAndCopyFirst(InputArrayOfArrays inputs,
int inpType = inputs.type(0);
if (inpKind == _InputArray::STD_VECTOR_MAT) {
Mat inp = inputs.getMat(0);
MatShape inpShape = inp.shape();
const size_t inpTotal = inpShape.total();
const size_t outTotal = shape.total();
std::vector<Mat>& outref = outputs.getMatVecRef();
outref.resize(1);
outref[0].fit(shape, inpType);
CV_Assert(outref[0].isContinuous());
if (inpTotal == 0 && outTotal == 0)
return;
Mat inp_ = inp.reshape(0, shape);
if (inp_.data != outref[0].data)
inp_.copyTo(outref[0]);
}
else {
UMat inp = inputs.getUMat(0);
MatShape inpShape = inputs.shape(0);
const size_t inpTotal = inpShape.total();
const size_t outTotal = shape.total();
std::vector<UMat>& outref = outputs.getUMatVecRef();
outref.resize(1);
outref[0].fit(shape, inpType);
CV_Assert(outref[0].isContinuous());
if (inpTotal == 0 && outTotal == 0)
return;
UMat inp_ = inp.reshape(0, shape);
inp_.copyTo(outref[0]);
}
@@ -129,6 +129,11 @@ public:
outMat = outputs_arr.getMatRef(0);
}
if (K == 0)
{
return;
}
auto* out = outMat.ptr<int64_t>();
std::vector<int> offsets(tasks + 1, 0);
for (int t = 0; t < tasks; ++t)
+1 -1
View File
@@ -1147,7 +1147,7 @@ void Net::Impl::forwardGraph(Ptr<Graph>& graph, InputArrayOfArrays inputs_,
buf.type() == m.type(),
(!m.u || m.u->data == outOrigData[i].first),
(!m.u || m.u->size == outOrigData[i].second));
} else if (!buf.u || m.u->size > buf.u->size) {
} else if (!buf.u || (m.u && m.u->size > buf.u->size)) {
buf = m;
} else {
// this branch means that the layer still calls
+4
View File
@@ -2641,6 +2641,10 @@ void ONNXImporter2::parseAttentionOnnxAi(LayerParams& params, const opencv_onnx:
void ONNXImporter2::parseRoiAlign(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
{
layerParams.type = "RoiAlign";
if (!layerParams.has("coordinate_transformation_mode")) {
int onnx_opset = onnx_opset_map.count(str_domain_ai_onnx) ? onnx_opset_map.at(str_domain_ai_onnx) : 16;
layerParams.set("coordinate_transformation_mode", onnx_opset < 16 ? "output_half_pixel" : "half_pixel");
}
addLayer(layerParams, node_proto, 3);
}
+29
View File
@@ -6,6 +6,7 @@
// Third party copyrights are property of their respective owners.
#include "test_precomp.hpp"
#include "npy_blob.hpp"
namespace opencv_test { namespace {
@@ -104,4 +105,32 @@ TEST(SoftNMS, Accuracy)
}
}
// Test NMS -> Reshape with zero detections using ONNX model.
// NMS with dynamic output shapes is only supported by the new engine.
TEST(NMS, ZeroDetections_Reshape)
{
auto engine_forced = static_cast<cv::dnn::EngineType>(
cv::utils::getConfigurationParameterSizeT("OPENCV_FORCE_DNN_ENGINE", cv::dnn::ENGINE_AUTO));
if (engine_forced == cv::dnn::ENGINE_CLASSIC)
{
applyTestTag(CV_TEST_TAG_DNN_SKIP_PARSER);
return;
}
std::string onnxmodel = findDataFile("dnn/onnx/models/nms_reshape_empty.onnx");
cv::dnn::Net net = cv::dnn::readNetFromONNX(onnxmodel);
ASSERT_FALSE(net.empty());
Mat boxes = blobFromNPY(findDataFile("dnn/onnx/data/input_nms_reshape_empty_0.npy"));
Mat scores = blobFromNPY(findDataFile("dnn/onnx/data/input_nms_reshape_empty_1.npy"));
net.setInput(boxes, "boxes");
net.setInput(scores, "scores");
std::vector<Mat> outs;
net.forward(outs, std::vector<String>{"output"});
ASSERT_EQ(outs.size(), (size_t)1);
Mat ref = blobFromNPY(findDataFile("dnn/onnx/data/output_nms_reshape_empty.npy"));
normAssert(ref, outs[0], "NMS_ZeroDetections_Reshape");
}
}} // namespace