diff --git a/modules/features2d/test/test_matchers_algorithmic.cpp b/modules/features2d/test/test_matchers_algorithmic.cpp index d76715dd95..853546124c 100644 --- a/modules/features2d/test/test_matchers_algorithmic.cpp +++ b/modules/features2d/test/test_matchers_algorithmic.cpp @@ -57,6 +57,9 @@ public: CV_DescriptorMatcherTest( const string& _name, const Ptr& _dmatcher, float _badPart ) : badPart(_badPart), name(_name), dmatcher(_dmatcher) {} + + static void generateData( Mat& query, Mat& train ); + protected: static const int dim = 500; static const int queryDescCount = 300; // must be even number because we split train data in some cases in two @@ -64,7 +67,6 @@ protected: const float badPart; virtual void run( int ); - void generateData( Mat& query, Mat& train ); void emptyDataTest(); void matchTest( const Mat& query, const Mat& train ); @@ -526,6 +528,81 @@ void CV_DescriptorMatcherTest::run( int ) radiusMatchTest( query, train ); } +// bug #3172: test that knnMatch() can handle images with fewer than knn keypoints +class CV_DescriptorMatcherLowKeypointTest : public cvtest::BaseTest +{ +public: + CV_DescriptorMatcherLowKeypointTest( const string& _name, const Ptr& _dmatcher ) : + name(_name), dmatcher(_dmatcher) + {} +protected: + virtual void run(int); + + void knnMatchTest( const Mat& query, const Mat& train ); + +private: + string name; + Ptr dmatcher; +}; + +void CV_DescriptorMatcherLowKeypointTest::knnMatchTest( const Mat& query, const Mat& train ) +{ + const int knn = 6; + const int queryDescCount = query.rows; + vector > matches; + + // three train images, the third one with only one keypoint + dmatcher->add( vector(1,train.rowRange(0, train.rows/2)) ); + dmatcher->add( vector(1,train.rowRange(train.rows/2, train.rows-1)) ); + dmatcher->add( vector(1,train.rowRange(train.rows-1, train.rows)) ); + const int trainImgCount = (int)dmatcher->getTrainDescriptors().size(); + + dmatcher->knnMatch( query, matches, knn, std::vector(), true ); + + if( matches.empty() ) + { + ts->printf(cvtest::TS::LOG, "No matches while testing knnMatch() function (3).\n"); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + } + else + { + int badImgIdxCount = 0, badQueryIdxCount = 0, badTrainIdxCount = 0; + for( size_t i = 0; i < matches.size(); i++ ) + { + for( size_t j = 0; j < matches[i].size(); j++ ) + { + const DMatch& match = matches[i][j]; + if( match.imgIdx < 0 || match.imgIdx >= trainImgCount ) + { + ++badImgIdxCount; + } + if( match.queryIdx < 0 || match.queryIdx >= queryDescCount ) + { + ++badQueryIdxCount; + } + if( match.trainIdx < 0 ) + { + ++badTrainIdxCount; + } + } + } + if( badImgIdxCount > 0 || badQueryIdxCount > 0 || badTrainIdxCount > 0 ) + { + ts->printf( cvtest::TS::LOG, "%d/%d/%d - wrong image/query/train indices while testing knnMatch() function (3).\n", + badImgIdxCount, badQueryIdxCount, badTrainIdxCount ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + } + } +} + +void CV_DescriptorMatcherLowKeypointTest::run( int ) +{ + Mat query, train; + CV_DescriptorMatcherTest::generateData( query, train ); + + knnMatchTest( query, train ); +} + /****************************************************************************************\ * Tests registrations * \****************************************************************************************/ @@ -541,3 +618,15 @@ TEST( Features2d_DescriptorMatcher_FlannBased, regression ) CV_DescriptorMatcherTest test( "descriptor-matcher-flann-based", Algorithm::create("DescriptorMatcher.FlannBasedMatcher"), 0.04f ); test.safe_run(); } + +TEST( Features2d_DescriptorMatcher_LowKeypoint_BruteForce, regression ) +{ + CV_DescriptorMatcherLowKeypointTest test( "descriptor-matcher-low-keypoint-brute-force", Algorithm::create("DescriptorMatcher.BFMatcher") ); + test.safe_run(); +} + +TEST(Features2d_DescriptorMatcher_LowKeypoint_FlannBased, regression) +{ + CV_DescriptorMatcherLowKeypointTest test( "descriptor-matcher-low-keypoint-flann-based", Algorithm::create("DescriptorMatcher.FlannBasedMatcher") ); + test.safe_run(); +}