fixed FernDescriptorMatch; optimized keypoint regions matching in detector/descriptor...
authorMaria Dimashova <no@email>
Mon, 4 Oct 2010 14:12:36 +0000 (14:12 +0000)
committerMaria Dimashova <no@email>
Mon, 4 Oct 2010 14:12:36 +0000 (14:12 +0000)
modules/features2d/include/opencv2/features2d/features2d.hpp
modules/features2d/src/evaluation.cpp
modules/features2d/src/matchers.cpp
samples/cpp/generic_descriptor_match.cpp
tests/cv/src/adetectordescriptor_evaluation.cpp

index ac48591..82f5d92 100644 (file)
@@ -2128,7 +2128,8 @@ protected:
     Params params;
 };
 
-CV_EXPORTS Ptr<GenericDescriptorMatch> createGenericDescriptorMatch( const string& genericDescritptorMatchType, const string &paramsFilename = string () );
+CV_EXPORTS Ptr<GenericDescriptorMatch> createGenericDescriptorMatcher( const string& genericDescritptorMatcherType,
+                                                                       const string &paramsFilename = string () );
 
 /****************************************************************************************\
 *                                VectorDescriptorMatch                                   *
index 53959b2..d440be5 100644 (file)
@@ -204,15 +204,75 @@ static void filterEllipticKeyPointsByImageSize( vector<EllipticKeyPoint>& keypoi
     }
 }
 
-static void overlap( const vector<EllipticKeyPoint>& keypoints1, const vector<EllipticKeyPoint>& keypoints2t, bool commonPart,
-                     SparseMat_<float>& overlaps )
+struct IntersectAreaCounter
 {
+    IntersectAreaCounter() : bua(0.f), bna(0.f) {}
+    IntersectAreaCounter( float _miny, float _maxy, float _dr, const Point2f& _diff,
+                          const Scalar& _ellipse1, const Scalar& _ellipse2 ) : bua(0.f), bna(0.f),
+                                                                               miny(_miny), maxy(_maxy), dr(_dr), diff(_diff),
+                                                                               ellipse1(_ellipse1), ellipse2(_ellipse2) {}
+    void operator()( const BlockedRange& range )
+    {
+        float temp_bua = bua, temp_bna = bna;
+        for( float rx1 = range.begin(); rx1 <= range.end(); rx1 += dr )
+        {
+            float rx2 = rx1 - diff.x;
+            for( float ry1 = miny; ry1 <= maxy; ry1 += dr )
+            {
+                float ry2 = ry1 - diff.y;
+                //compute the distance from the ellipse center
+                float e1 = (float)(ellipse1[0]*rx1*rx1 + 2*ellipse1[1]*rx1*ry1 + ellipse1[2]*ry1*ry1);
+                float e2 = (float)(ellipse2[0]*rx2*rx2 + 2*ellipse2[1]*rx2*ry2 + ellipse2[2]*ry2*ry2);
+                //compute the area
+                if( e1<1 && e2<1 ) temp_bna++;
+                if( e1<1 || e2<1 ) temp_bua++;
+            }
+        }
+        bua = temp_bua;
+        bna = temp_bna;
+    }
+    void join( IntersectAreaCounter& ac )
+    {
+        bua += ac.bua;
+        bna += ac.bna;
+    }
+
+    float bua, bna;
+
+    float miny, maxy, dr;
+    Point2f diff;
+    Scalar ellipse1, ellipse2;
+
+};
+
+struct SIdx
+{
+    SIdx() : S(-1), i1(-1), i2(-1) {}
+    SIdx(float _S, int _i1, int _i2) : S(_S), i1(_i1), i2(_i2) {}
+    float S;
+    int i1;
+    int i2;
+
+    bool operator<(const SIdx& v) const { return S > v.S; }
+
+    struct UsedFinder
+    {
+        UsedFinder(const SIdx& _used) : used(_used) {}
+        const SIdx& used;
+        bool operator()(const SIdx& v) const { return  (v.i1 == used.i1 || v.i2 == used.i2); }
+    };
+};
+
+static void computeOneToOneMatchedOverlaps( const vector<EllipticKeyPoint>& keypoints1, const vector<EllipticKeyPoint>& keypoints2t,
+                                            bool commonPart, vector<SIdx>& overlaps, float minOverlap )
+{
+    CV_Assert( minOverlap >= 0.f );
     overlaps.clear();
     if( keypoints1.empty() || keypoints2t.empty() )
         return;
 
-    int size[] = { keypoints1.size(), keypoints2t.size() };
-    overlaps.create( 2, size );
+    overlaps.clear();
+    overlaps.reserve(cvRound(keypoints1.size() * keypoints2t.size() * 0.01));
 
     for( size_t i1 = 0; i1 < keypoints1.size(); i1++ )
     {
@@ -246,34 +306,40 @@ static void overlap( const vector<EllipticKeyPoint>& keypoints1, const vector<El
                 float miny = floor((-keypoint1a.boundingBox.height < (diff.y-keypoint2a.boundingBox.height)) ?
                                     -keypoint1a.boundingBox.height : (diff.y-keypoint2a.boundingBox.height));
                 float mina = (maxx-minx) < (maxy-miny) ? (maxx-minx) : (maxy-miny) ;
-                float dr = mina/50.f;
-                float bua = 0.f, bna = 0.f;
+
                 //compute the area
-                for( float rx1 = minx; rx1 <= maxx; rx1+=dr )
+                float dr = mina/50.f;
+                IntersectAreaCounter ac( miny, maxy, dr, diff, keypoint1a.ellipse, keypoint2a.ellipse );
+                parallel_reduce( BlockedRange(minx, maxx), ac );
+                if( ac.bna > 0 )
                 {
-                    float rx2 = rx1-diff.x;
-                    for( float ry1=miny; ry1<=maxy; ry1+=dr )
-                    {
-                        float ry2=ry1-diff.y;
-                        //compute the distance from the ellipse center
-                        float e1 = (float)(keypoint1a.ellipse[0]*rx1*rx1+2*keypoint1a.ellipse[1]*rx1*ry1+keypoint1a.ellipse[2]*ry1*ry1);
-                        float e2 = (float)(keypoint2a.ellipse[0]*rx2*rx2+2*keypoint2a.ellipse[1]*rx2*ry2+keypoint2a.ellipse[2]*ry2*ry2);
-                        //compute the area
-                        if( e1<1 && e2<1 ) bna++;
-                        if( e1<1 || e2<1 ) bua++;
-                    }
+                    float ov =  ac.bna / ac.bua;
+                    if( ov >= minOverlap )
+                        overlaps.push_back(SIdx(ov, i1, i2));
                 }
-                if( bna > 0)
-                    overlaps.ref(i1,i2) = bna/bua;
             }
         }
     }
+
+    sort( overlaps.begin(), overlaps.end() );
+
+    typedef vector<SIdx>::iterator It;
+
+    It pos = overlaps.begin();
+    It end = overlaps.end();
+
+    while(pos != end)
+    {
+        It prev = pos++;
+        end = std::remove_if(pos, end, SIdx::UsedFinder(*prev));
+    }
+    overlaps.erase(pos, overlaps.end());
 }
 
 static void calculateRepeatability( const Mat& img1, const Mat& img2, const Mat& H1to2,
                                     const vector<KeyPoint>& _keypoints1, const vector<KeyPoint>& _keypoints2,
                                     float& repeatability, int& correspondencesCount,
-                                    SparseMat_<uchar>* thresholdedOverlapMask=0 )
+                                    Mat* thresholdedOverlapMask=0  )
 {
     vector<EllipticKeyPoint> keypoints1, keypoints2, keypoints1t, keypoints2t;
     EllipticKeyPoint::convert( _keypoints1, keypoints1 );
@@ -284,8 +350,8 @@ static void calculateRepeatability( const Mat& img1, const Mat& img2, const Mat&
     Mat H2to1; invert(H1to2, H2to1);
     EllipticKeyPoint::calcProjection( keypoints2, H2to1, keypoints2t );
 
-    bool ifEvaluateDetectors = !thresholdedOverlapMask; // == commonPart
     float overlapThreshold;
+    bool ifEvaluateDetectors = thresholdedOverlapMask == 0;
     if( ifEvaluateDetectors )
     {
         overlapThreshold = 1.f - 0.4f;
@@ -300,57 +366,34 @@ static void calculateRepeatability( const Mat& img1, const Mat& img2, const Mat&
     else
     {
         overlapThreshold = 1.f - 0.5f;
+
+        thresholdedOverlapMask->create( keypoints1.size(), keypoints2t.size(), CV_8UC1 );
+        thresholdedOverlapMask->setTo( Scalar::all(0) );
     }
     int minCount = min( keypoints1.size(), keypoints2t.size() );
 
     // calculate overlap errors
-    SparseMat_<float> overlaps;
-    overlap( keypoints1, keypoints2t, ifEvaluateDetectors, overlaps );
+    vector<SIdx> overlaps;
+    computeOneToOneMatchedOverlaps( keypoints1, keypoints2t, ifEvaluateDetectors, overlaps, overlapThreshold/*min overlap*/ );
 
     correspondencesCount = -1;
     repeatability = -1.f;
