diff --git a/modules/features2d/include/opencv2/features2d/features2d.hpp b/modules/features2d/include/opencv2/features2d/features2d.hpp index a9ad43c920..eda0f14a35 100644 --- a/modules/features2d/include/opencv2/features2d/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d/features2d.hpp @@ -1507,6 +1507,27 @@ struct CV_EXPORTS L2 } }; +/* + * Manhattan distance (city block distance) functor + */ +template +struct CV_EXPORTS L1 +{ + typedef T ValueType; + typedef typename Accumulator::Type ResultType; + + ResultType operator()( const T* a, const T* b, int size ) const + { + ResultType result = ResultType(); + for( int i = 0; i < size; i++ ) + { + ResultType diff = a[i] - b[i]; + result += fabs( diff ); + } + return result; + } +}; + /****************************************************************************************\ * DMatch * @@ -1755,6 +1776,7 @@ void BruteForceMatcher::matchImpl( const Mat& descriptors_1, const Mat { vector matchings; matchImpl( descriptors_1, descriptors_2, mask, matchings); + matches.clear(); matches.resize( matchings.size() ); for( size_t i=0;i::matchImpl( const Mat& descriptors_1, const Mat assert( DataType::type == descriptors_2.type() || descriptors_2.empty() ); int dimension = descriptors_1.cols; + matches.clear(); matches.resize(descriptors_1.rows); for( int i = 0; i < descriptors_1.rows; i++ ) @@ -1823,6 +1846,7 @@ void BruteForceMatcher::matchImpl( const Mat& descriptors_1, const Mat assert( DataType::type == descriptors_2.type() || descriptors_2.empty() ); int dimension = descriptors_1.cols; + matches.clear(); matches.resize( descriptors_1.rows ); for( int i = 0; i < descriptors_1.rows; i++ ) @@ -1930,8 +1954,6 @@ public: // Writes match object to a file storage virtual void write( FileStorage& fs ) const {}; - - static GenericDescriptorMatch* CreateDescriptorMatch( const string &alg_name, const string ¶ms_filename = string () ); protected: KeyPointCollection collection; @@ -1998,6 +2020,8 @@ public: virtual void match( const Mat& image, vector& points, vector& matches ); + virtual void match( const Mat& image, vector& points, vector >& matches, float threshold); + // Classify a set of keypoints. The same as match, but returns point classes rather than indices virtual void classify( const Mat& image, vector& points ); @@ -2146,6 +2170,7 @@ protected: Params params; }; +GenericDescriptorMatch* createDescriptorMatch( const string& genericDescritptorMatchType, const string ¶msFilename = string () ); /****************************************************************************************\ * VectorDescriptorMatch * \****************************************************************************************/ @@ -2159,7 +2184,7 @@ class CV_EXPORTS VectorDescriptorMatch : public GenericDescriptorMatch public: using GenericDescriptorMatch::add; - VectorDescriptorMatch( const Extractor& _extractor = Extractor(), const Matcher& _matcher = Matcher() ) : + VectorDescriptorMatch( Extractor *_extractor = 0, Matcher * _matcher = 0 ) : extractor(_extractor), matcher(_matcher) {} ~VectorDescriptorMatch() {} @@ -2171,8 +2196,8 @@ public: virtual void add( const Mat& image, vector& keypoints ) { Mat descriptors; - extractor.compute( image, keypoints, descriptors ); - matcher.add( descriptors ); + extractor->compute( image, keypoints, descriptors ); + matcher->add( descriptors ); collection.add( Mat(), keypoints ); }; @@ -2181,47 +2206,47 @@ public: virtual void match( const Mat& image, vector& points, vector& keypointIndices ) { Mat descriptors; - extractor.compute( image, points, descriptors ); + extractor->compute( image, points, descriptors ); - matcher.match( descriptors, keypointIndices ); + matcher->match( descriptors, keypointIndices ); }; virtual void match( const Mat& image, vector& points, vector& matches ) { Mat descriptors; - extractor.compute( image, points, descriptors ); + extractor->compute( image, points, descriptors ); - matcher.match( descriptors, matches ); + matcher->match( descriptors, matches ); } virtual void match( const Mat& image, vector& points, vector >& matches, float threshold ) { Mat descriptors; - extractor.compute( image, points, descriptors ); + extractor->compute( image, points, descriptors ); - matcher.match( descriptors, matches, threshold ); + matcher->match( descriptors, matches, threshold ); } virtual void clear() { GenericDescriptorMatch::clear(); - matcher.clear(); + matcher->clear(); } virtual void read (const FileNode& fn) { GenericDescriptorMatch::read(fn); - extractor.read (fn); + extractor->read (fn); } virtual void write (FileStorage& fs) const { GenericDescriptorMatch::write(fs); - extractor.write (fs); + extractor->write (fs); } protected: - Extractor extractor; - Matcher matcher; + Ptr extractor; + Ptr matcher; //vector classIds; }; diff --git a/modules/features2d/src/descriptors.cpp b/modules/features2d/src/descriptors.cpp index e66af9c75b..7c1b9d57bb 100644 --- a/modules/features2d/src/descriptors.cpp +++ b/modules/features2d/src/descriptors.cpp @@ -40,6 +40,7 @@ //M*/ #include "precomp.hpp" +#include //#define _KDTREE @@ -254,6 +255,10 @@ DescriptorMatcher* createDescriptorMatcher( const string& descriptorMatcherType { dm = new BruteForceMatcher >(); } + else if ( !descriptorMatcherType.compare( "BruteForce-L1" ) ) + { + dm = new BruteForceMatcher >(); + } else { //CV_Error( CV_StsBadArg, "unsupported descriptor matcher type"); @@ -330,27 +335,27 @@ void GenericDescriptorMatch::clear() collection.clear(); } -GenericDescriptorMatch* GenericDescriptorMatch::CreateDescriptorMatch( const string &alg_name, const string ¶ms_filename ) +GenericDescriptorMatch* createDescriptorMatch( const string& genericDescritptorMatchType, const string ¶msFilename ) { GenericDescriptorMatch *descriptorMatch = 0; - if( ! alg_name.compare ("one_way") ) + if( ! genericDescritptorMatchType.compare ("ONEWAY") ) { descriptorMatch = new OneWayDescriptorMatch (); } - else if( ! alg_name.compare ("fern") ) + else if( ! genericDescritptorMatchType.compare ("FERN") ) { FernDescriptorMatch::Params params; - params.signatureSize = INT_MAX; + params.signatureSize = numeric_limits::max(); descriptorMatch = new FernDescriptorMatch (params); } - else if( ! alg_name.compare ("calonder") ) + else if( ! genericDescritptorMatchType.compare ("CALONDER") ) { descriptorMatch = new CalonderDescriptorMatch (); } - if( !params_filename.empty() && descriptorMatch != 0 ) + if( !paramsFilename.empty() && descriptorMatch != 0 ) { - FileStorage fs = FileStorage( params_filename, FileStorage::READ ); + FileStorage fs = FileStorage( paramsFilename, FileStorage::READ ); if( fs.isOpened() ) { descriptorMatch->read( fs.root() ); @@ -460,6 +465,76 @@ void OneWayDescriptorMatch::match( const Mat& image, vector& points, v } } +void OneWayDescriptorMatch::match( const Mat& image, vector& points, vector >& matches, float threshold ) +{ + matches.clear(); + matches.resize( points.size() ); + IplImage _image = image; + + + vector dmatches; + match( image, points, dmatches ); + for( size_t i=0;i desc_idxs; + std::vector pose_idxs; + std::vector distances; + std::vector _scales; + + + base->FindDescriptor(&_image, n, desc_idxs, pose_idxs, distances, _scales); + cvResetImageROI(&_image); + + for( int j=0;jFindDescriptor( &_image, 100, points[i].pt, match.indexTrain, poseIdx, match.distance ); + //matches[i].push_back( match ); + } + */ +} + + void OneWayDescriptorMatch::read( const FileNode &fn ) { base = new OneWayDescriptorObject( params.patchSize, params.poseCount, string (), string (), string (), diff --git a/modules/features2d/src/detectors.cpp b/modules/features2d/src/detectors.cpp index 098ca0aff3..69c328acc8 100644 --- a/modules/features2d/src/detectors.cpp +++ b/modules/features2d/src/detectors.cpp @@ -344,6 +344,11 @@ FeatureDetector* createDetector( const string& detectorType ) 5/*edge_blur_size*/ ); } else if( !detectorType.compare( "GFTT" ) ) + { + fd = new GoodFeaturesToTrackDetector( 1000/*maxCorners*/, 0.01/*qualityLevel*/, 1./*minDistance*/, + 3/*int _blockSize*/, false/*useHarrisDetector*/, 0.04/*k*/ ); + } + else if( !detectorType.compare( "HARRIS" ) ) { fd = new GoodFeaturesToTrackDetector( 1000/*maxCorners*/, 0.01/*qualityLevel*/, 1./*minDistance*/, 3/*int _blockSize*/, true/*useHarrisDetector*/, 0.04/*k*/ ); diff --git a/tests/cv/src/adetectordescriptor_evaluation.cpp b/tests/cv/src/adetectordescriptor_evaluation.cpp index f0dede8089..c8d7bc77c1 100644 --- a/tests/cv/src/adetectordescriptor_evaluation.cpp +++ b/tests/cv/src/adetectordescriptor_evaluation.cpp @@ -1042,56 +1042,12 @@ inline void readKeypoints( FileStorage& fs, vector& keypoints, int img void DetectorQualityTest::readAlgorithm () { - //TODO: use Factory Register when it will be implemented - if (! algName.compare ("fast")) + defaultDetector = createDetector( algName ); + specificDetector = createDetector( algName ); + if( defaultDetector == 0 ) { - defaultDetector = new FastFeatureDetector(50, true); - specificDetector = new FastFeatureDetector(); - } - else if (! algName.compare ("mser")) - { - defaultDetector = new MserFeatureDetector(); - specificDetector = new MserFeatureDetector(); - } - else if (! algName.compare ("star")) - { - defaultDetector = new StarFeatureDetector(); - specificDetector = new StarFeatureDetector(); - } - else if (! algName.compare ("sift")) - { - defaultDetector = new SiftFeatureDetector(SIFT::DetectorParams::GET_DEFAULT_THRESHOLD(), 3); - specificDetector = new SiftFeatureDetector(); - } - else if (! algName.compare ("surf")) - { - defaultDetector = new SurfFeatureDetector(1500); - specificDetector = new SurfFeatureDetector(); - } - else - { - int maxCorners = 1500; - double qualityLevel = 0.01; - double minDistance = 2.0; - int blockSize=3; - - if (! algName.compare ("gftt")) - { - bool useHarrisDetector = false; - defaultDetector = new GoodFeaturesToTrackDetector (maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector); - specificDetector = new GoodFeaturesToTrackDetector (maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector); - } - else if (! algName.compare ("harris")) - { - bool useHarrisDetector = true; - defaultDetector = new GoodFeaturesToTrackDetector (maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector); - specificDetector = new GoodFeaturesToTrackDetector (maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector); - } - else - { - ts->printf(CvTS::LOG, "Algorithm can not be read\n"); - ts->set_failed_test_info( CvTS::FAIL_GENERIC); - } + ts->printf(CvTS::LOG, "Algorithm can not be read\n"); + ts->set_failed_test_info( CvTS::FAIL_GENERIC); } } @@ -1152,13 +1108,13 @@ int DetectorQualityTest::processResults( int datasetIdx, int caseIdx ) 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" ); +//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 * @@ -1179,7 +1135,7 @@ class DescriptorQualityTest : public BaseQualityTest { public: enum{ NO_MATCH_FILTER = 0 }; - DescriptorQualityTest( const char* _descriptorName, const char* _testName ) : + DescriptorQualityTest( const char* _descriptorName, const char* _testName, const char* _matcherName = 0 ) : BaseQualityTest( _descriptorName, _testName, "quality-of-descriptor" ) { validQuality.resize(DATASETS_COUNT); @@ -1190,6 +1146,9 @@ public: commRunParamsDefault.projectKeypointsFrom1Image = true; commRunParamsDefault.matchFilter = NO_MATCH_FILTER; commRunParamsDefault.isActiveParams = false; + + if( _matcherName ) + matcherName = _matcherName; } protected: @@ -1223,6 +1182,7 @@ protected: virtual int processResults( int datasetIdx, int caseIdx ); virtual void writePlotData( int di ) const; + void calculatePlotData( vector &allMatches, int allCorrespCount, int di ); struct Quality { @@ -1246,6 +1206,7 @@ protected: Ptr defaultDescMatch; CommonRunParams commRunParamsDefault; + string matcherName; }; string DescriptorQualityTest::getRunParamsFilename() const @@ -1364,54 +1325,71 @@ void DescriptorQualityTest::writePlotData( int di ) const void DescriptorQualityTest::readAlgorithm( ) { - //TODO: use Factory Register when it will be implemented - if (! algName.compare ("sift")) - { - SiftDescriptorExtractor extractor; - BruteForceMatcher > matcher; - defaultDescMatch = new VectorDescriptorMatch > >(extractor, matcher); - specificDescMatch = new VectorDescriptorMatch > >(extractor, matcher); - } - else if (! algName.compare ("surf")) - { - SurfDescriptorExtractor extractor; - BruteForceMatcher > matcher; - defaultDescMatch = new VectorDescriptorMatch > >(extractor, matcher); - specificDescMatch = new VectorDescriptorMatch > >(extractor, matcher); - } - else if (! algName.compare ("one_way")) - { - defaultDescMatch = new OneWayDescriptorMatch (); - specificDescMatch = new OneWayDescriptorMatch (); - } - else if (! algName.compare ("fern")) - { - FernDescriptorMatch::Params params; - params.nviews = 100; - params.signatureSize = INT_MAX; - params.nstructs = 50; - defaultDescMatch = new FernDescriptorMatch (params); - specificDescMatch = new FernDescriptorMatch (); - } - else if (! algName.compare ("calonder")) - { - CalonderDescriptorMatch::Params params; - params.numTrees = 20; - params.depth = 7; - params.views = 100; - params.reducedNumDim = 100; - params.patchSize = 20; + defaultDescMatch = createDescriptorMatch( algName ); + specificDescMatch = createDescriptorMatch( algName ); - defaultDescMatch = new CalonderDescriptorMatch (params); - specificDescMatch = new CalonderDescriptorMatch (); - } - else + if( defaultDescMatch == 0 ) { - ts->printf(CvTS::LOG, "Algorithm can not be read\n"); - ts->set_failed_test_info( CvTS::FAIL_GENERIC); + DescriptorExtractor *extractor = createDescriptorExtractor( algName ); + DescriptorMatcher *matcher = createDescriptorMatcher( matcherName ); + defaultDescMatch = new VectorDescriptorMatch( extractor, matcher ); + specificDescMatch = new VectorDescriptorMatch( extractor, matcher ); + + if( extractor == 0 || matcher == 0 ) + { + ts->printf(CvTS::LOG, "Algorithm can not be read\n"); + ts->set_failed_test_info( CvTS::FAIL_GENERIC); + } } } +void DescriptorQualityTest::calculatePlotData( vector &allMatches, int allCorrespCount, int di ) +{ + std::sort( allMatches.begin(), allMatches.end() ); + + //calcDatasetQuality[di].resize( allMatches.size() ); + calcDatasetQuality[di].clear(); + int correctMatchCount = 0, falseMatchCount = 0; + const float sparsePlotBound = 0.1; + const int npoints = 10000; + int step = 1 + allMatches.size() / npoints; + const float resultPrecision = 0.5; + bool isResultCalculated = false; + for( size_t i=0;i= sparsePlotBound || (i % step == 0) ) + { + Quality quality; + quality.recall = recall( correctMatchCount, allCorrespCount ); + quality.precision = precision( correctMatchCount, falseMatchCount ); + + calcDatasetQuality[di].push_back( quality ); + + if( !isResultCalculated && quality.precision < resultPrecision) + { + for(int ci=0;ci &imgs, const vector &Hs, int di, int &progress) { FileStorage keypontsFS( string(ts->get_data_path()) + KEYPOINTS_DIR + commRunParams[di].keypontsFilename, @@ -1465,48 +1443,7 @@ void DescriptorQualityTest::runDatasetTest (const vector &imgs, const vecto descMatch->clear (); } - std::sort( allMatches.begin(), allMatches.end() ); - - //calcDatasetQuality[di].resize( allMatches.size() ); - calcDatasetQuality[di].clear(); - int correctMatchCount = 0, falseMatchCount = 0; - const float sparsePlotBound = 0.1; - const int npoints = 10000; - int step = allMatches.size() / npoints; - const float resultPrecision = 0.5; - bool isResultCalculated = false; - for( size_t i=0;i= sparsePlotBound || (i % step == 0) ) - { - Quality quality; - quality.recall = recall( correctMatchCount, allCorrespCount ); - quality.precision = precision( correctMatchCount, falseMatchCount ); - - calcDatasetQuality[di].push_back( quality ); - - if( !isResultCalculated && quality.precision < resultPrecision) - { - for(int ci=0;ci