diff --git a/modules/dnn/src/onnx/onnx_importer.cpp b/modules/dnn/src/onnx/onnx_importer.cpp index cc375d28bf..555ff51b93 100644 --- a/modules/dnn/src/onnx/onnx_importer.cpp +++ b/modules/dnn/src/onnx/onnx_importer.cpp @@ -2997,6 +2997,34 @@ void ONNXImporter::parseDepthToSpace(LayerParams& layerParams, const opencv_onnx addLayer(layerParams, node_proto); } +template +Mat runRangeLayer(const Mat& startMat, const Mat& limitMat, const Mat& deltaMat) +{ + T start = startMat.at(0); + T limit = limitMat.at(0); + T delta = deltaMat.at(0); + + int numberOfElements; + if (startMat.depth() == CV_32S || startMat.depth() == CV_64S) { + if (delta > 0) + numberOfElements = (limit - start + delta - 1) / delta; + else + numberOfElements = (start - limit - delta - 1) / -delta; + } + else + { + numberOfElements = std::ceil((limit - start) / delta); + } + numberOfElements = std::max(numberOfElements, 0); + + Mat r(std::vector{numberOfElements}, startMat.type()); + for (int i = 0; i < numberOfElements; i++) + { + r.at(i) = start + (i * delta); + } + return r; +} + // Currently we only support range with all constant inputs void ONNXImporter::parseRange(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto) { @@ -3011,25 +3039,27 @@ void ONNXImporter::parseRange(LayerParams& layerParams, const opencv_onnx::NodeP // only supports the case which all inputs are constant CV_Assert(const_id.size() == 3); - Mat startMat = getIntBlob(node_proto, 0); - CV_Assert(startMat.type() == CV_32SC1); - int start = startMat.at(0); + Mat startMat = getBlob(node_proto, 0); + Mat limitMat = getBlob(node_proto, 1); + Mat deltaMat = getBlob(node_proto, 2); - Mat limitMat = getIntBlob(node_proto, 1); - CV_Assert(limitMat.type() == CV_32SC1); - int limit = limitMat.at(0); - - Mat deltaMat = getIntBlob(node_proto, 2); - CV_Assert(deltaMat.type() == CV_32SC1); - int delta = deltaMat.at(0); - - int number_of_elements = std::max(int(std::ceil((limit - start) / delta)), 0); - Mat r(number_of_elements, 1, CV_32SC1); - for (int i = 0; i < number_of_elements; i++) + Mat result; + switch (startMat.depth()) { - r.at(i) = start + (i * delta); - } - addConstant(node_proto.output(0), r); + case CV_32F: + result = runRangeLayer(startMat, limitMat, deltaMat); + break; + case CV_32S: + result = runRangeLayer(startMat, limitMat, deltaMat); + break; + case CV_64S: + result = runRangeLayer(startMat, limitMat, deltaMat); + break; + default: + CV_Error(cv::Error::BadDepth, "Unsupported type."); + }; + + addConstant(node_proto.output(0), result); constBlobsExtraInfo.insert(std::make_pair(node_proto.output(0), TensorInfo(1))); } diff --git a/modules/dnn/test/test_onnx_importer.cpp b/modules/dnn/test/test_onnx_importer.cpp index 441ed4ea1f..99bb789fb7 100644 --- a/modules/dnn/test/test_onnx_importer.cpp +++ b/modules/dnn/test/test_onnx_importer.cpp @@ -807,14 +807,26 @@ TEST_P(Test_ONNX_layers, CumSumExclusiveInplace) testONNXModels("cumsum_exclusive_inplace"); } -// Issue: https://github.com/opencv/opencv/issues/25363 -// The issue was addressed in 4.x, but the solution does not fit 5.x design -TEST_P(Test_ONNX_layers, DISABLED_Range) +TEST_P(Test_ONNX_layers, RangeFloat) { testONNXModels("range_float"); testONNXModels("range_float_negative"); } +TEST_P(Test_ONNX_layers, RangeInt32) +{ + testONNXModels("range_int32"); + testONNXModels("range_int32_negative"); +} + +TEST_P(Test_ONNX_layers, RangeInt64) +{ + if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) + applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); // OpenVINO uses int32 precision for int64 operations + testONNXModels("range_int64"); + testONNXModels("range_int64_negative"); +} + TEST_P(Test_ONNX_layers, Eltwise3D) { #if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2021040000)