-    const int* size = overlaps.size();
-    if( !size || overlaps.nzcount() == 0 )
+    if( overlaps.empty() )
         return;
 
     if( ifEvaluateDetectors )
     {
-        // threshold the overlaps
-        for( int y = 0; y < size[0]; y++ )
-        {
-            for( int x = 0; x < size[1]; x++ )
-            {
-                if ( overlaps(y,x) < overlapThreshold )
-                    overlaps.erase(y,x);
-            }
-        }
-
         // regions one-to-one matching
-        correspondencesCount = 0;
-        while( overlaps.nzcount() > 0 )
-        {
-            double maxOverlap = 0;
-            int maxIdx[2];
-            minMaxLoc( overlaps, 0, &maxOverlap, 0, maxIdx );
-            for( size_t i1 = 0; i1 < keypoints1.size(); i1++ )
-                overlaps.erase(i1, maxIdx[1]);
-            for( size_t i2 = 0; i2 < keypoints2t.size(); i2++ )
-                overlaps.erase(maxIdx[0], i2);
-            correspondencesCount++;
-        }
-        repeatability = minCount ? (float)correspondencesCount/minCount : -1;
+        correspondencesCount = overlaps.size();
+        repeatability = minCount ? (float)correspondencesCount / minCount : -1;
     }
     else
     {
-        thresholdedOverlapMask->create( 2, size );
-        for( int y = 0; y < size[0]; y++ )
+        for( size_t i = 0; i < overlaps.size(); i++ )
         {
-            for( int x = 0; x < size[1]; x++ )
-            {
-                float val = overlaps(y,x);
-                if ( val >= overlapThreshold )
-                    thresholdedOverlapMask->ref(y,x) = 1;
-            }
+            int y = overlaps[i].i1;
+            int x = overlaps[i].i2;
+            thresholdedOverlapMask->at<uchar>(y,x) = 1;
         }
     }
 }
