From b9662e099ca613cac55c4c394ceb95aaff07a862 Mon Sep 17 00:00:00 2001 From: Maria Dimashova Date: Sun, 1 May 2011 17:38:52 +0000 Subject: [PATCH] added the filtering of keypoints having zero size (#877) --- .../include/opencv2/features2d/features2d.hpp | 30 ++++++--- modules/features2d/src/brief.cpp | 2 +- modules/features2d/src/descriptors.cpp | 38 +++--------- modules/features2d/src/detectors.cpp | 10 +-- modules/features2d/src/keypoint.cpp | 48 ++++++++++++++ modules/features2d/src/matchers.cpp | 62 +++++++++++++------ 6 files changed, 128 insertions(+), 62 deletions(-) diff --git a/modules/features2d/include/opencv2/features2d/features2d.hpp b/modules/features2d/include/opencv2/features2d/features2d.hpp index 6034cd0444..66ffea98e8 100644 --- a/modules/features2d/include/opencv2/features2d/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d/features2d.hpp @@ -263,6 +263,26 @@ CV_EXPORTS void write(FileStorage& fs, const string& name, const vector& keypoints); +/* + * A class filters a vector of keypoints. + * Because now it is difficult to provide a convenient interface for all usage scenarios of the keypoints filter class, + * it has only 2 needed by now static methods. + */ +class CV_EXPORTS KeyPointsFilter +{ +public: + KeyPointsFilter(){} + + /* + * Remove keypoints within borderPixels of an image edge. + */ + static void runByImageBorder( vector& keypoints, Size imageSize, int borderSize ); + /* + * Remove keypoints of sizes out of range. + */ + static void runByKeypointSize( vector& keypoints, float minSize, float maxSize=std::numeric_limits::max() ); +}; + /*! SIFT implementation. @@ -1624,13 +1644,7 @@ public: static Ptr create( const string& descriptorExtractorType ); protected: - virtual void computeImpl( const Mat& image, vector& keypoints, Mat& descriptors ) const = 0; - - /* - * Remove keypoints within borderPixels of an image edge. - */ - static void removeBorderKeypoints( vector& keypoints, - Size imageSize, int borderSize ); + virtual void computeImpl( const Mat& image, vector& keypoints, Mat& descriptors ) const = 0; }; /* @@ -1715,7 +1729,7 @@ void CalonderDescriptorExtractor::computeImpl( const cv::Mat& image, cv::Mat& descriptors) const { // Cannot compute descriptors for keypoints on the image border. - removeBorderKeypoints(keypoints, image.size(), BORDER_SIZE); + KeyPointsFilter::runByImageBorder(keypoints, image.size(), BORDER_SIZE); /// @todo Check 16-byte aligned descriptors.create(keypoints.size(), classifier_.classes(), cv::DataType::type); diff --git a/modules/features2d/src/brief.cpp b/modules/features2d/src/brief.cpp index d9d60ac63b..0bd4012149 100644 --- a/modules/features2d/src/brief.cpp +++ b/modules/features2d/src/brief.cpp @@ -208,7 +208,7 @@ void BriefDescriptorExtractor::computeImpl(const Mat& image, std::vector& keypoints, Mat& descriptors ) const -{ +{ if( image.empty() || keypoints.empty() ) - return; + { + descriptors.release(); + return; + } - // Check keypoints are in image. Do filter bad points here? - //for( size_t i = 0; i < keypoints.size(); i++ ) - // CV_Assert( Rect(0,0, image.cols, image.rows).contains(keypoints[i].pt) ); + + KeyPointsFilter::runByImageBorder( keypoints, image.size(), 0 ); + KeyPointsFilter::runByKeypointSize( keypoints, std::numeric_limits::epsilon() ); computeImpl( image, keypoints, descriptors ); } @@ -99,18 +89,6 @@ bool DescriptorExtractor::empty() const return false; } -void DescriptorExtractor::removeBorderKeypoints( vector& keypoints, - Size imageSize, int borderSize ) -{ - if( borderSize > 0) - { - keypoints.erase( remove_if(keypoints.begin(), keypoints.end(), - RoiPredicate(Rect(Point(borderSize, borderSize), - Point(imageSize.width - borderSize, imageSize.height - borderSize)))), - keypoints.end() ); - } -} - Ptr DescriptorExtractor::create(const string& descriptorExtractorType) { DescriptorExtractor* de = 0; diff --git a/modules/features2d/src/detectors.cpp b/modules/features2d/src/detectors.cpp index 83c10523b5..d5a0f83743 100644 --- a/modules/features2d/src/detectors.cpp +++ b/modules/features2d/src/detectors.cpp @@ -65,14 +65,14 @@ FeatureDetector::~FeatureDetector() void FeatureDetector::detect( const Mat& image, vector& keypoints, const Mat& mask ) const { - keypoints.clear(); + keypoints.clear(); - if( image.empty() ) - return; + if( image.empty() ) + return; - CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) ); + CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) ); - detectImpl( image, keypoints, mask ); + detectImpl( image, keypoints, mask ); } void FeatureDetector::detect(const vector& imageCollection, vector >& pointCollection, const vector& masks ) const diff --git a/modules/features2d/src/keypoint.cpp b/modules/features2d/src/keypoint.cpp index 7435cfeb6d..88305914c5 100644 --- a/modules/features2d/src/keypoint.cpp +++ b/modules/features2d/src/keypoint.cpp @@ -152,4 +152,52 @@ float KeyPoint::overlap( const KeyPoint& kp1, const KeyPoint& kp2 ) return ovrl; } +struct RoiPredicate +{ + RoiPredicate( const Rect& _r ) : r(_r) + {} + + bool operator()( const KeyPoint& keyPt ) const + { + return !r.contains( keyPt.pt ); + } + + Rect r; +}; + +void KeyPointsFilter::runByImageBorder( vector& keypoints, Size imageSize, int borderSize ) +{ + if( borderSize > 0) + { + keypoints.erase( remove_if(keypoints.begin(), keypoints.end(), + RoiPredicate(Rect(Point(borderSize, borderSize), + Point(imageSize.width - borderSize, imageSize.height - borderSize)))), + keypoints.end() ); + } +} + +struct SizePredicate +{ + SizePredicate( float _minSize, float _maxSize ) : minSize(_minSize), maxSize(_maxSize) + {} + + bool operator()( const KeyPoint& keyPt ) const + { + float size = keyPt.size; + return (size < minSize) || (size > maxSize); + } + + float minSize, maxSize; +}; + +void KeyPointsFilter::runByKeypointSize( vector& keypoints, float minSize, float maxSize ) +{ + CV_Assert( minSize >= 0 ); + CV_Assert( maxSize >= 0); + CV_Assert( minSize <= maxSize ); + + keypoints.erase( remove_if(keypoints.begin(), keypoints.end(), SizePredicate(minSize, maxSize)), + keypoints.end() ); +} + } diff --git a/modules/features2d/src/matchers.cpp b/modules/features2d/src/matchers.cpp index ff3a3aabba..82ae5c19db 100755 --- a/modules/features2d/src/matchers.cpp +++ b/modules/features2d/src/matchers.cpp @@ -244,21 +244,21 @@ void DescriptorMatcher::match( const Mat& queryDescriptors, vector& matc void DescriptorMatcher::checkMasks( const vector& masks, int queryDescriptorsCount ) const { - if( isMaskSupported() && !masks.empty() ) - { - // Check masks - size_t imageCount = trainDescCollection.size(); - CV_Assert( masks.size() == imageCount ); - for( size_t i = 0; i < imageCount; i++ ) - { - if( !masks[i].empty() && !trainDescCollection[i].empty() ) - { - CV_Assert( masks[i].rows == queryDescriptorsCount && - masks[i].cols == trainDescCollection[i].rows && - masks[i].type() == CV_8UC1 ); - } - } - } + if( isMaskSupported() && !masks.empty() ) + { + // Check masks + size_t imageCount = trainDescCollection.size(); + CV_Assert( masks.size() == imageCount ); + for( size_t i = 0; i < imageCount; i++ ) + { + if( !masks[i].empty() && !trainDescCollection[i].empty() ) + { + CV_Assert( masks[i].rows == queryDescriptorsCount && + masks[i].cols == trainDescCollection[i].rows && + masks[i].type() == CV_8UC1 ); + } + } + } } void DescriptorMatcher::knnMatch( const Mat& queryDescriptors, vector >& matches, int knn, @@ -736,10 +736,20 @@ GenericDescriptorMatcher::GenericDescriptorMatcher() GenericDescriptorMatcher::~GenericDescriptorMatcher() {} -void GenericDescriptorMatcher::add( const vector& imgCollection, - vector >& pointCollection ) +void GenericDescriptorMatcher::add( const vector& images, + vector >& keypoints ) { - trainPointCollection.add( imgCollection, pointCollection ); + CV_Assert( !images.empty() ); + CV_Assert( images.size() == keypoints.size() ); + + for( size_t i = 0; i < images.size(); i++ ) + { + CV_Assert( !images[i].empty() ); + KeyPointsFilter::runByImageBorder( keypoints[i], images[i].size(), 0 ); + KeyPointsFilter::runByKeypointSize( keypoints[i], std::numeric_limits::epsilon() ); + } + + trainPointCollection.add( images, keypoints ); } const vector& GenericDescriptorMatcher::getTrainImages() const @@ -827,6 +837,14 @@ void GenericDescriptorMatcher::knnMatch( const Mat& queryImage, vector vector >& matches, int knn, const vector& masks, bool compactResult ) { + matches.clear(); + + if( queryImage.empty() || queryKeypoints.empty() ) + return; + + KeyPointsFilter::runByImageBorder( queryKeypoints, queryImage.size(), 0 ); + KeyPointsFilter::runByKeypointSize( queryKeypoints, std::numeric_limits::epsilon() ); + train(); knnMatchImpl( queryImage, queryKeypoints, matches, knn, masks, compactResult ); } @@ -835,6 +853,14 @@ void GenericDescriptorMatcher::radiusMatch( const Mat& queryImage, vector >& matches, float maxDistance, const vector& masks, bool compactResult ) { + matches.clear(); + + if( queryImage.empty() || queryKeypoints.empty() ) + return; + + KeyPointsFilter::runByImageBorder( queryKeypoints, queryImage.size(), 0 ); + KeyPointsFilter::runByKeypointSize( queryKeypoints, std::numeric_limits::epsilon() ); + train(); radiusMatchImpl( queryImage, queryKeypoints, matches, maxDistance, masks, compactResult ); }