// 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" namespace opencv_test { namespace { class CV_GMSMatcherTest : public cvtest::BaseTest { public: CV_GMSMatcherTest(); ~CV_GMSMatcherTest(); protected: virtual void run(int); bool combinations[4][2]; double eps[3][4]; //3 imgs x 4 combinations double correctMatchDistThreshold; }; CV_GMSMatcherTest::CV_GMSMatcherTest() { combinations[0][0] = false; combinations[0][1] = false; combinations[1][0] = false; combinations[1][1] = true; combinations[2][0] = true; combinations[2][1] = false; combinations[3][0] = true; combinations[3][1] = true; eps[0][0] = 0.91; eps[0][1] = 0.91; eps[0][2] = 0.91; eps[0][3] = 0.91; eps[1][0] = 0.80; eps[1][1] = 0.78; eps[1][2] = 0.80; eps[1][3] = 0.78; eps[2][0] = 0.6; eps[2][1] = 0.6; eps[2][2] = 0.6; eps[2][3] = 0.6; correctMatchDistThreshold = 5.0; } CV_GMSMatcherTest::~CV_GMSMatcherTest() {} void CV_GMSMatcherTest::run( int ) { ts->set_failed_test_info(cvtest::TS::OK); Mat imgRef = imread(string(ts->get_data_path()) + "detectors_descriptors_evaluation/images_datasets/graf/img1.png"); Ptr orb = ORB::create(10000); vector keypointsRef, keypointsCur; Mat descriptorsRef, descriptorsCur; orb->detectAndCompute(imgRef, noArray(), keypointsRef, descriptorsRef); vector matchesAll, matchesGMS; Ptr matcher = DescriptorMatcher::create("BruteForce-Hamming"); const int startImg = 2; const int nImgs = 3; for (int num = startImg; num < startImg+nImgs; num++) { string fileName = cv::format("img%d.png", num); string imgPath = string(ts->get_data_path()) + "detectors_descriptors_evaluation/images_datasets/graf/" + fileName; Mat imgCur = imread(imgPath); orb->detectAndCompute(imgCur, noArray(), keypointsCur, descriptorsCur); matcher->match(descriptorsCur, descriptorsRef, matchesAll); string xml = string(ts->get_data_path()) + format("detectors_descriptors_evaluation/images_datasets/graf/H1to%dp.xml", num); FileStorage fs(xml, FileStorage::READ); if (!fs.isOpened()) { ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); return; } Mat H1toCur; fs[format("H1%d", num)] >> H1toCur; for (int comb = 0; comb < 4; comb++) { matchGMS(imgCur.size(), imgRef.size(), keypointsCur, keypointsRef, matchesAll, matchesGMS, combinations[comb][0], combinations[comb][1]); int nbCorrectMatches = 0; for (size_t i = 0; i < matchesGMS.size(); i++) { Point2f ptRef = keypointsRef[matchesGMS[i].trainIdx].pt; Point2f ptCur = keypointsCur[matchesGMS[i].queryIdx].pt; Mat matRef = (Mat_(3,1) << ptRef.x, ptRef.y, 1); Mat matTrans = H1toCur * matRef; Point2f ptTrans( (float) (matTrans.at(0,0)/matTrans.at(2,0)), (float) (matTrans.at(1,0)/matTrans.at(2,0))); if (cv::norm(ptTrans-ptCur) < correctMatchDistThreshold) nbCorrectMatches++; } double ratio = nbCorrectMatches / (double) matchesGMS.size(); EXPECT_GT(ratio, eps[num-startImg][comb]) << cv::format("Invalid accuracy for image %s and combination withRotation=%d withScale=%d, " "matches ratio is %g, ratio threshold is %g, distance threshold is %g.", fileName.c_str(), combinations[comb][0], combinations[comb][1], ratio, eps[num-startImg][comb], correctMatchDistThreshold); } } } TEST(XFeatures2d_GMSMatcher, gms_matcher_regression) { CV_GMSMatcherTest test; test.safe_run(); } }} // namespace