diff --git a/modules/features2d/include/opencv2/features2d/features2d.hpp b/modules/features2d/include/opencv2/features2d/features2d.hpp index c21d6fcb3..1716d585b 100644 --- a/modules/features2d/include/opencv2/features2d/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d/features2d.hpp @@ -1931,13 +1931,13 @@ protected: template inline void BruteForceMatcher::matchImpl( const Mat& query, const Mat& mask, vector& matches ) const { - vector matchings; - matchImpl( query, mask, matchings); + vector fullMatches; + matchImpl( query, mask, fullMatches); matches.clear(); - matches.resize( matchings.size() ); - for( size_t i=0;i::matchImpl( const Mat& query, const Mat& mask, int dimension = query.cols; matches.clear(); - matches.resize(query.rows); + matches.reserve(query.rows); for( int i = 0; i < query.rows; i++ ) { @@ -1983,7 +1983,7 @@ void BruteForceMatcher::matchImpl( const Mat& query, const Mat& mask, match.indexTrain = matchIndex; match.indexQuery = i; match.distance = matchDistance; - matches[i] = match; + matches.push_back( match ); } } } @@ -2028,7 +2028,8 @@ void BruteForceMatcher::matchImpl( const Mat& query, const Mat& mask, } template<> -void BruteForceMatcher >::matchImpl( const Mat& query, const Mat& mask, vector& matches ) const; +void BruteForceMatcher >::matchImpl( const Mat& query, const Mat& mask, vector& matches ) const; +//void BruteForceMatcher >::matchImpl( const Mat& query, const Mat& mask, vector& matches ) const; CV_EXPORTS Ptr createDescriptorMatcher( const string& descriptorMatcherType ); diff --git a/modules/features2d/src/descriptors.cpp b/modules/features2d/src/descriptors.cpp index 0b44a2f2c..b89d68bc0 100644 --- a/modules/features2d/src/descriptors.cpp +++ b/modules/features2d/src/descriptors.cpp @@ -427,8 +427,11 @@ Ptr createDescriptorMatcher( const string& descriptorMatcherT * BruteForceMatcher L2 specialization * \****************************************************************************************/ template<> -void BruteForceMatcher >::matchImpl( const Mat& query, const Mat& /*mask*/, vector& matches ) const +void BruteForceMatcher >::matchImpl( const Mat& query, const Mat& mask, vector& matches ) const { + assert( mask.empty() || (mask.rows == query.rows && mask.cols == train.rows) ); + assert( query.cols == train.cols || query.empty() || train.empty() ); + matches.clear(); matches.reserve( query.rows ); #if (!defined HAVE_EIGEN2) @@ -440,9 +443,27 @@ void BruteForceMatcher >::matchImpl( const Mat& query, const Mat& /*ma { Mat distances = (-2)*query.row(i)*desc_2t; distances += norms; + DMatch match; + match.indexTrain = -1; + double minVal; Point minLoc; - minMaxLoc ( distances, 0, 0, &minLoc ); - matches.push_back( minLoc.x ); + if( mask.empty() ) + { + minMaxLoc ( distances, &minVal, 0, &minLoc ); + } + else + { + minMaxLoc ( distances, &minVal, 0, &minLoc, 0, mask.row( i ) ); + } + match.indexTrain = minLoc.x; + + if( match.indexTrain != -1 ) + { + match.indexQuery = i; + double queryNorm = norm( query.row(i) ); + match.distance = sqrt( minVal + queryNorm*queryNorm ); + matches.push_back( match ); + } } #else @@ -451,21 +472,46 @@ void BruteForceMatcher >::matchImpl( const Mat& query, const Mat& /*ma cv2eigen( query.t(), desc1t); cv2eigen( train, desc2 ); - //Eigen::Matrix norms = desc2.rowwise().squaredNorm(); Eigen::Matrix norms = desc2.rowwise().squaredNorm() / 2; - for( int i=0;i distances = (-2) * (desc2*desc1t.col(i)); - Eigen::Matrix distances = desc2*desc1t.col(i); + for( int i=0;i distances = desc2*desc1t.col(i); + distances -= norms; + DMatch match; + match.indexQuery = i; + match.distance = sqrt( (-2)*distances.maxCoeff( &match.indexTrain ) + desc1t.col(i).squaredNorm() ); + matches.push_back( match ); + } + } + else + { + for( int i=0;i distances = desc2*desc1t.col(i); + distances -= norms; - //distances += norms; - distances -= norms; + float maxCoeff = -std::numeric_limits::max(); + DMatch match; + match.indexTrain = -1; + for( int j=0;j maxCoeff ) + { + maxCoeff = distances( j, 0 ); + match.indexTrain = j; + } + } - int idx; - - //distances.minCoeff(&idx); - distances.maxCoeff(&idx); - matches.push_back( idx ); + if( match.indexTrain != -1 ) + { + match.indexQuery = i; + match.distance = sqrt( (-2)*maxCoeff + desc1t.col(i).squaredNorm() ); + matches.push_back( match ); + } + } } #endif } diff --git a/tests/cv/src/tabruteforcematcher.cpp b/tests/cv/src/tabruteforcematcher.cpp index 81895709e..fb0e3a534 100644 --- a/tests/cv/src/tabruteforcematcher.cpp +++ b/tests/cv/src/tabruteforcematcher.cpp @@ -31,7 +31,8 @@ void BruteForceMatcherTest::run( int ) for( int i=0;i( 0, i ) = i; - RNG rng (cvGetTickCount()); + //RNG rng = RNG( cvGetTickCount() ); + RNG rng = RNG( *ts->get_rng() ); randShuffle( permutation, 1, &rng ); float boundary = 500.f; @@ -45,7 +46,7 @@ void BruteForceMatcherTest::run( int ) } } - vector specMatches, genericMatches; + vector specMatches, genericMatches; BruteForceMatcher > specMatcher; BruteForceMatcher genericMatcher; specMatcher.add( train ); @@ -70,7 +71,45 @@ void BruteForceMatcherTest::run( int ) ts->set_failed_test_info( CvTS::FAIL_INVALID_OUTPUT ); for( int i=0;i( 0, i ) || genericMatches[i] != permutation.at( 0, i ) ) + float epsilon = 1e-2; + bool isEquiv = fabs( specMatches[i].distance - genericMatches[i].distance ) < epsilon && specMatches[i].indexQuery == genericMatches[i].indexQuery && specMatches[i].indexTrain == genericMatches[i].indexTrain; + if( !isEquiv || specMatches[i].indexTrain != permutation.at( 0, i ) ) + { + ts->set_failed_test_info( CvTS::FAIL_MISMATCH ); + break; + } + } + + + //Test mask + Mat mask( query.rows, train.rows, CV_8UC1 ); + rng.fill( mask, RNG::UNIFORM, 0, 2 ); + + + time0 = cvGetTickCount(); + specMatcher.match( query, mask, specMatches ); + time1 = cvGetTickCount(); + genericMatcher.match( query, mask, genericMatches ); + time2 = cvGetTickCount(); + + specMatcherTime = float(time1 - time0)/(float)cvGetTickFrequency(); + ts->printf( CvTS::LOG, "Matching by matrix multiplication time with mask s: %f, us per pair: %f\n", + specMatcherTime*1e-6, specMatcherTime/( descriptorsNumber*descriptorsNumber ) ); + + genericMatcherTime = float(time2 - time1)/(float)cvGetTickFrequency(); + ts->printf( CvTS::LOG, "Matching without matrix multiplication time with mask s: %f, us per pair: %f\n", + genericMatcherTime*1e-6, genericMatcherTime/( descriptorsNumber*descriptorsNumber ) ); + + if( specMatches.size() != genericMatches.size() ) + ts->set_failed_test_info( CvTS::FAIL_INVALID_OUTPUT ); + + + for( int i=0;iset_failed_test_info( CvTS::FAIL_MISMATCH ); break;