@@ -462,8 +505,9 @@ void cv::evaluateGenericDescriptorMatcher( const Mat& img1, const Mat& img2, con
     dmatch->clear();
 
     vector<vector<DMatch> > *matches1to2, buf1;
-    vector<vector<uchar> > *correctMatches1to2Mask, buf2;
     matches1to2 = _matches1to2 != 0 ? _matches1to2 : &buf1;
+
+    vector<vector<uchar> > *correctMatches1to2Mask, buf2;
     correctMatches1to2Mask = _correctMatches1to2Mask != 0 ? _correctMatches1to2Mask : &buf2;
 
     if( keypoints1.empty() )
@@ -488,14 +532,10 @@ void cv::evaluateGenericDescriptorMatcher( const Mat& img1, const Mat& img2, con
     }
     float repeatability;
     int correspCount;
-    SparseMat_<uchar> thresholdedOverlapMask; // thresholded allOverlapErrors
-    calculateRepeatability( img1, img2, H1to2,
-                            keypoints1, keypoints2,
-                            repeatability, correspCount,
-                            &thresholdedOverlapMask );
+    Mat thresholdedOverlapMask; // thresholded allOverlapErrors
+    calculateRepeatability( img1, img2, H1to2, keypoints1, keypoints2, repeatability, correspCount, &thresholdedOverlapMask );
 
     correctMatches1to2Mask->resize(matches1to2->size());
-    int ddd = 0;
     for( size_t i = 0; i < matches1to2->size(); i++ )
     {
         (*correctMatches1to2Mask)[i].resize((*matches1to2)[i].size());
@@ -503,8 +543,7 @@ void cv::evaluateGenericDescriptorMatcher( const Mat& img1, const Mat& img2, con
         {
             int indexQuery = (*matches1to2)[i][j].indexQuery;
             int indexTrain = (*matches1to2)[i][j].indexTrain;
-            (*correctMatches1to2Mask)[i][j] = thresholdedOverlapMask( indexQuery, indexTrain );
-            ddd += thresholdedOverlapMask( indexQuery, indexTrain ) != 0 ? 1 : 0;
+            (*correctMatches1to2Mask)[i][j] = thresholdedOverlapMask.at<uchar>( indexQuery, indexTrain );
         }
     }
 
index 77cef80..c8eaed2 100755 (executable)
@@ -569,7 +569,7 @@ void FernDescriptorMatch::trainFernClassifier()
     {
         assert( params.filename.empty() );
 
-        vector<vector<Point2f> > points;
+        vector<vector<Point2f> > points(collection.images.size());
         for( size_t imgIdx = 0; imgIdx < collection.images.size(); imgIdx++ )
             KeyPoint::convert( collection.points[imgIdx], points[imgIdx] );
 
@@ -757,34 +757,34 @@ void VectorDescriptorMatch::write (FileStorage& fs) const
 /****************************************************************************************\
 *                Factory function for GenericDescriptorMatch creating                    *
 \****************************************************************************************/
-Ptr<GenericDescriptorMatch> createGenericDescriptorMatch( const string& genericDescritptorMatchType,
-                                                          const string &paramsFilename )
+Ptr<GenericDescriptorMatch> createGenericDescriptorMatcher( const string& genericDescritptorMatcherType,
+                                                            const string &paramsFilename )
 {
-    GenericDescriptorMatch *descriptorMatch = 0;
-    if( ! genericDescritptorMatchType.compare("ONEWAY") )
+    GenericDescriptorMatch *descriptorMatcher = 0;
+    if( ! genericDescritptorMatcherType.compare("ONEWAY") )
     {
-        descriptorMatch = new OneWayDescriptorMatch();
+        descriptorMatcher = new OneWayDescriptorMatch();
     }
-    else if( ! genericDescritptorMatchType.compare("FERN") )
+    else if( ! genericDescritptorMatcherType.compare("FERN") )
     {
-        descriptorMatch = new FernDescriptorMatch();
+        descriptorMatcher = new FernDescriptorMatch();
     }
-    else if( ! genericDescritptorMatchType.compare ("CALONDER") )
+    else if( ! genericDescritptorMatcherType.compare ("CALONDER") )
     {
         //descriptorMatch = new CalonderDescriptorMatch ();
     }
 
-    if( !paramsFilename.empty() && descriptorMatch != 0 )
+    if( !paramsFilename.empty() && descriptorMatcher != 0 )
     {
         FileStorage fs = FileStorage( paramsFilename, FileStorage::READ );
         if( fs.isOpened() )
         {
-            descriptorMatch->read( fs.root() );
+            descriptorMatcher->read( fs.root() );
             fs.release();
         }
     }
 
-    return descriptorMatch;
+    return descriptorMatcher;
 }
 
 }
index eef8baa..45d57a2 100644 (file)
@@ -24,8 +24,8 @@ int main(int argc, char** argv)
     std::string alg_name = std::string(argv[3]);
     std::string params_filename = std::string(argv[4]);
 
-    GenericDescriptorMatch *descriptorMatch = createGenericDescriptorMatch(alg_name, params_filename);
-    if( descriptorMatch == 0 )
+    GenericDescriptorMatch *descriptorMatcher = createGenericDescriptorMatcher(alg_name, params_filename);
+    if( descriptorMatcher == 0 )
     {
         printf ("Cannot create descriptor\n");
         return 0;
@@ -50,10 +50,10 @@ int main(int argc, char** argv)
 
     printf("Finding nearest neighbors... \n");
     // find NN for each of keypoints2 in keypoints1
-    descriptorMatch->add( img1, keypoints1 );
+    descriptorMatcher->add( img1, keypoints1 );
     vector<int> matches2to1;
     matches2to1.resize(keypoints2.size());
-    descriptorMatch->match( img2, keypoints2, matches2to1 );
+    descriptorMatcher->match( img2, keypoints2, matches2to1 );
     printf("Done\n");
 
     IplImage* img_corr = DrawCorrespondences(img1, keypoints1, img2, keypoints2, matches2to1);
@@ -65,7 +65,7 @@ int main(int argc, char** argv)
     cvReleaseImage(&img1);
     cvReleaseImage(&img2);
     cvReleaseImage(&img_corr);
-    delete descriptorMatch;
+    delete descriptorMatcher;
 }
 
 IplImage* DrawCorrespondences(IplImage* img1, const vector<KeyPoint>& features1, IplImage* img2,
index ab39b1c..759bd16 100644 (file)
@@ -716,7 +716,7 @@ void DetectorQualityTest::runDatasetTest (const vector<Mat> &imgs, const vector<
         evaluateFeatureDetector( imgs[0], imgs[ci+1], Hs[ci], &keypoints1, &keypoints2,
                                  rep, calcQuality[di][ci].correspondenceCount,
                                  detector );
-        calcQuality[di][ci].repeatability = 100.f*rep;
+        calcQuality[di][ci].repeatability = rep == -1 ? rep : 100.f*rep;
         writeKeypoints( keypontsFS, keypoints2, ci+1);
     }
 }
@@ -732,32 +732,25 @@ void testLog( CvTS* ts, bool isBadAccuracy )
 int DetectorQualityTest::processResults( int datasetIdx, int caseIdx )
 {
     int res = CvTS::OK;
+    bool isBadAccuracy;
 
     Quality valid = validQuality[datasetIdx][caseIdx], calc = calcQuality[datasetIdx][caseIdx];
 
-    bool isBadAccuracy;
-    int countEps = 1;
-    const float rltvEps = 0.001;
+    const int countEps = 1 + cvRound( 0.005f*(float)valid.correspondenceCount );
+    const float rltvEps = 0.5f;
+
     ts->printf(CvTS::LOG, "%s: calc=%f, valid=%f", REPEAT.c_str(), calc.repeatability, valid.repeatability );
-    isBadAccuracy = valid.repeatability - calc.repeatability > rltvEps;
+    isBadAccuracy = (valid.repeatability - calc.repeatability) > rltvEps;
     testLog( ts, isBadAccuracy );
     res = isBadAccuracy ? CvTS::FAIL_BAD_ACCURACY : res;
 
     ts->printf(CvTS::LOG, "%s: calc=%d, valid=%d", CORRESP_COUNT.c_str(), calc.correspondenceCount, valid.correspondenceCount );
-    isBadAccuracy = valid.correspondenceCount - calc.correspondenceCount > countEps;
+    isBadAccuracy = (valid.correspondenceCount - calc.correspondenceCount) > countEps;
     testLog( ts, isBadAccuracy );
     res = isBadAccuracy ? CvTS::FAIL_BAD_ACCURACY : res;
     return res;
 }
 
-DetectorQualityTest fastDetectorQuality = DetectorQualityTest( "FAST", "quality-detector-fast" );
-DetectorQualityTest gfttDetectorQuality = DetectorQualityTest( "GFTT", "quality-detector-gftt" );
-DetectorQualityTest harrisDetectorQuality = DetectorQualityTest( "HARRIS", "quality-detector-harris" );
-DetectorQualityTest mserDetectorQuality = DetectorQualityTest( "MSER", "quality-detector-mser" );
-DetectorQualityTest starDetectorQuality = DetectorQualityTest( "STAR", "quality-detector-star" );
-DetectorQualityTest siftDetectorQuality = DetectorQualityTest( "SIFT", "quality-detector-sift" );
-DetectorQualityTest surfDetectorQuality = DetectorQualityTest( "SURF", "quality-detector-surf" );
-
 /****************************************************************************************\
 *                                  Descriptors evaluation                                 *
 \****************************************************************************************/
@@ -844,8 +837,8 @@ protected:
     };
     vector<CommonRunParams> commRunParams;
 
-    Ptr<GenericDescriptorMatch> specificDescMatch;
-    Ptr<GenericDescriptorMatch> defaultDescMatch;
+    Ptr<GenericDescriptorMatch> specificDescMatcher;
+    Ptr<GenericDescriptorMatch> defaultDescMatcher;
 
     CommonRunParams commRunParamsDefault;
     string matcherName;
@@ -909,7 +902,7 @@ void DescriptorQualityTest::readDefaultRunParams (FileNode &fn)
     {
         commRunParamsDefault.projectKeypointsFrom1Image = (int)fn[PROJECT_KEYPOINTS_FROM_1IMAGE] != 0;
         commRunParamsDefault.matchFilter = (int)fn[MATCH_FILTER];
-        defaultDescMatch->read (fn);
+        defaultDescMatcher->read (fn);
     }
 }
 
