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

Merge pull request #28121 from abhishek-gola:loop_layer_add

Add Loop layer to new DNN engine #28121

Addition of loop layer in 5.x for issue: https://github.com/opencv/opencv/issues/26179 and https://github.com/opencv/opencv/issues/26141 and https://github.com/opencv/opencv/issues/25200

OpenCV Extra: https://github.com/opencv/opencv_extra/pull/1335

### 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:
Abhishek Gola
2026-04-14 11:45:46 +05:30
committed by GitHub
parent 3d77645a3a
commit de851d24a5
14 changed files with 393 additions and 32 deletions
+113
View File
@@ -978,4 +978,117 @@ TEST_P(Reproducibility_ResNet50_QDQ_ONNX, Accuracy)
INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_ResNet50_QDQ_ONNX,
testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV)));
typedef testing::TestWithParam<Target> Reproducibility_MobileNetSSD_ONNX;
TEST_P(Reproducibility_MobileNetSSD_ONNX, Accuracy)
{
Target targetId = GetParam();
auto engine_forced = static_cast<EngineType>(
cv::utils::getConfigurationParameterSizeT("OPENCV_FORCE_DNN_ENGINE", ENGINE_AUTO));
if (engine_forced == ENGINE_CLASSIC)
{
applyTestTag(CV_TEST_TAG_DNN_SKIP_PARSER);
return;
}
applyTestTag(targetId == DNN_TARGET_CPU ? CV_TEST_TAG_MEMORY_512MB : CV_TEST_TAG_MEMORY_1GB);
ASSERT_TRUE(ocl::useOpenCL() || targetId == DNN_TARGET_CPU || targetId == DNN_TARGET_CPU_FP16);
std::string modelname = _tf("onnx/models/ssd_mobilenet_v1_12.onnx", false);
Net net = readNetFromONNX(modelname);
net.setPreferableBackend(DNN_BACKEND_OPENCV);
net.setPreferableTarget(targetId);
if (targetId == DNN_TARGET_CPU_FP16)
net.enableWinograd(false);
std::string imgname = _tf("dog_orig_size.png");
Mat image = imread(imgname);
ASSERT_TRUE(!image.empty());
Mat input;
resize(image, input, Size(300, 300));
int imsize[] = {1, input.rows, input.cols, 3};
Mat input8dim4(4, imsize, CV_8U, input.data);
std::vector<String> outNames = net.getUnconnectedOutLayersNames();
std::vector<Mat> outs;
double min_t = 0;
const int niters =
#ifdef _DEBUG
1;
#else
30;
#endif
for (int i = 0; i < niters; i++) {
double t = (double)getTickCount();
net.setInput(input8dim4);
net.forward(outs, outNames);
t = (double)getTickCount() - t;
min_t = i == 0 ? t : std::min(min_t, t);
}
printf("run time = %.2fms\n", min_t*1000./getTickFrequency());
// Model outputs: detection_boxes [1,N,4], detection_classes [1,N],
// detection_scores [1,N], num_detections [1]
ASSERT_EQ(outs.size(), (size_t)4);
Mat boxes, classes, scores, numDet;
for (size_t i = 0; i < outs.size(); i++) {
if (outs[i].dims == 3 && outs[i].size[2] == 4)
boxes = outs[i];
else if (outs[i].total() == 1)
numDet = outs[i];
else if (outs[i].dims == 2) {
float first = outs[i].at<float>(0, 0);
if (first == std::round(first) && first > 0)
classes = outs[i];
else
scores = outs[i];
}
}
ASSERT_FALSE(boxes.empty());
ASSERT_FALSE(scores.empty());
ASSERT_FALSE(classes.empty());
ASSERT_FALSE(numDet.empty());
int ndet = (int)numDet.at<float>(0);
printf("num_detections = %d\n", ndet);
ASSERT_GT(ndet, 0);
// Build test detection vectors from model outputs
// Model boxes are normalized (y1, x1, y2, x2) — convert to Rect2d(x, y, w, h)
std::vector<int> testClassIds;
std::vector<float> testScores;
std::vector<Rect2d> testBoxes;
for (int j = 0; j < ndet; j++) {
testClassIds.push_back((int)classes.at<float>(0, j));
testScores.push_back(scores.at<float>(0, j));
float y1 = boxes.at<float>(0, j, 0);
float x1 = boxes.at<float>(0, j, 1);
float y2 = boxes.at<float>(0, j, 2);
float x2 = boxes.at<float>(0, j, 3);
testBoxes.push_back(Rect2d(x1, y1, x2 - x1, y2 - y1));
}
// Reference detections for dog_orig_size.png
// COCO 1-indexed: 2=bicycle, 3=car, 18=dog
std::vector<int> refClassIds = {2, 18, 3};
std::vector<float> refScores = {0.944377f, 0.877805f, 0.787824f};
std::vector<Rect2d> refBoxes = {
Rect2d(0.157917, 0.219984, 0.742909 - 0.157917, 0.739280 - 0.219984), // bicycle
Rect2d(0.168082, 0.360803, 0.426304 - 0.168082, 0.919625 - 0.360803), // dog
Rect2d(0.600506, 0.114612, 0.899101 - 0.600506, 0.298757 - 0.114612), // car
};
float confThreshold = 0.5f;
double scoreDiff = 0.1;
double iouDiff = 0.05;
normAssertDetections(refClassIds, refScores, refBoxes,
testClassIds, testScores, testBoxes,
"", confThreshold, scoreDiff, iouDiff);
}
INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_MobileNetSSD_ONNX,
testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV)));
}} // namespace