diff --git a/modules/features2d/include/opencv2/features2d.hpp b/modules/features2d/include/opencv2/features2d.hpp index 1f0a92c18..2474dd594 100644 --- a/modules/features2d/include/opencv2/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d.hpp @@ -1519,6 +1519,41 @@ protected: Ptr dmatcher; }; +/* + * Class to match image descriptors using bag of visual words. + */ +class CV_EXPORTS BOWImgDescriptorMatcher +{ +public: + BOWImgDescriptorMatcher( const Ptr& _dmatcher ); + virtual ~BOWImgDescriptorMatcher(); + + /* + * Compute the matching of the current descriptor according to the vocabulary. + * + * vocDescriptor the descriptors to match + * pointIdxsOfClusters vector of matching + */ + void compute( const Mat & descriptors, Mat& vocDescriptor, std::vector< std::vector< int > > * pointIdxsOfClusters = 0 ); + + /* + * Set the vocabulary + */ + void setVocabulary( const Mat& vocabulary ); + const Mat& getVocabulary() const; + + int descriptorSize() const; + int descriptorType() const; + +protected: + Mat vocabulary; + Ptr dmatcher; + +private: + int _type; +}; + + } /* namespace cv */ #endif diff --git a/modules/features2d/src/bagofwords.cpp b/modules/features2d/src/bagofwords.cpp index 4307983fe..5ef8b5c4b 100644 --- a/modules/features2d/src/bagofwords.cpp +++ b/modules/features2d/src/bagofwords.cpp @@ -193,4 +193,76 @@ int BOWImgDescriptorExtractor::descriptorType() const return CV_32FC1; } +BOWImgDescriptorMatcher::BOWImgDescriptorMatcher( const Ptr& _dmatcher ) : + dmatcher(_dmatcher), + _type( -1 ) +{} + +BOWImgDescriptorMatcher::~BOWImgDescriptorMatcher() +{} + +void BOWImgDescriptorMatcher::setVocabulary( const Mat& _vocabulary ) +{ + dmatcher->clear(); + CV_Assert( _vocabulary.type() == CV_32F ); + vocabulary = _vocabulary; + dmatcher->add( std::vector(1, vocabulary) ); +} + +const Mat& BOWImgDescriptorMatcher::getVocabulary() const +{ + return vocabulary; +} + +void BOWImgDescriptorMatcher::compute( const Mat & descriptors, Mat& vocDescriptor, std::vector > * pointIdxsOfClusters ) +{ + vocDescriptor.release(); + + int clusterCount = descriptorSize(); // = vocabulary.rows + + _type = descriptors.type(); + + Mat _descriptors; + if( _type != CV_32F ) + descriptors.convertTo( _descriptors, CV_32F ); + else + descriptors.copyTo( _descriptors ); + // Match keypoint descriptors to cluster center (to vocabulary) + std::vector matches; + dmatcher->match( _descriptors, matches ); + + // Compute image descriptor + if( pointIdxsOfClusters ) + { + pointIdxsOfClusters->clear(); + pointIdxsOfClusters->resize(clusterCount); + } + + vocDescriptor = Mat::zeros( 1, clusterCount, descriptorType() ); + float *dptr = (float*)vocDescriptor.data; + for( size_t i = 0; i < matches.size(); i++ ) + { + int queryIdx = matches[i].queryIdx; + int trainIdx = matches[i].trainIdx; // cluster index + CV_Assert( queryIdx == (int)i ); + + dptr[trainIdx] = dptr[trainIdx] + 1.f; + if( pointIdxsOfClusters ) + (*pointIdxsOfClusters)[trainIdx].push_back( queryIdx ); + } + + // Normalize image descriptor. + vocDescriptor /= descriptors.rows; +} + +int BOWImgDescriptorMatcher::descriptorSize() const +{ + return vocabulary.empty() ? 0 : vocabulary.rows; +} + +int BOWImgDescriptorMatcher::descriptorType() const +{ + return _type; +} + }