@@ -917,7 +910,7 @@ void DescriptorQualityTest::writeDefaultRunParams (FileStorage &fs) const
 {
     fs << PROJECT_KEYPOINTS_FROM_1IMAGE << commRunParamsDefault.projectKeypointsFrom1Image;
     fs << MATCH_FILTER << commRunParamsDefault.matchFilter;
-    defaultDescMatch->write (fs);
+    defaultDescMatcher->write (fs);
 }
 
 void DescriptorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx )
@@ -928,7 +921,7 @@ void DescriptorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx )
         commRunParams[datasetIdx].keypontsFilename = (string)fn[KEYPOINTS_FILENAME];
         commRunParams[datasetIdx].projectKeypointsFrom1Image = (int)fn[PROJECT_KEYPOINTS_FROM_1IMAGE] != 0;
         commRunParams[datasetIdx].matchFilter = (int)fn[MATCH_FILTER];
-        specificDescMatch->read (fn);
+        specificDescMatcher->read (fn);
     }
     else
     {
@@ -943,13 +936,13 @@ void DescriptorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetI
     fs << PROJECT_KEYPOINTS_FROM_1IMAGE << commRunParams[datasetIdx].projectKeypointsFrom1Image;
     fs << MATCH_FILTER << commRunParams[datasetIdx].matchFilter;
 
-    defaultDescMatch->write (fs);
+    defaultDescMatcher->write (fs);
 }
 
 void DescriptorQualityTest::setDefaultDatasetRunParams( int datasetIdx )
 {
     commRunParams[datasetIdx] = commRunParamsDefault;
-    commRunParams[datasetIdx].keypontsFilename = "surf_" + DATASET_NAMES[datasetIdx] + ".xml.gz";
+    commRunParams[datasetIdx].keypontsFilename = "SURF_" + DATASET_NAMES[datasetIdx] + ".xml.gz";
 }
 
 void DescriptorQualityTest::writePlotData( int di ) const
