// This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. #include "test_precomp.hpp" #include #include #include "npy_blob.hpp" #include #include namespace opencv_test { namespace { template static std::string _tf(TString filename, bool required = true) { String rootFolder = "dnn/"; return findDataFile(rootFolder + filename, required); } class Test_Model : public DNNTestLayer { public: void testDetectModel(const std::string& weights, const std::string& /*cfg*/, const std::string& imgPath, const std::vector& refClassIds, const std::vector& refConfidences, const std::vector& refBoxes, double scoreDiff, double iouDiff, double confThreshold = 0.24, double nmsThreshold = 0.0, const Size& size = {-1, -1}, Scalar mean = Scalar(), double scale = 1.0, bool swapRB = false, bool crop = false, const std::vector& outNames = {"boxes", "scores", "class_idx"}) { checkBackend(); CV_Assert(outNames.size() == 3); Mat frame = imread(imgPath); Net net = readNet(weights); net.setPreferableBackend(backend); net.setPreferableTarget(target); if (target == DNN_TARGET_CPU_FP16) net.enableWinograd(false); net.setInput(blobFromImage(frame, scale, size, mean, swapRB, crop, CV_32F)); std::vector outs; net.forward(outs, outNames); ASSERT_EQ(outs.size(), 3u); Mat outBoxes = outs[0].reshape(1, (int)outs[0].total() / 4); const Mat& outScores = outs[1]; const Mat& outClsIds = outs[2]; std::vector boxes; std::vector confidences; std::vector classIds; for (int i = 0; i < outBoxes.rows; ++i) { float confidence = outScores.at(i); if (confidence < confThreshold) continue; const float* box = outBoxes.ptr(i); boxes.emplace_back(box[0] / size.width, box[1] / size.height, (box[2] - box[0]) / size.width, (box[3] - box[1]) / size.height); confidences.push_back(confidence); classIds.push_back((int)outClsIds.at(i)); } if (nmsThreshold > 0) { std::vector keep; NMSBoxesBatched(boxes, confidences, classIds, (float)confThreshold, (float)nmsThreshold, keep); std::vector nmsBoxes; std::vector nmsConfidences; std::vector nmsClassIds; for (int idx : keep) { nmsBoxes.push_back(boxes[idx]); nmsConfidences.push_back(confidences[idx]); nmsClassIds.push_back(classIds[idx]); } boxes = std::move(nmsBoxes); confidences = std::move(nmsConfidences); classIds = std::move(nmsClassIds); } normAssertDetections(refClassIds, refConfidences, refBoxes, classIds, confidences, boxes, "", confThreshold, scoreDiff, iouDiff); } void testClassifyModel(const std::string& weights, const std::string& cfg, const std::string& imgPath, std::pair ref, float norm, const Size& size = {-1, -1}, Scalar mean = Scalar(), double scale = 1.0, bool swapRB = false, bool crop = false) { checkBackend(); Mat frame = imread(imgPath); ClassificationModel model(weights, cfg); model.setInputSize(size).setInputMean(mean).setInputScale(scale) .setInputSwapRB(swapRB).setInputCrop(crop); std::pair prediction = model.classify(frame); EXPECT_EQ(prediction.first, ref.first); ASSERT_NEAR(prediction.second, ref.second, norm); } void testKeypointsModel(const std::string& weights, const std::string& cfg, const Mat& frame, const Mat& exp, float norm, const Size& size = {-1, -1}, Scalar mean = Scalar(), double scale = 1.0, bool swapRB = false, bool crop = false) { checkBackend(); std::vector points; KeypointsModel model(weights, cfg); model.setInputSize(size).setInputMean(mean).setInputScale(scale) .setInputSwapRB(swapRB).setInputCrop(crop); model.setPreferableBackend(backend); model.setPreferableTarget(target); points = model.estimate(frame, 0.5); Mat out = Mat(points).reshape(1, (int)points.size()); normAssert(exp, out, "", norm, norm); } void testSegmentationModel(const std::string& weights_file, const std::string& config_file, const std::string& inImgPath, const std::string& outImgPath, float norm, const Size& size = {-1, -1}, Scalar mean = Scalar(), double scale = 1.0, bool swapRB = false, bool crop = false, const std::vector& outnames=std::vector()) { checkBackend(); Mat frame = imread(inImgPath); Mat mask; Mat exp = imread(outImgPath, 0); SegmentationModel model(weights_file, config_file); model.setInputSize(size).setInputMean(mean).setInputScale(scale) .setInputSwapRB(swapRB).setInputCrop(crop); model.setPreferableBackend(backend); model.setPreferableTarget(target); if(!outnames.empty()) model.setOutputNames(outnames); model.segment(frame, mask); normAssert(mask, exp, "", norm, norm); } void testTextRecognitionModel(const std::string& weights, const std::string& cfg, const std::string& imgPath, const std::string& seq, const std::string& decodeType, const std::vector& vocabulary, const Size& size = {-1, -1}, Scalar mean = Scalar(), double scale = 1.0, bool swapRB = false, bool crop = false) { checkBackend(); Mat frame = imread(imgPath, IMREAD_GRAYSCALE); TextRecognitionModel model(weights, cfg); model.setDecodeType(decodeType) .setVocabulary(vocabulary) .setInputSize(size).setInputMean(mean).setInputScale(scale) .setInputSwapRB(swapRB).setInputCrop(crop); model.setPreferableBackend(backend); model.setPreferableTarget(target); std::string result = model.recognize(frame); EXPECT_EQ(result, seq) << "Full frame: " << imgPath; std::vector rois; rois.push_back(Rect(0, 0, frame.cols, frame.rows)); rois.push_back(Rect(0, 0, frame.cols, frame.rows)); // twice std::vector results; model.recognize(frame, rois, results); EXPECT_EQ((size_t)2u, results.size()) << "ROI: " << imgPath; EXPECT_EQ(results[0], seq) << "ROI[0]: " << imgPath; EXPECT_EQ(results[1], seq) << "ROI[1]: " << imgPath; } void testTextDetectionModelByDB(const std::string& weights, const std::string& cfg, const std::string& imgPath, const std::vector>& gt, float binThresh, float polyThresh, uint maxCandidates, double unclipRatio, const Size& size = {-1, -1}, Scalar mean = Scalar(), Scalar scale = Scalar::all(1.0), double boxes_iou_diff = 0.05, bool swapRB = false, bool crop = false) { checkBackend(); Mat frame = imread(imgPath); TextDetectionModel_DB model(weights, cfg); model.setBinaryThreshold(binThresh) .setPolygonThreshold(polyThresh) .setUnclipRatio(unclipRatio) .setMaxCandidates(maxCandidates) .setInputSize(size).setInputMean(mean).setInputScale(scale) .setInputSwapRB(swapRB).setInputCrop(crop); model.setPreferableBackend(backend); model.setPreferableTarget(target); // 1. Check common TextDetectionModel API through RotatedRect std::vector results; model.detectTextRectangles(frame, results); EXPECT_GT(results.size(), (size_t)0); std::vector< std::vector > contours; for (size_t i = 0; i < results.size(); i++) { const RotatedRect& box = results[i]; Mat contour; boxPoints(box, contour); std::vector contour2i(4); for (int i = 0; i < 4; i++) { contour2i[i].x = cvRound(contour.at(i, 0)); contour2i[i].y = cvRound(contour.at(i, 1)); } contours.push_back(contour2i); } #if 0 // test debug Mat result = frame.clone(); drawContours(result, contours, -1, Scalar(0, 0, 255), 1); imshow("result", result); // imwrite("result.png", result); waitKey(0); #endif normAssertTextDetections(gt, contours, "", boxes_iou_diff); // 2. Check quadrangle-based API // std::vector< std::vector > contours; model.detect(frame, contours); #if 0 // test debug Mat result = frame.clone(); drawContours(result, contours, -1, Scalar(0, 0, 255), 1); imshow("result_contours", result); // imwrite("result_contours.png", result); waitKey(0); #endif normAssertTextDetections(gt, contours, "", boxes_iou_diff); } void testTextDetectionModelByEAST( const std::string& weights, const std::string& cfg, const std::string& imgPath, const std::vector& gt, float confThresh, float nmsThresh, const Size& size = {-1, -1}, Scalar mean = Scalar(), double scale = 1.0, bool swapRB = false, bool crop = false, double eps_center = 5/*pixels*/, double eps_size = 5/*pixels*/, double eps_angle = 1 ) { checkBackend(); Mat frame = imread(imgPath); TextDetectionModel_EAST model(weights, cfg); model.setConfidenceThreshold(confThresh) .setNMSThreshold(nmsThresh) .setInputSize(size).setInputMean(mean).setInputScale(scale) .setInputSwapRB(swapRB).setInputCrop(crop); model.setPreferableBackend(backend); model.setPreferableTarget(target); std::vector results; model.detectTextRectangles(frame, results); EXPECT_EQ(results.size(), (size_t)1); for (size_t i = 0; i < results.size(); i++) { const RotatedRect& box = results[i]; #if 0 // test debug Mat contour; boxPoints(box, contour); std::vector contour2i(4); for (int i = 0; i < 4; i++) { contour2i[i].x = cvRound(contour.at(i, 0)); contour2i[i].y = cvRound(contour.at(i, 1)); } std::vector< std::vector > contours; contours.push_back(contour2i); Mat result = frame.clone(); drawContours(result, contours, -1, Scalar(0, 0, 255), 1); imshow("result", result); //imwrite("result.png", result); waitKey(0); #endif const RotatedRect& gtBox = gt[i]; EXPECT_NEAR(box.center.x, gtBox.center.x, eps_center); EXPECT_NEAR(box.center.y, gtBox.center.y, eps_center); EXPECT_NEAR(box.size.width, gtBox.size.width, eps_size); EXPECT_NEAR(box.size.height, gtBox.size.height, eps_size); EXPECT_NEAR(box.angle, gtBox.angle, eps_angle); } } }; TEST_P(Test_Model, Classify) { std::pair ref(652, 0.641789); std::string img_path = _tf("grace_hopper_227.png"); std::string weights_file = _tf("onnx/models/alexnet.onnx", false); Size size{227, 227}; float norm = 1e-4; testClassifyModel(weights_file, "", img_path, ref, norm, size); } TEST_P(Test_Model, YOLOv3) { applyTestTag( CV_TEST_TAG_LONG, CV_TEST_TAG_MEMORY_2GB, CV_TEST_TAG_DEBUG_VERYLONG ); if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); checkBackend(); std::vector refClassIds = {16, 1, 7}; std::vector refConfidences = {0.998835f, 0.987915f, 0.952998f}; std::vector refBoxes = { Rect2d(0.160018f, 0.389962f, 0.257871f, 0.553753f), Rect2d(0.150904f, 0.221934f, 0.591361f, 0.524322f), Rect2d(0.614625f, 0.150259f, 0.286741f, 0.138992f), }; double scoreDiff = 8e-5, iouDiff = 3e-4; if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD || target == DNN_TARGET_CPU_FP16) { scoreDiff = 0.006; iouDiff = 0.042; } else if (target == DNN_TARGET_CUDA_FP16) { scoreDiff = 0.04; iouDiff = 0.03; } const float confThreshold = 0.5f, nmsThreshold = 0.4f; const Size inputSize(416, 416); Mat img = imread(_tf("dog416.png")); cv::resize(img, img, inputSize); Mat blob = blobFromImage(img, 1.0 / 255.0, inputSize, Scalar(), true, false); Net net = readNet(_tf("yolov3-converted.onnx", false)); net.setPreferableBackend(backend); net.setPreferableTarget(target); net.setInput(blob); std::vector outs; net.forward(outs, net.getUnconnectedOutLayersNames()); int numBoxes = (int)(outs[0].total() / 4); Mat boxesMat = outs[0].reshape(1, numBoxes); Mat confsMat = outs[1].reshape(1, numBoxes); std::vector boxes; std::vector confidences; std::vector classIds; for (int j = 0; j < numBoxes; ++j) { Mat scores = confsMat.row(j); double confidence; Point maxLoc; minMaxLoc(scores, 0, &confidence, 0, &maxLoc); if (confidence >= confThreshold) { float* b = boxesMat.ptr(j); boxes.emplace_back(b[0], b[1], b[2] - b[0], b[3] - b[1]); confidences.push_back((float)confidence); classIds.push_back(maxLoc.x); } } std::vector keep; NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, keep); std::vector nmsBoxes; std::vector nmsConfs; std::vector nmsCls; for (int k : keep) { nmsBoxes.push_back(boxes[k]); nmsConfs.push_back(confidences[k]); nmsCls.push_back(classIds[k]); } normAssertDetections(refClassIds, refConfidences, refBoxes, nmsCls, nmsConfs, nmsBoxes, "", confThreshold, scoreDiff, iouDiff); } TEST_P(Test_Model, Keypoints_pose) { if (target == DNN_TARGET_OPENCL_FP16) applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16); if (target == DNN_TARGET_CPU_FP16) applyTestTag(CV_TEST_TAG_DNN_SKIP_CPU_FP16); #ifdef HAVE_INF_ENGINE if (target == DNN_TARGET_MYRIAD) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_VERSION); #endif Mat inp = imread(_tf("pose.png")); std::string weights = _tf("onnx/models/lightweight_pose_estimation_201912.onnx", false); float kpdata[] = { 237.65625f, 78.25f, 237.65625f, 136.9375f, 190.125f, 136.9375f, 142.59375f, 195.625f, 79.21875f, 176.0625f, 285.1875f, 117.375f, 348.5625f, 195.625f, 396.09375f, 176.0625f, 205.96875f, 313.0f, 205.96875f, 430.375f, 205.96875f, 528.1875f, 269.34375f, 293.4375f, 253.5f, 430.375f, 237.65625f, 528.1875f, 221.8125f, 58.6875f, 253.5f, 58.6875f, 205.96875f, 78.25f, 253.5f, 58.6875f }; Mat exp(18, 2, CV_32FC1, kpdata); Size size{256, 256}; float norm = 1e-4; double scale = 1.0/255; Scalar mean = Scalar(128, 128, 128); bool swapRB = false; // Ref. Range: [58.6875, 508.625] if (target == DNN_TARGET_CUDA_FP16) norm = 20; // l1 = 1.5, lInf = 20 testKeypointsModel(weights, "", inp, exp, norm, size, mean, scale, swapRB); } TEST_P(Test_Model, Keypoints_face) { #if defined(INF_ENGINE_RELEASE) if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER, CV_TEST_TAG_DNN_SKIP_IE_VERSION); #endif Mat inp = imread(_tf("gray_face.png"), 0); std::string weights = _tf("onnx/models/facial_keypoints.onnx", false); Mat exp = blobFromNPY(_tf("facial_keypoints_exp.npy")); Size size{224, 224}; double scale = 1.0/255; Scalar mean = Scalar(); bool swapRB = false; // Ref. Range: [-1.1784188, 1.7758257] float norm = 2e-3; if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_CPU_FP16) norm = 5e-3; if (target == DNN_TARGET_MYRIAD) { // Myriad2: l1 = 0.0004, lInf = 0.002 // MyriadX: l1 = 0.003, lInf = 0.009 norm = 0.009; } if (target == DNN_TARGET_CUDA_FP16) norm = 0.004; // l1 = 0.0006, lInf = 0.004 testKeypointsModel(weights, "", inp, exp, norm, size, mean, scale, swapRB); } TEST_P(Test_Model, Segmentation) { applyTestTag( CV_TEST_TAG_MEMORY_2GB, CV_TEST_TAG_DEBUG_VERYLONG ); float norm = 0; #if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) // Failed to allocate graph: NC_ERROR if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); // accuracy if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && (target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16)) { norm = 25.0f; // depends on OS/OpenCL version } #elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) // Failed to allocate graph: NC_ERROR if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); // cnn_network_ngraph_impl.cpp:104 Function contains several inputs and outputs with one friendly name: 'upscore2'! if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); // cnn_network_ngraph_impl.cpp:104 Function contains several inputs and outputs with one friendly name: 'upscore2'! if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); #elif defined(INF_ENGINE_RELEASE) // Failed to allocate graph: NC_ERROR if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); #endif //if ((backend == DNN_BACKEND_OPENCV && (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_CPU_FP16)) // || (backend == DNN_BACKEND_CUDA && target == DNN_TARGET_CUDA_FP16)) { // let's always set it to 7 for now norm = 7.0f; // l1 = 0.01 lInf = 7 } std::string inp = _tf("dog416.png"); std::string weights_file = _tf("onnx/models/fcn-resnet50-12.onnx", false); std::string exp = _tf("segmentation_exp.png"); Size size{128, 128}; double scale = 0.019; Scalar mean = Scalar(0.485*255, 0.456*255, 0.406*255); bool swapRB = true; testSegmentationModel(weights_file, "", inp, exp, norm, size, mean, scale, swapRB, false); } TEST_P(Test_Model, TextRecognition) { #if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) // FIXIT: dnn/src/ie_ngraph.cpp:494: error: (-215:Assertion failed) !inps.empty() in function 'createNet' if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_CPU) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_CPU, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); // Node Transpose_79 was not assigned on any pointed device if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && (target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16)) applyTestTag(target == DNN_TARGET_OPENCL ? CV_TEST_TAG_DNN_SKIP_IE_OPENCL : CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION ); #elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) // IE Exception: Ngraph operation Reshape with name 71 has dynamic output shape on 0 port, but CPU plug-in supports only static shape if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && (target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16)) applyTestTag(target == DNN_TARGET_OPENCL ? CV_TEST_TAG_DNN_SKIP_IE_OPENCL : CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION ); #endif std::string imgPath = _tf("text_rec_test.png"); std::string weightPath = _tf("onnx/models/crnn.onnx", false); std::string seq = "welcome"; Size size{100, 32}; double scale = 1.0 / 127.5; Scalar mean = Scalar(127.5); std::string decodeType = "CTC-greedy"; std::vector vocabulary = {"0","1","2","3","4","5","6","7","8","9", "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"}; testTextRecognitionModel(weightPath, "", imgPath, seq, decodeType, vocabulary, size, mean, scale); } TEST_P(Test_Model, TextRecognitionWithCTCPrefixBeamSearch) { #if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) // Node Transpose_79 was not assigned on any pointed device if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && (target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16)) applyTestTag(target == DNN_TARGET_OPENCL ? CV_TEST_TAG_DNN_SKIP_IE_OPENCL : CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION ); #elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) // IE Exception: Ngraph operation Reshape with name 71 has dynamic output shape on 0 port, but CPU plug-in supports only static shape if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && (target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16)) applyTestTag(target == DNN_TARGET_OPENCL ? CV_TEST_TAG_DNN_SKIP_IE_OPENCL : CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION ); #endif std::string imgPath = _tf("text_rec_test.png"); std::string weightPath = _tf("onnx/models/crnn.onnx", false); std::string seq = "welcome"; Size size{100, 32}; double scale = 1.0 / 127.5; Scalar mean = Scalar(127.5); std::string decodeType = "CTC-prefix-beam-search"; std::vector vocabulary = {"0","1","2","3","4","5","6","7","8","9", "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"}; testTextRecognitionModel(weightPath, "", imgPath, seq, decodeType, vocabulary, size, mean, scale); } TEST_P(Test_Model, TextDetectionByDB) { applyTestTag(CV_TEST_TAG_DEBUG_VERYLONG); if (target == DNN_TARGET_OPENCL_FP16) applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16); if (target == DNN_TARGET_CPU_FP16) applyTestTag(CV_TEST_TAG_DNN_SKIP_CPU_FP16); std::string imgPath = _tf("text_det_test1.png"); std::string weightPathDB = _tf("onnx/models/DB_TD500_resnet50.onnx", false); std::string weightPathPPDB = _tf("onnx/models/PP_OCRv3_DB_text_det.onnx", false); // GroundTruth std::vector> gt = { { Point(142, 193), Point(136, 164), Point(213, 150), Point(219, 178) }, { Point(136, 165), Point(122, 114), Point(319, 71), Point(330, 122) } }; Size size{736, 736}; Scalar scaleDB = Scalar::all(1.0 / 255.0); Scalar meanDB = Scalar(122.67891434, 116.66876762, 104.00698793); // new mean and stddev Scalar meanPPDB = Scalar(123.675, 116.28, 103.53); Scalar stddevPPDB = Scalar(0.229, 0.224, 0.225); Scalar scalePPDB = scaleDB / stddevPPDB; float binThresh = 0.3; float polyThresh = 0.5; uint maxCandidates = 200; double unclipRatio = 2.0; { SCOPED_TRACE("Original DB"); float boxes_iou_diff = 0.05f; if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) boxes_iou_diff = 0.11f; testTextDetectionModelByDB(weightPathDB, "", imgPath, gt, binThresh, polyThresh, maxCandidates, unclipRatio, size, meanDB, scaleDB, boxes_iou_diff); } { SCOPED_TRACE("PP-OCRDBv3"); testTextDetectionModelByDB(weightPathPPDB, "", imgPath, gt, binThresh, polyThresh, maxCandidates, unclipRatio, size, meanPPDB, scalePPDB, 0.21f); } } TEST_P(Test_Model, TextDetectionByEAST) { applyTestTag(CV_TEST_TAG_DEBUG_VERYLONG); std::string imgPath = _tf("text_det_test2.jpg"); std::string weightPath = _tf("frozen_east_text_detection.pb", false); // GroundTruth std::vector gt = { RotatedRect(Point2f(657.55f, 409.5f), Size2f(316.84f, 62.45f), -4.79) }; // Model parameters Size size{320, 320}; double scale = 1.0; Scalar mean = Scalar(123.68, 116.78, 103.94); bool swapRB = true; // Detection algorithm parameters float confThresh = 0.5; float nmsThresh = 0.4; double eps_center = 5/*pixels*/; double eps_size = 5/*pixels*/; double eps_angle = 1; if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_CUDA_FP16 || target == DNN_TARGET_MYRIAD || target == DNN_TARGET_CPU_FP16) { eps_center = 10; eps_size = 25; eps_angle = 3; } testTextDetectionModelByEAST(weightPath, "", imgPath, gt, confThresh, nmsThresh, size, mean, scale, swapRB, false/*crop*/, eps_center, eps_size, eps_angle ); } INSTANTIATE_TEST_CASE_P(/**/, Test_Model, dnnBackendsAndTargets()); static void topK(const Mat& probs, std::vector >& result, int K) { CV_Assert(probs.type() == CV_32F); CV_Assert(probs.dims == 2 && probs.rows == 1); int N = int(probs.total()); K = std::min(K, N); std::vector > pairs(N); for (int i = 0; i < N; i++) { pairs[i] = {-probs.at(i), i}; } std::partial_sort(pairs.begin(), pairs.begin() + K, pairs.end()); result.resize(K); for (int i = 0; i < K; i++) { result[i] = {pairs[i].second, -pairs[i].first}; } } typedef testing::TestWithParam Reproducibility_ResNet50_ONNX; TEST_P(Reproducibility_ResNet50_ONNX, Accuracy) { Target targetId = GetParam(); 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/resnet50v1.onnx", false); Net net = readNetFromONNX(modelname); net.setPreferableBackend(DNN_BACKEND_OPENCV); net.setPreferableTarget(targetId); if (targetId == DNN_TARGET_CPU_FP16) net.enableWinograd(false); //net.dumpToStream(std::cout); //net.setTracingMode(DNN_TRACE_ALL); std::string imgname = _tf("sqcat.png"); Mat image = imread(imgname); Mat input = blobFromImage(image, 0.017, Size(224,224), Scalar(103.939, 116.779, 123.68), false, true, CV_32F); ASSERT_TRUE(!input.empty()); net.setInput(input); Mat out = net.forward(); std::vector > ref = {{285, 10.13}, {287, 9.68}, {283, 8.83}, {278, 8.56}, {279, 8.34}}; std::vector > res; const int K = 5; topK(out, res, K); const float eps = 0.15f; ASSERT_EQ(int(res.size()), K); std::vector reflabels(K), reslabels(K); for (int i = 0; i < K; i++) { reflabels[i] = ref[i].first; reslabels[i] = res[i].first; } ASSERT_EQ(reflabels, reslabels); for (int i = 0; i < K; i++) { EXPECT_NEAR(ref[i].second, res[i].second, eps); } } INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_ResNet50_ONNX, testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV))); typedef testing::TestWithParam Reproducibility_ResNet50_QDQ_ONNX; TEST_P(Reproducibility_ResNet50_QDQ_ONNX, Accuracy) { Target targetId = GetParam(); 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/resnet50-v1-12-qdq.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("sqcat.png"); Mat image = imread(imgname); Mat input = blobFromImage(image, 0.017, Size(224,224), Scalar(103.939, 116.779, 123.68), false, true, CV_32F); ASSERT_TRUE(!input.empty()); net.setInput(input); Mat out = net.forward(); const int K = 5; std::vector > res; topK(out, res, K); ASSERT_EQ(int(res.size()), K); // Top 4 class's score must be within eps of its reference value. std::vector > ref = {{285, 10.44}, {287, 10.13}, {283, 8.89}, {278, 8.43}}; const float eps = 0.5f; std::map res_map; for (int i = 0; i < (int)res.size(); i++) res_map[res[i].first] = res[i].second; for (const auto& r : ref) { auto it = res_map.find(r.first); EXPECT_NE(it, res_map.end()) << "Expected class " << r.first << " not found in top-4"; if (it != res_map.end()) { EXPECT_NEAR(r.second, it->second, eps) << "Score mismatch for class " << r.first; } } } INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_ResNet50_QDQ_ONNX, testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV))); typedef testing::TestWithParam Reproducibility_ViT_ONNX; TEST_P(Reproducibility_ViT_ONNX, Accuracy) { Target targetId = GetParam(); applyTestTag(targetId == DNN_TARGET_CPU ? CV_TEST_TAG_MEMORY_1GB : CV_TEST_TAG_MEMORY_2GB); ASSERT_TRUE(ocl::useOpenCL() || targetId == DNN_TARGET_CPU || targetId == DNN_TARGET_CPU_FP16); auto engine_forced = static_cast( cv::utils::getConfigurationParameterSizeT("OPENCV_FORCE_DNN_ENGINE", ENGINE_AUTO)); if (engine_forced == ENGINE_CLASSIC) { applyTestTag(CV_TEST_TAG_DNN_SKIP_PARSER); return; } std::string modelname = _tf("vit_base_patch16_224_Opset16.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("sqcat.png"); Mat image = imread(imgname); // ViT preprocessing: (pixel/255 - 0.5)/0.5 == pixel/127.5 - 1 // blobFromImage form: (pixel - 127.5) * (1/127.5) Mat input = blobFromImage(image, 1.0 / 127.5, Size(224, 224), Scalar(127.5, 127.5, 127.5), true, true, CV_32F); ASSERT_TRUE(!input.empty()); net.setInput(input); Mat out = net.forward(); const int K = 5; std::vector > res; topK(out, res, K); ASSERT_EQ(int(res.size()), K); // Reference top-5 captured from the ONNX Runtime engine (OPENCV_FORCE_DNN_ENGINE=4). std::vector > ref = { {285, 7.683f}, {282, 7.182f}, {281, 6.894f}, {287, 3.623f}, {283, 3.287f} }; const float eps = 0.5f; std::vector reflabels(K), reslabels(K); for (int i = 0; i < K; i++) { reflabels[i] = ref[i].first; reslabels[i] = res[i].first; } ASSERT_EQ(reflabels, reslabels); for (int i = 0; i < K; i++) { EXPECT_NEAR(ref[i].second, res[i].second, eps); } } INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_ViT_ONNX, testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV))); typedef testing::TestWithParam Reproducibility_BERT_ONNX; TEST_P(Reproducibility_BERT_ONNX, Accuracy) { applyTestTag(CV_TEST_TAG_MEMORY_2GB); Target targetId = GetParam(); ASSERT_TRUE(ocl::useOpenCL() || targetId == DNN_TARGET_CPU || targetId == DNN_TARGET_CPU_FP16); auto engine_forced = static_cast( cv::utils::getConfigurationParameterSizeT("OPENCV_FORCE_DNN_ENGINE", ENGINE_AUTO)); if (engine_forced == ENGINE_CLASSIC) { applyTestTag(CV_TEST_TAG_DNN_SKIP_PARSER); return; } std::string modelname = _tf("onnx/models/bert.onnx", false); Net net = readNetFromONNX(modelname); net.setPreferableBackend(DNN_BACKEND_OPENCV); net.setPreferableTarget(targetId); // Tokenized with bert-base-uncased: "The [MASK] sat on the mat." // [CLS]=101 the=1996 [MASK]=103 sat=2938 on=2006 the=1996 mat=13523 .=1012 [SEP]=102 const int seq_len = 9; int64_t input_ids_data[seq_len] = {101, 1996, 103, 2938, 2006, 1996, 13523, 1012, 102}; int64_t attention_mask_data[seq_len] = {1, 1, 1, 1, 1, 1, 1, 1, 1}; int64_t token_type_ids_data[seq_len] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; int shape[2] = {1, seq_len}; Mat input_ids(2, shape, CV_64S, input_ids_data); Mat attention_mask(2, shape, CV_64S, attention_mask_data); Mat token_type_ids(2, shape, CV_64S, token_type_ids_data); net.setInput(input_ids, "input_ids"); net.setInput(attention_mask, "attention_mask"); net.setInput(token_type_ids, "token_type_ids"); Mat out = net.forward(); // Output shape: [1, 9, 30522] (batch, seq_len, vocab_size) ASSERT_EQ(out.dims, 3); ASSERT_EQ(out.size[0], 1); ASSERT_EQ(out.size[1], seq_len); ASSERT_EQ(out.size[2], 30522); const int vocab = 30522; const float* mask_logits = out.ptr() + 2 * vocab; const int K = 5; std::vector > res; std::vector idx(vocab); for (int i = 0; i < vocab; i++) idx[i] = i; std::partial_sort(idx.begin(), idx.begin() + K, idx.end(), [&](int a, int b) { return mask_logits[a] > mask_logits[b]; }); for (int k = 0; k < K; k++) res.emplace_back(idx[k], mask_logits[idx[k]]); std::vector > ref = { {2611, 8.222f}, {2158, 8.196f}, {3899, 8.021f}, {2879, 7.972f}, {2450, 7.393f} }; const float eps = 0.5f; std::vector reflabels(K), reslabels(K); for (int i = 0; i < K; i++) { reflabels[i] = ref[i].first; reslabels[i] = res[i].first; } ASSERT_EQ(reflabels, reslabels); for (int i = 0; i < K; i++) { EXPECT_NEAR(ref[i].second, res[i].second, eps); } } INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_BERT_ONNX, testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV))); typedef testing::TestWithParam Reproducibility_MobileNetSSD_ONNX; TEST_P(Reproducibility_MobileNetSSD_ONNX, Accuracy) { Target targetId = GetParam(); auto engine_forced = static_cast( 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 outNames = net.getUnconnectedOutLayersNames(); std::vector outs; net.setInput(input8dim4); net.forward(outs, outNames); // 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(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(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 testClassIds; std::vector testScores; std::vector testBoxes; for (int j = 0; j < ndet; j++) { testClassIds.push_back((int)classes.at(0, j)); testScores.push_back(scores.at(0, j)); float y1 = boxes.at(0, j, 0); float x1 = boxes.at(0, j, 1); float y2 = boxes.at(0, j, 2); float x2 = boxes.at(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 refClassIds = {2, 18, 3}; std::vector refScores = {0.944377f, 0.877805f, 0.787824f}; std::vector 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 { enum YoloFormat { YOLO_V5, YOLO_V8, YOLO_X }; static void YoloPostprocess(const Mat& out, YoloFormat fmt, int inputSize, float confTh, float nmsTh, std::vector& classIds, std::vector& confidences, std::vector& boxes) { CV_Assert(out.dims == 3); bool hasObj = (fmt != YOLO_V8); int nclasses = 80; int stride = 4 + (hasObj ? 1 : 0) + nclasses; const float* data = nullptr; std::vector buf; int N; if (fmt == YOLO_V8) { int C = out.size[1]; N = out.size[2]; CV_Assert(C == stride); const float* src = out.ptr(); buf.resize((size_t)N * C); for (int i = 0; i < C; i++) for (int j = 0; j < N; j++) buf[j * C + i] = src[i * N + j]; data = buf.data(); } else { N = out.size[1]; CV_Assert(out.size[2] == stride); data = out.ptr(); } // YOLOX grid decode tables std::vector gridX, gridY, strideVec; if (fmt == YOLO_X) { const int strides[] = {8, 16, 32}; gridX.resize(N); gridY.resize(N); strideVec.resize(N); int idx = 0; for (int si = 0; si < 3; si++) { int gs = inputSize / strides[si]; for (int y = 0; y < gs; y++) for (int x = 0; x < gs; x++) { gridX[idx] = (float)x; gridY[idx] = (float)y; strideVec[idx] = (float)strides[si]; idx++; } } CV_Assert(idx == N); } int classOff = hasObj ? 5 : 4; double scale = 1.0 / inputSize; std::vector intBoxes; std::vector allCls; std::vector allConf; std::vector allBoxes; for (int i = 0; i < N; i++) { const float* r = data + (size_t)i * stride; float obj = hasObj ? r[4] : 1.0f; if (obj < confTh) continue; int bestCls = 0; float bestScore = 0; for (int c = 0; c < nclasses; c++) { float s = r[classOff + c] * obj; if (s > bestScore) { bestScore = s; bestCls = c; } } if (bestScore < confTh) continue; float cx, cy, w, h; if (fmt == YOLO_X) { cx = (r[0] + gridX[i]) * strideVec[i]; cy = (r[1] + gridY[i]) * strideVec[i]; w = std::exp(r[2]) * strideVec[i]; h = std::exp(r[3]) * strideVec[i]; } else { cx = r[0]; cy = r[1]; w = r[2]; h = r[3]; } intBoxes.push_back(Rect((int)(cx-w/2), (int)(cy-h/2), (int)w, (int)h)); allConf.push_back(bestScore); allCls.push_back(bestCls); allBoxes.push_back(Rect2d((cx-w/2)*scale, (cy-h/2)*scale, w*scale, h*scale)); } std::vector indices; cv::dnn::NMSBoxes(intBoxes, allConf, confTh, nmsTh, indices); for (int idx : indices) { classIds.push_back(allCls[idx]); confidences.push_back(allConf[idx]); boxes.push_back(allBoxes[idx]); } } } // local namespace typedef testing::TestWithParam Reproducibility_YOLOv5n_ONNX; TEST_P(Reproducibility_YOLOv5n_ONNX, Accuracy) { Target targetId = GetParam(); 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("yolov5n.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("dog416.png"); Mat image = imread(imgname); ASSERT_TRUE(!image.empty()); Mat input = blobFromImage(image, 1.0/255.0, Size(640, 640), Scalar(), true, false, CV_32F); net.setInput(input); Mat out = net.forward(); if (out.type() != CV_32F) out.convertTo(out, CV_32F); std::vector classIds; std::vector confidences; std::vector testBoxes; YoloPostprocess(out, YOLO_V5, 640, 0.25f, 0.45f, classIds, confidences, testBoxes); std::vector refClassIds = {16, 2, 1, 1}; std::vector refScores = {0.711f, 0.581f, 0.344f, 0.275f}; std::vector refBoxes = { Rect2d(0.168262, 0.374023, 0.247852, 0.577734), // dog Rect2d(0.605469, 0.134375, 0.286719, 0.156250), // car Rect2d(0.186279, 0.248828, 0.148926, 0.129688), // bicycle (small) Rect2d(0.231836, 0.277930, 0.519141, 0.483203), // bicycle (large) }; normAssertDetections(refClassIds, refScores, refBoxes, classIds, confidences, testBoxes, "", 0.25f, /*scoreDiff=*/0.2, /*iouDiff=*/0.2); } INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_YOLOv5n_ONNX, testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV))); typedef testing::TestWithParam Reproducibility_YOLOv8n_ONNX; TEST_P(Reproducibility_YOLOv8n_ONNX, Accuracy) { Target targetId = GetParam(); 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("yolov8n.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("dog416.png"); Mat image = imread(imgname); ASSERT_TRUE(!image.empty()); Mat input = blobFromImage(image, 1.0/255.0, Size(640, 640), Scalar(), true, false, CV_32F); net.setInput(input); Mat out = net.forward(); if (out.type() != CV_32F) out.convertTo(out, CV_32F); std::vector classIds; std::vector confidences; std::vector testBoxes; YoloPostprocess(out, YOLO_V8, 640, 0.25f, 0.45f, classIds, confidences, testBoxes); std::vector refClassIds = {16, 1, 7}; std::vector refScores = {0.827f, 0.809f, 0.544f}; std::vector refBoxes = { Rect2d(0.171157, 0.386951, 0.231909, 0.551873), // dog Rect2d(0.160967, 0.234788, 0.577899, 0.495077), // bicycle Rect2d(0.608337, 0.130141, 0.291832, 0.167390), // truck }; normAssertDetections(refClassIds, refScores, refBoxes, classIds, confidences, testBoxes, "", 0.25f, /*scoreDiff=*/0.1, /*iouDiff=*/0.1); } INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_YOLOv8n_ONNX, testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV))); typedef testing::TestWithParam Reproducibility_YOLOXS_ONNX; TEST_P(Reproducibility_YOLOXS_ONNX, Accuracy) { Target targetId = GetParam(); 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("yolox_s.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("dog416.png"); Mat image = imread(imgname); ASSERT_TRUE(!image.empty()); Mat input = blobFromImage(image, 1.0, Size(640, 640), Scalar(), false, false, CV_32F); net.setInput(input); Mat out = net.forward(); if (out.type() != CV_32F) out.convertTo(out, CV_32F); std::vector classIds; std::vector confidences; std::vector testBoxes; YoloPostprocess(out, YOLO_X, 640, 0.25f, 0.45f, classIds, confidences, testBoxes); std::vector refClassIds = {1, 16, 7, 1}; std::vector refScores = {0.962f, 0.920f, 0.833f, 0.266f}; std::vector refBoxes = { Rect2d(0.160787, 0.225276, 0.577830, 0.503752), // bicycle (large) Rect2d(0.172622, 0.386773, 0.230225, 0.554768), // dog Rect2d(0.601869, 0.128871, 0.302539, 0.168476), // truck Rect2d(0.166281, 0.251719, 0.339791, 0.385267), // bicycle (small) }; normAssertDetections(refClassIds, refScores, refBoxes, classIds, confidences, testBoxes, "", 0.25f, /*scoreDiff=*/0.2, /*iouDiff=*/0.2); } INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_YOLOXS_ONNX, testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV))); typedef testing::TestWithParam Reproducibility_BlazeFace_ONNX; TEST_P(Reproducibility_BlazeFace_ONNX, Accuracy) { auto engine_forced = static_cast( 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; } Target targetId = GetParam(); 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/blazeface.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 = findDataFile("cv/cascadeandhog/images/karen-and-rob.png"); Mat image = imread(imgname); ASSERT_FALSE(image.empty()); Mat input = blobFromImage(image, 1.0 / 255.0, Size(128, 128), Scalar(), true, false, CV_32F); ASSERT_FALSE(input.empty()); Mat refSelected = blobFromNPY(_tf("onnx/data/output_blazeface_selectedBoxes.npy")); ASSERT_FALSE(refSelected.empty()); const int oneDim[] = {1}; Mat conf(1, oneDim, CV_32F); conf.ptr()[0] = 0.20f; Mat iou(1, oneDim, CV_32F); iou.ptr()[0] = 0.30f; Mat maxDet(1, oneDim, CV_64S); maxDet.ptr()[0] = 25; std::vector outNames = net.getUnconnectedOutLayersNames(); std::vector outs; Mat selected; int idxSel = -1; net.setInput(input, "image"); net.setInput(conf, "conf_threshold"); net.setInput(iou, "iou_threshold"); net.setInput(maxDet, "max_detections"); net.forward(outs, outNames); for (size_t j = 0; j < outNames.size(); ++j) { if (outNames[j].find("selectedBoxes") != std::string::npos) { idxSel = static_cast(j); break; } } if (idxSel < 0 && !outs.empty()) idxSel = 0; ASSERT_GE(idxSel, 0); outs[idxSel].convertTo(selected, CV_32F); Mat outFlat = selected.reshape(1, 1); Mat refFlat = refSelected.reshape(1, 1); ASSERT_EQ(outFlat.total(), refFlat.total()) << "OpenCV output size differs from ORT reference"; EXPECT_LE(cv::norm(outFlat, refFlat, NORM_INF), 1e-2); } INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_BlazeFace_ONNX, testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV))); typedef testing::TestWithParam Reproducibility_FacePaint_ONNX; TEST_P(Reproducibility_FacePaint_ONNX, Accuracy) { Target targetId = GetParam(); 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/face_paint_512_v2_0.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 = findDataFile("cv/shared/baboon.png"); Mat image = imread(imgname); ASSERT_FALSE(image.empty()); Mat input = blobFromImage(image, 1.0/127.5, Size(512, 512), Scalar(127.5, 127.5, 127.5), true, false, CV_32F); ASSERT_TRUE(!input.empty()); net.setInput(input); Mat out = net.forward(); Mat ref_img = imread(_tf("onnx/data/face_paint_512_v2_0_ort_output.png")); ASSERT_FALSE(ref_img.empty()) << "Failed to load reference PNG"; Mat ref = blobFromImage(ref_img, 1.0 / 127.5, Size(), Scalar(127.5, 127.5, 127.5), true, false, CV_32F); Mat outFlat = out.reshape(1, 1); Mat refFlat = ref.reshape(1, 1); ASSERT_EQ(outFlat.total(), refFlat.total()) << "OpenCV output size differs from ORT reference"; EXPECT_LE(cv::norm(outFlat, refFlat, NORM_INF), 0.01); } INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_FacePaint_ONNX, testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV))); typedef testing::TestWithParam Reproducibility_SwinIR_ONNX; TEST_P(Reproducibility_SwinIR_ONNX, Accuracy) { Target targetId = GetParam(); applyTestTag(CV_TEST_TAG_MEMORY_512MB, CV_TEST_TAG_LONG); auto engine_forced = static_cast( cv::utils::getConfigurationParameterSizeT("OPENCV_FORCE_DNN_ENGINE", ENGINE_AUTO)); if (engine_forced == ENGINE_CLASSIC) { applyTestTag(CV_TEST_TAG_DNN_SKIP_PARSER); return; } std::string modelname = _tf("onnx/models/swinir_x4_gan.onnx", false); Net net = readNetFromONNX(modelname, ENGINE_NEW); ASSERT_FALSE(net.empty()); net.setPreferableBackend(DNN_BACKEND_OPENCV); net.setPreferableTarget(targetId); std::string imgname = findDataFile("cv/dnn_superres/butterfly.png"); Mat image = imread(imgname); ASSERT_FALSE(image.empty()); Mat input = blobFromImage(image, 1.0 / 255.0, Size(64, 64), Scalar(0, 0, 0), true, false, CV_32F); net.setInput(input); Mat out = net.forward(); ASSERT_EQ(out.dims, 4); EXPECT_EQ(out.size[0], 1); EXPECT_EQ(out.size[1], 3); EXPECT_EQ(out.size[2], 256); EXPECT_EQ(out.size[3], 256); double minVal, maxVal; cv::minMaxLoc(out.reshape(1, 1), &minVal, &maxVal); EXPECT_GE(minVal, -0.2); EXPECT_LE(maxVal, 1.2); } INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_SwinIR_ONNX, testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV))); }} // namespace