1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
42 #include "opencv2/imgproc.hpp"
43 #include "opencv2/highgui.hpp"
44 #include "opencv2/features2d.hpp"
45 #include "opencv2/legacy.hpp"
57 /****************************************************************************************\
58 * Functions to evaluate affine covariant detectors and descriptors. *
59 \****************************************************************************************/
61 static inline Point2f applyHomography( const Mat_<double>& H, const Point2f& pt )
63 double z = H(2,0)*pt.x + H(2,1)*pt.y + H(2,2);
67 return Point2f( (float)((H(0,0)*pt.x + H(0,1)*pt.y + H(0,2))*w),
68 (float)((H(1,0)*pt.x + H(1,1)*pt.y + H(1,2))*w) );
70 return Point2f( numeric_limits<float>::max(), numeric_limits<float>::max() );
73 static inline void linearizeHomographyAt( const Mat_<double>& H, const Point2f& pt, Mat_<double>& A )
76 double p1 = H(0,0)*pt.x + H(0,1)*pt.y + H(0,2),
77 p2 = H(1,0)*pt.x + H(1,1)*pt.y + H(1,2),
78 p3 = H(2,0)*pt.x + H(2,1)*pt.y + H(2,2),
82 A(0,0) = H(0,0)/p3 - p1*H(2,0)/p3_2; // fxdx
83 A(0,1) = H(0,1)/p3 - p1*H(2,1)/p3_2; // fxdy
85 A(1,0) = H(1,0)/p3 - p2*H(2,0)/p3_2; // fydx
86 A(1,1) = H(1,1)/p3 - p2*H(2,1)/p3_2; // fydx
89 A.setTo(Scalar::all(numeric_limits<double>::max()));
92 static void calcKeyPointProjections( const vector<KeyPoint>& src, const Mat_<double>& H, vector<KeyPoint>& dst )
96 CV_Assert( !H.empty() && H.cols == 3 && H.rows == 3);
97 dst.resize(src.size());
98 vector<KeyPoint>::const_iterator srcIt = src.begin();
99 vector<KeyPoint>::iterator dstIt = dst.begin();
100 for( ; srcIt != src.end(); ++srcIt, ++dstIt )
102 Point2f dstPt = applyHomography(H, srcIt->pt);
104 float srcSize2 = srcIt->size * srcIt->size;
105 Mat_<double> M(2, 2);
106 M(0,0) = M(1,1) = 1./srcSize2;
108 Mat_<double> invM; invert(M, invM);
109 Mat_<double> Aff; linearizeHomographyAt(H, srcIt->pt, Aff);
110 Mat_<double> dstM; invert(Aff*invM*Aff.t(), dstM);
111 Mat_<double> eval; eigen( dstM, eval );
112 CV_Assert( eval(0,0) && eval(1,0) );
113 float dstSize = (float)pow(1./(eval(0,0)*eval(1,0)), 0.25);
115 // TODO: check angle projection
116 float srcAngleRad = (float)(srcIt->angle*CV_PI/180);
117 Point2f vec1(cos(srcAngleRad), sin(srcAngleRad)), vec2;
118 vec2.x = (float)(Aff(0,0)*vec1.x + Aff(0,1)*vec1.y);
119 vec2.y = (float)(Aff(1,0)*vec1.x + Aff(0,1)*vec1.y);
120 float dstAngleGrad = fastAtan2(vec2.y, vec2.x);
122 *dstIt = KeyPoint( dstPt, dstSize, dstAngleGrad, srcIt->response, srcIt->octave, srcIt->class_id );
127 static void filterKeyPointsByImageSize( vector<KeyPoint>& keypoints, const Size& imgSize )
129 if( !keypoints.empty() )
131 vector<KeyPoint> filtered;
132 filtered.reserve(keypoints.size());
133 Rect r(0, 0, imgSize.width, imgSize.height);
134 vector<KeyPoint>::const_iterator it = keypoints.begin();
135 for( int i = 0; it != keypoints.end(); ++it, i++ )
136 if( r.contains(it->pt) )
137 filtered.push_back(*it);
138 keypoints.assign(filtered.begin(), filtered.end());
142 /****************************************************************************************\
143 * Detectors evaluation *
144 \****************************************************************************************/
145 const int DATASETS_COUNT = 8;
146 const int TEST_CASE_COUNT = 5;
148 const string IMAGE_DATASETS_DIR = "detectors_descriptors_evaluation/images_datasets/";
149 const string DETECTORS_DIR = "detectors_descriptors_evaluation/detectors/";
150 const string DESCRIPTORS_DIR = "detectors_descriptors_evaluation/descriptors/";
151 const string KEYPOINTS_DIR = "detectors_descriptors_evaluation/keypoints_datasets/";
153 const string PARAMS_POSTFIX = "_params.xml";
154 const string RES_POSTFIX = "_res.xml";
156 const string REPEAT = "repeatability";
157 const string CORRESP_COUNT = "correspondence_count";
159 string DATASET_NAMES[DATASETS_COUNT] = { "bark", "bikes", "boat", "graf", "leuven", "trees", "ubc", "wall"};
161 string DEFAULT_PARAMS = "default";
163 string IS_ACTIVE_PARAMS = "isActiveParams";
164 string IS_SAVE_KEYPOINTS = "isSaveKeypoints";
167 class BaseQualityEvaluator
170 BaseQualityEvaluator( const char* _algName, const char* _testName ) : algName(_algName), testName(_testName)
173 isWriteGraphicsData = true;
178 virtual ~BaseQualityEvaluator(){}
181 virtual string getRunParamsFilename() const = 0;
182 virtual string getResultsFilename() const = 0;
183 virtual string getPlotPath() const = 0;
185 virtual void calcQualityClear( int datasetIdx ) = 0;
186 virtual bool isCalcQualityEmpty( int datasetIdx ) const = 0;
188 void readAllDatasetsRunParams();
189 virtual void readDatasetRunParams( FileNode& fn, int datasetIdx ) = 0;
190 void writeAllDatasetsRunParams() const;
191 virtual void writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const = 0;
192 void setDefaultAllDatasetsRunParams();
193 virtual void setDefaultDatasetRunParams( int datasetIdx ) = 0;
194 virtual void readDefaultRunParams( FileNode& /*fn*/ ) {}
195 virtual void writeDefaultRunParams( FileStorage& /*fs*/ ) const {}
197 bool readDataset( const string& datasetName, vector<Mat>& Hs, vector<Mat>& imgs );
199 virtual void readAlgorithm() {}
200 virtual void processRunParamsFile() {}
201 virtual void runDatasetTest( const vector<Mat>& /*imgs*/, const vector<Mat>& /*Hs*/, int /*di*/, int& /*progress*/ ) {}
203 virtual void processResults( int datasetIdx );
204 virtual void processResults();
205 virtual void writePlotData( int /*datasetIdx*/ ) const {}
207 string algName, testName;
208 bool isWriteParams, isWriteGraphicsData;
211 void BaseQualityEvaluator::readAllDatasetsRunParams()
213 string filename = getRunParamsFilename();
214 FileStorage fs( filename, FileStorage::READ );
217 isWriteParams = true;
218 setDefaultAllDatasetsRunParams();
219 printf("All runParams are default.\n");
223 isWriteParams = false;
224 FileNode topfn = fs.getFirstTopLevelNode();
226 FileNode pfn = topfn[DEFAULT_PARAMS];
227 readDefaultRunParams(pfn);
229 for( int i = 0; i < DATASETS_COUNT; i++ )
231 FileNode fn = topfn[DATASET_NAMES[i]];
234 printf( "%d-runParams is default.\n", i);
235 setDefaultDatasetRunParams(i);
238 readDatasetRunParams(fn, i);
243 void BaseQualityEvaluator::writeAllDatasetsRunParams() const
245 string filename = getRunParamsFilename();
246 FileStorage fs( filename, FileStorage::WRITE );
249 fs << "run_params" << "{"; // top file node
250 fs << DEFAULT_PARAMS << "{";
251 writeDefaultRunParams(fs);
253 for( int i = 0; i < DATASETS_COUNT; i++ )
255 fs << DATASET_NAMES[i] << "{";
256 writeDatasetRunParams(fs, i);
262 printf( "File %s for writing run params can not be opened.\n", filename.c_str() );
265 void BaseQualityEvaluator::setDefaultAllDatasetsRunParams()
267 for( int i = 0; i < DATASETS_COUNT; i++ )
268 setDefaultDatasetRunParams(i);
271 bool BaseQualityEvaluator::readDataset( const string& datasetName, vector<Mat>& Hs, vector<Mat>& imgs )
273 Hs.resize( TEST_CASE_COUNT );
274 imgs.resize( TEST_CASE_COUNT+1 );
275 string dirname = data_path + IMAGE_DATASETS_DIR + datasetName + "/";
276 for( int i = 0; i < (int)Hs.size(); i++ )
278 stringstream filename; filename << "H1to" << i+2 << "p.xml";
279 FileStorage fs( dirname + filename.str(), FileStorage::READ );
282 cout << "filename " << dirname + filename.str() << endl;
283 FileStorage fs2( dirname + filename.str(), FileStorage::READ );
286 fs.getFirstTopLevelNode() >> Hs[i];
289 for( int i = 0; i < (int)imgs.size(); i++ )
291 stringstream filename; filename << "img" << i+1 << ".png";
292 imgs[i] = imread( dirname + filename.str(), 0 );
293 if( imgs[i].empty() )
295 cout << "filename " << filename.str() << endl;
302 void BaseQualityEvaluator::processResults( int datasetIdx )
304 if( isWriteGraphicsData )
305 writePlotData( datasetIdx );
308 void BaseQualityEvaluator::processResults()
311 writeAllDatasetsRunParams();
314 void BaseQualityEvaluator::run()
317 processRunParamsFile ();
319 int notReadDatasets = 0;
322 FileStorage runParamsFS( getRunParamsFilename(), FileStorage::READ );
323 isWriteParams = (! runParamsFS.isOpened());
324 FileNode topfn = runParamsFS.getFirstTopLevelNode();
325 FileNode defaultParams = topfn[DEFAULT_PARAMS];
326 readDefaultRunParams (defaultParams);
328 cout << testName << endl;
329 for(int di = 0; di < DATASETS_COUNT; di++ )
331 cout << "Dataset " << di << " [" << DATASET_NAMES[di] << "] " << flush;
332 vector<Mat> imgs, Hs;
333 if( !readDataset( DATASET_NAMES[di], Hs, imgs ) )
335 calcQualityClear (di);
336 printf( "Images or homography matrices of dataset named %s can not be read\n",
337 DATASET_NAMES[di].c_str());
342 FileNode fn = topfn[DATASET_NAMES[di]];
343 readDatasetRunParams(fn, di);
345 runDatasetTest (imgs, Hs, di, progress);
346 processResults( di );
349 if( notReadDatasets == DATASETS_COUNT )
351 printf( "All datasets were not be read\n");
356 runParamsFS.release();
361 class DetectorQualityEvaluator : public BaseQualityEvaluator
364 DetectorQualityEvaluator( const char* _detectorName, const char* _testName ) : BaseQualityEvaluator( _detectorName, _testName )
366 calcQuality.resize(DATASETS_COUNT);
367 isSaveKeypoints.resize(DATASETS_COUNT);
368 isActiveParams.resize(DATASETS_COUNT);
370 isSaveKeypointsDefault = false;
371 isActiveParamsDefault = false;
375 virtual string getRunParamsFilename() const;
376 virtual string getResultsFilename() const;
377 virtual string getPlotPath() const;
379 virtual void calcQualityClear( int datasetIdx );
380 virtual bool isCalcQualityEmpty( int datasetIdx ) const;
382 virtual void readDatasetRunParams( FileNode& fn, int datasetIdx );
383 virtual void writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const;
384 virtual void setDefaultDatasetRunParams( int datasetIdx );
385 virtual void readDefaultRunParams( FileNode &fn );
386 virtual void writeDefaultRunParams( FileStorage &fs ) const;
388 virtual void writePlotData( int di ) const;
390 void openToWriteKeypointsFile( FileStorage& fs, int datasetIdx );
392 virtual void readAlgorithm();
393 virtual void processRunParamsFile() {}
394 virtual void runDatasetTest( const vector<Mat> &imgs, const vector<Mat> &Hs, int di, int &progress );
396 Ptr<FeatureDetector> specificDetector;
397 Ptr<FeatureDetector> defaultDetector;
402 int correspondenceCount;
404 vector<vector<Quality> > calcQuality;
406 vector<bool> isSaveKeypoints;
407 vector<bool> isActiveParams;
409 bool isSaveKeypointsDefault;
410 bool isActiveParamsDefault;
413 string DetectorQualityEvaluator::getRunParamsFilename() const
415 return data_path + DETECTORS_DIR + algName + PARAMS_POSTFIX;
418 string DetectorQualityEvaluator::getResultsFilename() const
420 return data_path + DETECTORS_DIR + algName + RES_POSTFIX;
423 string DetectorQualityEvaluator::getPlotPath() const
425 return data_path + DETECTORS_DIR + "plots/";
428 void DetectorQualityEvaluator::calcQualityClear( int datasetIdx )
430 calcQuality[datasetIdx].clear();
433 bool DetectorQualityEvaluator::isCalcQualityEmpty( int datasetIdx ) const
435 return calcQuality[datasetIdx].empty();
438 void DetectorQualityEvaluator::readDefaultRunParams (FileNode &fn)
442 isSaveKeypointsDefault = (int)fn[IS_SAVE_KEYPOINTS] != 0;
443 defaultDetector->read (fn);
447 void DetectorQualityEvaluator::writeDefaultRunParams (FileStorage &fs) const
449 fs << IS_SAVE_KEYPOINTS << isSaveKeypointsDefault;
450 defaultDetector->write (fs);
453 void DetectorQualityEvaluator::readDatasetRunParams( FileNode& fn, int datasetIdx )
455 isActiveParams[datasetIdx] = (int)fn[IS_ACTIVE_PARAMS] != 0;
456 if (isActiveParams[datasetIdx])
458 isSaveKeypoints[datasetIdx] = (int)fn[IS_SAVE_KEYPOINTS] != 0;
459 specificDetector->read (fn);
463 setDefaultDatasetRunParams(datasetIdx);
467 void DetectorQualityEvaluator::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const
469 fs << IS_ACTIVE_PARAMS << isActiveParams[datasetIdx];
470 fs << IS_SAVE_KEYPOINTS << isSaveKeypoints[datasetIdx];
471 defaultDetector->write (fs);
474 void DetectorQualityEvaluator::setDefaultDatasetRunParams( int datasetIdx )
476 isSaveKeypoints[datasetIdx] = isSaveKeypointsDefault;
477 isActiveParams[datasetIdx] = isActiveParamsDefault;
480 void DetectorQualityEvaluator::writePlotData(int di ) const
482 int imgXVals[] = { 2, 3, 4, 5, 6 }; // if scale, blur or light changes
483 int viewpointXVals[] = { 20, 30, 40, 50, 60 }; // if viewpoint changes
484 int jpegXVals[] = { 60, 80, 90, 95, 98 }; // if jpeg compression
487 if( !DATASET_NAMES[di].compare("ubc") )
491 else if( !DATASET_NAMES[di].compare("graf") || !DATASET_NAMES[di].compare("wall") )
493 xVals = viewpointXVals;
498 stringstream rFilename, cFilename;
499 rFilename << getPlotPath() << algName << "_" << DATASET_NAMES[di] << "_repeatability.csv";
500 cFilename << getPlotPath() << algName << "_" << DATASET_NAMES[di] << "_correspondenceCount.csv";
501 ofstream rfile(rFilename.str().c_str()), cfile(cFilename.str().c_str());
502 for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
504 rfile << xVals[ci] << ", " << calcQuality[di][ci].repeatability << endl;
505 cfile << xVals[ci] << ", " << calcQuality[di][ci].correspondenceCount << endl;
509 void DetectorQualityEvaluator::openToWriteKeypointsFile( FileStorage& fs, int datasetIdx )
511 string filename = data_path + KEYPOINTS_DIR + algName + "_"+ DATASET_NAMES[datasetIdx] + ".xml.gz" ;
513 fs.open(filename, FileStorage::WRITE);
515 printf( "keypoints can not be written in file %s because this file can not be opened\n", filename.c_str() );
518 inline void writeKeypoints( FileStorage& fs, const vector<KeyPoint>& keypoints, int imgIdx )
522 stringstream imgName; imgName << "img" << imgIdx;
523 write( fs, imgName.str(), keypoints );
527 inline void readKeypoints( FileStorage& fs, vector<KeyPoint>& keypoints, int imgIdx )
529 CV_Assert( fs.isOpened() );
530 stringstream imgName; imgName << "img" << imgIdx;
531 read( fs[imgName.str()], keypoints);
534 void DetectorQualityEvaluator::readAlgorithm ()
536 defaultDetector = FeatureDetector::create( algName );
537 specificDetector = FeatureDetector::create( algName );
538 if( !defaultDetector )
540 printf( "Algorithm can not be read\n" );
545 static int update_progress( const string& /*name*/, int progress, int test_case_idx, int count, double dt )
547 int width = 60 /*- (int)name.length()*/;
550 int t = cvRound( ((double)test_case_idx * width)/count );
553 cout << "." << flush;
557 else if( cvRound(dt) > progress )
559 cout << "." << flush;
560 progress = cvRound(dt);
566 void DetectorQualityEvaluator::runDatasetTest (const vector<Mat> &imgs, const vector<Mat> &Hs, int di, int &progress)
568 Ptr<FeatureDetector> detector = isActiveParams[di] ? specificDetector : defaultDetector;
569 FileStorage keypontsFS;
570 if( isSaveKeypoints[di] )
571 openToWriteKeypointsFile( keypontsFS, di );
573 calcQuality[di].resize(TEST_CASE_COUNT);
575 vector<KeyPoint> keypoints1;
576 detector->detect( imgs[0], keypoints1 );
577 writeKeypoints( keypontsFS, keypoints1, 0);
578 int progressCount = DATASETS_COUNT*TEST_CASE_COUNT;
580 for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
582 progress = update_progress( testName, progress, di*TEST_CASE_COUNT + ci + 1, progressCount, 0 );
583 vector<KeyPoint> keypoints2;
585 evaluateFeatureDetector( imgs[0], imgs[ci+1], Hs[ci], &keypoints1, &keypoints2,
586 rep, calcQuality[di][ci].correspondenceCount,
588 calcQuality[di][ci].repeatability = rep == -1 ? rep : 100.f*rep;
589 writeKeypoints( keypontsFS, keypoints2, ci+1);
593 // static void testLog( bool isBadAccuracy )
595 // if( isBadAccuracy )
596 // printf(" bad accuracy\n");
601 /****************************************************************************************\
602 * Descriptors evaluation *
603 \****************************************************************************************/
605 const string RECALL = "recall";
606 const string PRECISION = "precision";
608 const string KEYPOINTS_FILENAME = "keypointsFilename";
609 const string PROJECT_KEYPOINTS_FROM_1IMAGE = "projectKeypointsFrom1Image";
610 const string MATCH_FILTER = "matchFilter";
611 const string RUN_PARAMS_IS_IDENTICAL = "runParamsIsIdentical";
613 const string ONE_WAY_TRAIN_DIR = "detectors_descriptors_evaluation/one_way_train_images/";
614 const string ONE_WAY_IMAGES_LIST = "one_way_train_images.txt";
616 class DescriptorQualityEvaluator : public BaseQualityEvaluator
619 enum{ NO_MATCH_FILTER = 0 };
620 DescriptorQualityEvaluator( const char* _descriptorName, const char* _testName, const char* _matcherName = 0 ) :
621 BaseQualityEvaluator( _descriptorName, _testName )
623 calcQuality.resize(DATASETS_COUNT);
624 calcDatasetQuality.resize(DATASETS_COUNT);
625 commRunParams.resize(DATASETS_COUNT);
627 commRunParamsDefault.projectKeypointsFrom1Image = true;
628 commRunParamsDefault.matchFilter = NO_MATCH_FILTER;
629 commRunParamsDefault.isActiveParams = false;
632 matcherName = _matcherName;
636 virtual string getRunParamsFilename() const;
637 virtual string getResultsFilename() const;
638 virtual string getPlotPath() const;
640 virtual void calcQualityClear( int datasetIdx );
641 virtual bool isCalcQualityEmpty( int datasetIdx ) const;
643 virtual void readDatasetRunParams( FileNode& fn, int datasetIdx ); //
644 virtual void writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const;
645 virtual void setDefaultDatasetRunParams( int datasetIdx );
646 virtual void readDefaultRunParams( FileNode &fn );
647 virtual void writeDefaultRunParams( FileStorage &fs ) const;
649 virtual void readAlgorithm();
650 virtual void processRunParamsFile() {}
651 virtual void runDatasetTest( const vector<Mat> &imgs, const vector<Mat> &Hs, int di, int &progress );
653 virtual void writePlotData( int di ) const;
654 void calculatePlotData( vector<vector<DMatch> > &allMatches, vector<vector<uchar> > &allCorrectMatchesMask, int di );
661 vector<vector<Quality> > calcQuality;
662 vector<vector<Quality> > calcDatasetQuality;
664 struct CommonRunParams
666 string keypontsFilename;
667 bool projectKeypointsFrom1Image;
668 int matchFilter; // not used now
671 vector<CommonRunParams> commRunParams;
673 Ptr<GenericDescriptorMatch> specificDescMatcher;
674 Ptr<GenericDescriptorMatch> defaultDescMatcher;
676 CommonRunParams commRunParamsDefault;
680 string DescriptorQualityEvaluator::getRunParamsFilename() const
682 return data_path + DESCRIPTORS_DIR + algName + PARAMS_POSTFIX;
685 string DescriptorQualityEvaluator::getResultsFilename() const
687 return data_path + DESCRIPTORS_DIR + algName + RES_POSTFIX;
690 string DescriptorQualityEvaluator::getPlotPath() const
692 return data_path + DESCRIPTORS_DIR + "plots/";
695 void DescriptorQualityEvaluator::calcQualityClear( int datasetIdx )
697 calcQuality[datasetIdx].clear();
700 bool DescriptorQualityEvaluator::isCalcQualityEmpty( int datasetIdx ) const
702 return calcQuality[datasetIdx].empty();
705 void DescriptorQualityEvaluator::readDefaultRunParams (FileNode &fn)
709 commRunParamsDefault.projectKeypointsFrom1Image = (int)fn[PROJECT_KEYPOINTS_FROM_1IMAGE] != 0;
710 commRunParamsDefault.matchFilter = (int)fn[MATCH_FILTER];
711 defaultDescMatcher->read (fn);
715 void DescriptorQualityEvaluator::writeDefaultRunParams (FileStorage &fs) const
717 fs << PROJECT_KEYPOINTS_FROM_1IMAGE << commRunParamsDefault.projectKeypointsFrom1Image;
718 fs << MATCH_FILTER << commRunParamsDefault.matchFilter;
719 defaultDescMatcher->write (fs);
722 void DescriptorQualityEvaluator::readDatasetRunParams( FileNode& fn, int datasetIdx )
724 commRunParams[datasetIdx].isActiveParams = (int)fn[IS_ACTIVE_PARAMS] != 0;
725 if (commRunParams[datasetIdx].isActiveParams)
727 commRunParams[datasetIdx].keypontsFilename = (string)fn[KEYPOINTS_FILENAME];
728 commRunParams[datasetIdx].projectKeypointsFrom1Image = (int)fn[PROJECT_KEYPOINTS_FROM_1IMAGE] != 0;
729 commRunParams[datasetIdx].matchFilter = (int)fn[MATCH_FILTER];
730 specificDescMatcher->read (fn);
734 setDefaultDatasetRunParams(datasetIdx);
738 void DescriptorQualityEvaluator::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const
740 fs << IS_ACTIVE_PARAMS << commRunParams[datasetIdx].isActiveParams;
741 fs << KEYPOINTS_FILENAME << commRunParams[datasetIdx].keypontsFilename;
742 fs << PROJECT_KEYPOINTS_FROM_1IMAGE << commRunParams[datasetIdx].projectKeypointsFrom1Image;
743 fs << MATCH_FILTER << commRunParams[datasetIdx].matchFilter;
745 defaultDescMatcher->write (fs);
748 void DescriptorQualityEvaluator::setDefaultDatasetRunParams( int datasetIdx )
750 commRunParams[datasetIdx] = commRunParamsDefault;
751 commRunParams[datasetIdx].keypontsFilename = "SURF_" + DATASET_NAMES[datasetIdx] + ".xml.gz";
754 void DescriptorQualityEvaluator::writePlotData( int di ) const
756 stringstream filename;
757 filename << getPlotPath() << algName << "_" << DATASET_NAMES[di] << ".csv";
758 FILE *file = fopen (filename.str().c_str(), "w");
759 size_t size = calcDatasetQuality[di].size();
760 for (size_t i=0;i<size;i++)
762 fprintf( file, "%f, %f\n", 1 - calcDatasetQuality[di][i].precision, calcDatasetQuality[di][i].recall);
767 void DescriptorQualityEvaluator::readAlgorithm( )
769 defaultDescMatcher = GenericDescriptorMatcher::create( algName );
770 specificDescMatcher = GenericDescriptorMatcher::create( algName );
772 if( !defaultDescMatcher )
774 Ptr<DescriptorExtractor> extractor = DescriptorExtractor::create( algName );
775 Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create( matcherName );
776 defaultDescMatcher = makePtr<VectorDescriptorMatch>( extractor, matcher );
777 specificDescMatcher = makePtr<VectorDescriptorMatch>( extractor, matcher );
779 if( !extractor || !matcher )
781 printf("Algorithm can not be read\n");
787 void DescriptorQualityEvaluator::calculatePlotData( vector<vector<DMatch> > &allMatches, vector<vector<uchar> > &allCorrectMatchesMask, int di )
789 vector<Point2f> recallPrecisionCurve;
790 computeRecallPrecisionCurve( allMatches, allCorrectMatchesMask, recallPrecisionCurve );
792 calcDatasetQuality[di].clear();
793 const float resultPrecision = 0.5;
794 bool isResultCalculated = false;
795 const double eps = 1e-2;
798 initQuality.recall = 0;
799 initQuality.precision = 0;
800 calcDatasetQuality[di].push_back( initQuality );
802 for( size_t i=0;i<recallPrecisionCurve.size();i++ )
805 quality.recall = recallPrecisionCurve[i].y;
806 quality.precision = 1 - recallPrecisionCurve[i].x;
807 Quality back = calcDatasetQuality[di].back();
809 if( fabs( quality.recall - back.recall ) < eps && fabs( quality.precision - back.precision ) < eps )
812 calcDatasetQuality[di].push_back( quality );
814 if( !isResultCalculated && quality.precision < resultPrecision )
816 for(int ci=0;ci<TEST_CASE_COUNT;ci++)
818 calcQuality[di][ci].recall = quality.recall;
819 calcQuality[di][ci].precision = quality.precision;
821 isResultCalculated = true;
826 void DescriptorQualityEvaluator::runDatasetTest (const vector<Mat> &imgs, const vector<Mat> &Hs, int di, int &progress)
828 FileStorage keypontsFS( data_path + KEYPOINTS_DIR + commRunParams[di].keypontsFilename, FileStorage::READ );
829 if( !keypontsFS.isOpened())
831 calcQuality[di].clear();
832 printf( "keypoints from file %s can not be read\n", commRunParams[di].keypontsFilename.c_str() );
836 Ptr<GenericDescriptorMatcher> descMatch = commRunParams[di].isActiveParams ? specificDescMatcher : defaultDescMatcher;
837 calcQuality[di].resize(TEST_CASE_COUNT);
839 vector<KeyPoint> keypoints1;
840 readKeypoints( keypontsFS, keypoints1, 0);
842 int progressCount = DATASETS_COUNT*TEST_CASE_COUNT;
844 vector<vector<DMatch> > allMatches1to2;
845 vector<vector<uchar> > allCorrectMatchesMask;
846 for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
848 progress = update_progress( testName, progress, di*TEST_CASE_COUNT + ci + 1, progressCount, 0 );
850 vector<KeyPoint> keypoints2;
851 if( commRunParams[di].projectKeypointsFrom1Image )
853 // TODO need to test function calcKeyPointProjections
854 calcKeyPointProjections( keypoints1, Hs[ci], keypoints2 );
855 filterKeyPointsByImageSize( keypoints2, imgs[ci+1].size() );
858 readKeypoints( keypontsFS, keypoints2, ci+1 );
859 // TODO if( commRunParams[di].matchFilter )
861 vector<vector<DMatch> > matches1to2;
862 vector<vector<uchar> > correctMatchesMask;
863 vector<Point2f> recallPrecisionCurve; // not used because we need recallPrecisionCurve for
864 // all images in dataset
865 evaluateGenericDescriptorMatcher( imgs[0], imgs[ci+1], Hs[ci], keypoints1, keypoints2,
866 &matches1to2, &correctMatchesMask, recallPrecisionCurve,
868 allMatches1to2.insert( allMatches1to2.end(), matches1to2.begin(), matches1to2.end() );
869 allCorrectMatchesMask.insert( allCorrectMatchesMask.end(), correctMatchesMask.begin(), correctMatchesMask.end() );
872 calculatePlotData( allMatches1to2, allCorrectMatchesMask, di );
875 //--------------------------------- Calonder descriptor test --------------------------------------------
876 class CalonderDescriptorQualityEvaluator : public DescriptorQualityEvaluator
879 CalonderDescriptorQualityEvaluator() :
880 DescriptorQualityEvaluator( "Calonder", "quality-descriptor-calonder") {}
881 virtual void readAlgorithm( )
883 string classifierFile = data_path + "/features2d/calonder_classifier.rtc";
884 Ptr<DescriptorExtractor> extractor = makePtr<CalonderDescriptorExtractor<float> >( classifierFile );
885 defaultDescMatcher = makePtr<VectorDescriptorMatch>(
887 makePtr<BFMatcher>(extractor->defaultNorm()));
888 specificDescMatcher = defaultDescMatcher;
892 //--------------------------------- One Way descriptor test --------------------------------------------
893 class OneWayDescriptorQualityTest : public DescriptorQualityEvaluator
896 OneWayDescriptorQualityTest() :
897 DescriptorQualityEvaluator("ONEWAY", "quality-descriptor-one-way")
901 virtual void processRunParamsFile ();
902 virtual void writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const;
905 void OneWayDescriptorQualityTest::processRunParamsFile ()
907 string filename = getRunParamsFilename();
908 FileStorage fs = FileStorage (filename, FileStorage::READ);
909 FileNode fn = fs.getFirstTopLevelNode();
910 fn = fn[DEFAULT_PARAMS];
912 string pcaFilename = data_path + (string)fn["pcaFilename"];
913 string trainPath = data_path + (string)fn["trainPath"];
914 string trainImagesList = (string)fn["trainImagesList"];
915 int patch_width = fn["patchWidth"];
916 int patch_height = fn["patchHeight"];
917 Size patchSize = cvSize (patch_width, patch_height);
918 int poseCount = fn["poseCount"];
920 if (trainImagesList.length () == 0 )
925 readAllDatasetsRunParams();
927 Ptr<OneWayDescriptorBase> base(
928 new OneWayDescriptorBase(patchSize, poseCount, pcaFilename,
929 trainPath, trainImagesList));
931 Ptr<OneWayDescriptorMatch> match = makePtr<OneWayDescriptorMatch>();
932 match->initialize( OneWayDescriptorMatch::Params (), base );
933 defaultDescMatcher = match;
934 writeAllDatasetsRunParams();
937 void OneWayDescriptorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const
939 fs << IS_ACTIVE_PARAMS << commRunParams[datasetIdx].isActiveParams;
940 fs << KEYPOINTS_FILENAME << commRunParams[datasetIdx].keypontsFilename;
941 fs << PROJECT_KEYPOINTS_FROM_1IMAGE << commRunParams[datasetIdx].projectKeypointsFrom1Image;
942 fs << MATCH_FILTER << commRunParams[datasetIdx].matchFilter;
945 int main( int argc, char** argv )
949 cout << "Format: " << argv[0] << " testdata path (path to testdata/cv)" << endl;
955 if( *data_path.rbegin() != '\\' )
956 data_path = data_path + "\\";
958 if( *data_path.rbegin() != '/' )
959 data_path = data_path + "/";
962 Ptr<BaseQualityEvaluator> evals[] =
964 makePtr<DetectorQualityEvaluator>( "FAST", "quality-detector-fast" ),
965 makePtr<DetectorQualityEvaluator>( "GFTT", "quality-detector-gftt" ),
966 makePtr<DetectorQualityEvaluator>( "HARRIS", "quality-detector-harris" ),
967 makePtr<DetectorQualityEvaluator>( "MSER", "quality-detector-mser" ),
968 makePtr<DetectorQualityEvaluator>( "STAR", "quality-detector-star" ),
969 makePtr<DetectorQualityEvaluator>( "SIFT", "quality-detector-sift" ),
970 makePtr<DetectorQualityEvaluator>( "SURF", "quality-detector-surf" ),
972 makePtr<DescriptorQualityEvaluator>( "SIFT", "quality-descriptor-sift", "BruteForce" ),
973 makePtr<DescriptorQualityEvaluator>( "SURF", "quality-descriptor-surf", "BruteForce" ),
974 makePtr<DescriptorQualityEvaluator>( "FERN", "quality-descriptor-fern"),
975 makePtr<CalonderDescriptorQualityEvaluator>()
978 for( size_t i = 0; i < sizeof(evals)/sizeof(evals[0]); i++ )