@@ -967,15 +960,15 @@ void DescriptorQualityTest::writePlotData( int di ) const
 
 void DescriptorQualityTest::readAlgorithm( )
 {
-    defaultDescMatch = createGenericDescriptorMatch( algName );
-    specificDescMatch = createGenericDescriptorMatch( algName );
+    defaultDescMatcher = createGenericDescriptorMatcher( algName );
+    specificDescMatcher = createGenericDescriptorMatcher( algName );
 
-    if( defaultDescMatch == 0 )
+    if( defaultDescMatcher == 0 )
     {
         Ptr<DescriptorExtractor> extractor = createDescriptorExtractor( algName );
         Ptr<DescriptorMatcher> matcher = createDescriptorMatcher( matcherName );
-        defaultDescMatch = new VectorDescriptorMatch( extractor, matcher );
-        specificDescMatch = new VectorDescriptorMatch( extractor, matcher );
+        defaultDescMatcher = new VectorDescriptorMatch( extractor, matcher );
+        specificDescMatcher = new VectorDescriptorMatch( extractor, matcher );
 
         if( extractor == 0 || matcher == 0 )
         {
@@ -1035,7 +1028,7 @@ void DescriptorQualityTest::runDatasetTest (const vector<Mat> &imgs, const vecto
        return;
     }
 
-    Ptr<GenericDescriptorMatch> descMatch = commRunParams[di].isActiveParams ? specificDescMatch : defaultDescMatch;
+    Ptr<GenericDescriptorMatch> descMatch = commRunParams[di].isActiveParams ? specificDescMatcher : defaultDescMatcher;
     calcQuality[di].resize(TEST_CASE_COUNT);
 
     vector<KeyPoint> keypoints1;
@@ -1076,28 +1069,40 @@ void DescriptorQualityTest::runDatasetTest (const vector<Mat> &imgs, const vecto
 
 int DescriptorQualityTest::processResults( int datasetIdx, int caseIdx )
 {
+    const float rltvEps = 0.001f;
+
     int res = CvTS::OK;
+    bool isBadAccuracy;
+
     Quality valid = validQuality[datasetIdx][caseIdx], calc = calcQuality[datasetIdx][caseIdx];
 
-    bool isBadAccuracy;
-    const float rltvEps = 0.001f;
     ts->printf(CvTS::LOG, "%s: calc=%f, valid=%f", RECALL.c_str(), calc.recall, valid.recall );
-    isBadAccuracy = valid.recall - calc.recall > rltvEps;
+    isBadAccuracy = (valid.recall - calc.recall) > rltvEps;
     testLog( ts, isBadAccuracy );
     res = isBadAccuracy ? CvTS::FAIL_BAD_ACCURACY : res;
 
     ts->printf(CvTS::LOG, "%s: calc=%f, valid=%f", PRECISION.c_str(), calc.precision, valid.precision );
-    isBadAccuracy = valid.precision - calc.precision > rltvEps;
+    isBadAccuracy = (valid.precision - calc.precision) > rltvEps;
     testLog( ts, isBadAccuracy );
     res = isBadAccuracy ? CvTS::FAIL_BAD_ACCURACY : res;
 
     return res;
 }
 
-//DescriptorQualityTest siftDescriptorQuality = DescriptorQualityTest( "SIFT", "quality-descriptor-sift", "BruteForce" );
-//DescriptorQualityTest surfDescriptorQuality = DescriptorQualityTest( "SURF", "quality-descriptor-surf", "BruteForce" );
-//DescriptorQualityTest siftL1DescriptorQuality = DescriptorQualityTest( "SIFT", "quality-descriptor-sift-L1", "BruteForce-L1" );
-//DescriptorQualityTest surfL1DescriptorQuality = DescriptorQualityTest( "SURF", "quality-descriptor-surf-L1", "BruteForce-L1" );
+//--------------------------------- Calonder descriptor test --------------------------------------------
+class CalonderDescriptorQualityTest : public DescriptorQualityTest
+{
+public:
+    CalonderDescriptorQualityTest() :
+            DescriptorQualityTest( "Calonder", "quality-descriptor-calonder") {}
+    virtual void readAlgorithm( )
+    {
+        string classifierFile = string(ts->get_data_path()) + "/features2d/calonder_classifier.rtc";
+        defaultDescMatcher = new VectorDescriptorMatch( new CalonderDescriptorExtractor<float>( classifierFile ),
+                                                        new BruteForceMatcher<L2<float> > );
+        specificDescMatcher = defaultDescMatcher;
+    }
+};
 
 //--------------------------------- One Way descriptor test --------------------------------------------
 class OneWayDescriptorQualityTest : public DescriptorQualityTest
@@ -1139,7 +1144,7 @@ void OneWayDescriptorQualityTest::processRunParamsFile ()
 
     OneWayDescriptorMatch *match = new OneWayDescriptorMatch ();
     match->initialize( OneWayDescriptorMatch::Params (), base );
-    defaultDescMatch = match;
+    defaultDescMatcher = match;
     writeAllDatasetsRunParams();
 }
 
@@ -1151,7 +1156,30 @@ void OneWayDescriptorQualityTest::writeDatasetRunParams( FileStorage& fs, int da
     fs << MATCH_FILTER << commRunParams[datasetIdx].matchFilter;
 }
 
+// Detectors
+//DetectorQualityTest fastDetectorQuality = DetectorQualityTest( "FAST", "quality-detector-fast" );
+//DetectorQualityTest gfttDetectorQuality = DetectorQualityTest( "GFTT", "quality-detector-gftt" );
+//DetectorQualityTest harrisDetectorQuality = DetectorQualityTest( "HARRIS", "quality-detector-harris" );
+//DetectorQualityTest mserDetectorQuality = DetectorQualityTest( "MSER", "quality-detector-mser" );
+//DetectorQualityTest starDetectorQuality = DetectorQualityTest( "STAR", "quality-detector-star" );
+//DetectorQualityTest siftDetectorQuality = DetectorQualityTest( "SIFT", "quality-detector-sift" );
+//DetectorQualityTest surfDetectorQuality = DetectorQualityTest( "SURF", "quality-detector-surf" );
 
-//OneWayDescriptorQualityTest oneWayDescriptorQuality;
+// Detectors
+//DescriptorQualityTest siftDescriptorQuality = DescriptorQualityTest( "SIFT", "quality-descriptor-sift", "BruteForce" );
+//DescriptorQualityTest surfDescriptorQuality = DescriptorQualityTest( "SURF", "quality-descriptor-surf", "BruteForce" );
 //DescriptorQualityTest fernDescriptorQualityTest( "FERN", "quality-descriptor-fern");
-//DescriptorQualityTest calonderDescriptorQualityTest( "CALONDER", "quality-descriptor-calonder");
+//CalonderDescriptorQualityTest calonderDescriptorQualityTest;
+
+
+
+// Don't run them because of bug in OneWayDescriptorBase many to many matching. TODO: fix this bug.
+//OneWayDescriptorQualityTest oneWayDescriptorQuality;
+
+// Don't run them (will validate and save results as "quality-descriptor-sift" and "quality-descriptor-surf" test data).
+// TODO: differ result filenames.
+//DescriptorQualityTest siftL1DescriptorQuality = DescriptorQualityTest( "SIFT", "quality-descriptor-sift-L1", "BruteForce-L1" );
+//DescriptorQualityTest surfL1DescriptorQuality = DescriptorQualityTest( "SURF", "quality-descriptor-surf-L1", "BruteForce-L1" );
+//DescriptorQualityTest oppSiftL1DescriptorQuality = DescriptorQualityTest( "SIFT", "quality-descriptor-opponent-sift-L1", "BruteForce-L1" );
+//DescriptorQualityTest oppSurfL1DescriptorQuality = DescriptorQualityTest( "SURF", "quality-descriptor-opponent-surf-L1", "BruteForce-L1" );
+