Fixed bugs in BruteForceMatcher and its specialization
authorIlya Lysenkov <no@email>
Wed, 4 Aug 2010 08:26:30 +0000 (08:26 +0000)
committerIlya Lysenkov <no@email>
Wed, 4 Aug 2010 08:26:30 +0000 (08:26 +0000)
modules/features2d/include/opencv2/features2d/features2d.hpp
modules/features2d/src/descriptors.cpp
tests/cv/src/tabruteforcematcher.cpp

index c21d6fc..1716d58 100644 (file)
@@ -1931,13 +1931,13 @@ protected:
 template<class Distance> inline
 void BruteForceMatcher<Distance>::matchImpl( const Mat& query, const Mat& mask, vector<int>& matches ) const
 {
-    vector<DMatch> matchings;
-    matchImpl( query, mask, matchings);
+    vector<DMatch> fullMatches;
+    matchImpl( query, mask, fullMatches);
     matches.clear();
-    matches.resize( matchings.size() );
-    for( size_t i=0;i<matchings.size();i++)
+    matches.resize( fullMatches.size() );
+    for( size_t i=0;i<fullMatches.size();i++)
     {
-        matches[i] = matchings[i].indexTrain;
+        matches[i] = fullMatches[i].indexTrain;
     }
 }
 
@@ -1955,7 +1955,7 @@ void BruteForceMatcher<Distance>::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<Distance>::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<Distance>::matchImpl( const Mat& query, const Mat& mask,
 }
 
 template<>
-void BruteForceMatcher<L2<float> >::matchImpl( const Mat& query, const Mat& mask, vector<int>& matches ) const;
+void BruteForceMatcher<L2<float> >::matchImpl( const Mat& query, const Mat& mask, vector<DMatch>& matches ) const;
+//void BruteForceMatcher<L2<float> >::matchImpl( const Mat& query, const Mat& mask, vector<int>& matches ) const;
 
 CV_EXPORTS Ptr<DescriptorMatcher> createDescriptorMatcher( const string& descriptorMatcherType );
 
index 0b44a2f..b89d68b 100644 (file)
@@ -427,8 +427,11 @@ Ptr<DescriptorMatcher> createDescriptorMatcher( const string& descriptorMatcherT
 *                             BruteForceMatcher L2 specialization                        *
 \****************************************************************************************/
 template<>
-void BruteForceMatcher<L2<float> >::matchImpl( const Mat& query, const Mat& /*mask*/, vector<int>& matches ) const
+void BruteForceMatcher<L2<float> >::matchImpl( const Mat& query, const Mat& mask, vector<DMatch>& 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<L2<float> >::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<L2<float> >::matchImpl( const Mat& query, const Mat& /*ma
     cv2eigen( query.t(), desc1t);
     cv2eigen( train, desc2 );
 
-    //Eigen::Matrix<float, Eigen::Dynamic, 1> norms = desc2.rowwise().squaredNorm();
     Eigen::Matrix<float, Eigen::Dynamic, 1> norms = desc2.rowwise().squaredNorm() / 2;
-    for( int i=0;i<query.rows;i++ )
-    {
-        //Eigen::Matrix<float, Eigen::Dynamic, 1> distances = (-2) * (desc2*desc1t.col(i));
-        Eigen::Matrix<float, Eigen::Dynamic, 1> distances = desc2*desc1t.col(i);
 
-        //distances += norms;
-        distances -= norms;
+    if( mask.empty() )
+    {
+        for( int i=0;i<query.rows;i++ )
+        {
+            Eigen::Matrix<float, Eigen::Dynamic, 1> 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<query.rows;i++ )
+        {
+            Eigen::Matrix<float, Eigen::Dynamic, 1> distances = desc2*desc1t.col(i);
+            distances -= norms;
 
-        int idx;
+            float maxCoeff = -std::numeric_limits<float>::max();
+            DMatch match;
+            match.indexTrain = -1;
+            for( int j=0;j<train.rows;j++ )
+            {
+                if( possibleMatch( mask, i, j ) && distances( j, 0 ) > maxCoeff )
+                {
+                    maxCoeff = distances( j, 0 );
+                    match.indexTrain = j;
+                }
+            }
 
-        //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
 }
index 8189570..fb0e3a5 100644 (file)
@@ -31,7 +31,8 @@ void BruteForceMatcherTest::run( int )
     for( int i=0;i<descriptorsNumber;i++ )
         permutation.at<int>( 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<int> specMatches, genericMatches;
+    vector<DMatch> specMatches, genericMatches;
     BruteForceMatcher<L2<float> > specMatcher;
     BruteForceMatcher<L2Fake > 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<descriptorsNumber;i++ )
     {
-        if( specMatches[i] != permutation.at<int>( 0, i ) || genericMatches[i] != permutation.at<int>( 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<int>( 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;i<specMatches.size();i++ )
+    {
+        //float epsilon = 1e-2;
+        float epsilon = 10000000;
+        bool isEquiv = fabs( specMatches[i].distance - genericMatches[i].distance ) < epsilon && specMatches[i].indexQuery == genericMatches[i].indexQuery && specMatches[i].indexTrain == genericMatches[i].indexTrain;
+        if( !isEquiv )
         {
             ts->set_failed_test_info( CvTS::FAIL_MISMATCH );
             break;