From 9b4c68262359f793bec0d36d9fc0fdfb69f281c5 Mon Sep 17 00:00:00 2001 From: Maria Dimashova Date: Mon, 31 Jan 2011 14:18:50 +0000 Subject: [PATCH] added empty() method to common features2d classes; fixed #831 --- .../include/opencv2/features2d/features2d.hpp | 42 ++++++++++++++++--- modules/features2d/src/calonder.cpp | 7 +++- modules/features2d/src/descriptors.cpp | 10 +++++ modules/features2d/src/detectors.cpp | 15 +++++++ modules/features2d/src/matchers.cpp | 25 ++++++++++- modules/features2d/src/planardetect.cpp | 4 ++ tests/cv/src/afeatures2d.cpp | 28 +++++++++---- 7 files changed, 112 insertions(+), 19 deletions(-) diff --git a/modules/features2d/include/opencv2/features2d/features2d.hpp b/modules/features2d/include/opencv2/features2d/features2d.hpp index 6f09e7f4d8..420f60ca28 100644 --- a/modules/features2d/include/opencv2/features2d/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d/features2d.hpp @@ -523,6 +523,7 @@ public: virtual int operator()(const Mat& img, Point2f kpt, vector& signature) const; virtual int operator()(const Mat& patch, vector& signature) const; virtual void clear(); + virtual bool empty() const; void setVerbose(bool verbose); int getClassCount() const; @@ -1086,6 +1087,8 @@ public: // GetPCAFilename: get default PCA filename static string GetPCAFilename () { return "pca.yml"; } + virtual bool empty() const { return m_train_feature_count <= 0 ? true : false; } + protected: CvSize m_patch_size; // patch size int m_pose_count; // the number of poses for each descriptor @@ -1212,6 +1215,9 @@ public: // Read detector object from a file node. virtual void write( FileStorage& ) const; + // Return true if detector object is empty + virtual bool empty() const; + // Create feature detector by detector name. static Ptr create( const string& detectorType ); @@ -1359,18 +1365,19 @@ public: }; SimpleBlobDetector(const SimpleBlobDetector::Params ¶meters = SimpleBlobDetector::Params()); + protected: struct CV_EXPORTS Center { - cv::Point2d location; - double radius; - double confidence; + Point2d location; + double radius; + double confidence; }; virtual void detectImpl( const Mat& image, vector& keypoints, const Mat& mask=Mat() ) const; virtual void findBlobs(const cv::Mat &image, const cv::Mat &binaryImage, std::vector
¢ers) const; - cv::Point2d computeGrayscaleCentroid(const cv::Mat &image, const std::vector &contour) const; + Point2d computeGrayscaleCentroid(const cv::Mat &image, const std::vector &contour) const; Params params; }; @@ -1422,6 +1429,7 @@ public: int gridRows=4, int gridCols=4 ); // TODO implement read/write + virtual bool empty() const; protected: virtual void detectImpl( const Mat& image, vector& keypoints, const Mat& mask=Mat() ) const; @@ -1442,6 +1450,7 @@ public: PyramidAdaptedFeatureDetector( const Ptr& detector, int levels=2 ); // TODO implement read/write + virtual bool empty() const; protected: virtual void detectImpl( const Mat& image, vector& keypoints, const Mat& mask=Mat() ) const; @@ -1500,6 +1509,8 @@ public: */ DynamicAdaptedFeatureDetector( const Ptr& adjaster, int min_features=400, int max_features=500, int max_iters=5 ); + virtual bool empty() const; + protected: virtual void detectImpl( const Mat& image, vector& keypoints, const Mat& mask=Mat() ) const; @@ -1607,6 +1618,8 @@ public: virtual int descriptorSize() const = 0; virtual int descriptorType() const = 0; + virtual bool empty() const; + static Ptr create( const string& descriptorExtractorType ); protected: @@ -1680,6 +1693,8 @@ public: virtual int descriptorSize() const { return classifier_.classes(); } virtual int descriptorType() const { return DataType::type; } + virtual bool empty() const; + protected: virtual void computeImpl( const Mat& image, vector& keypoints, Mat& descriptors ) const; @@ -1722,6 +1737,12 @@ template void CalonderDescriptorExtractor::write( FileStorage& ) const {} +template +bool CalonderDescriptorExtractor::empty() const +{ + return classifier_.trees_.empty(); +} + /* * OpponentColorDescriptorExtractor * @@ -1742,6 +1763,8 @@ public: virtual int descriptorSize() const; virtual int descriptorType() const; + virtual bool empty() const; + protected: virtual void computeImpl( const Mat& image, vector& keypoints, Mat& descriptors ) const; @@ -1766,7 +1789,7 @@ public: /// @todo read and write for brief protected: - virtual void computeImpl(const Mat& image, std::vector& keypoints, Mat& descriptors) const; + virtual void computeImpl(const Mat& image, std::vector& keypoints, Mat& descriptors) const; typedef void(*PixelTestFn)(const Mat&, const std::vector&, Mat&); @@ -1924,7 +1947,7 @@ public: /* * Return true if there are not train descriptors in collection. */ - bool empty() const; + virtual bool empty() const; /* * Return true if the matcher supports mask in match methods. */ @@ -2366,6 +2389,9 @@ public: // Writes matcher object to a file storage virtual void write( FileStorage& ) const; + // Return true if matching object is empty (e.g. feature detector or descriptor matcher are empty) + virtual bool empty() const; + // Clone the matcher. If emptyTrainData is false the method create deep copy of the object, i.e. copies // both parameters and train data. If emptyTrainData is true the method create object copy with current parameters // but with empty train data. @@ -2473,6 +2499,8 @@ public: virtual void read( const FileNode &fn ); virtual void write( FileStorage& fs ) const; + virtual bool empty() const; + virtual Ptr clone( bool emptyTrainData=false ) const; protected: @@ -2540,6 +2568,7 @@ public: virtual void read( const FileNode &fn ); virtual void write( FileStorage& fs ) const; + virtual bool empty() const; virtual Ptr clone( bool emptyTrainData=false ) const; @@ -2586,6 +2615,7 @@ public: virtual void read( const FileNode& fn ); virtual void write( FileStorage& fs ) const; + virtual bool empty() const; virtual Ptr clone( bool emptyTrainData=false ) const; diff --git a/modules/features2d/src/calonder.cpp b/modules/features2d/src/calonder.cpp index b8b5f0d962..d7a74eea20 100644 --- a/modules/features2d/src/calonder.cpp +++ b/modules/features2d/src/calonder.cpp @@ -860,8 +860,11 @@ int RTreeClassifier::countNonZeroElements(float *vec, int n, double tol) void RTreeClassifier::read(const char* file_name) { std::ifstream file(file_name, std::ifstream::binary); - read(file); - file.close(); + if( file.is_open() ) + { + read(file); + file.close(); + } } void RTreeClassifier::read(std::istream &is) diff --git a/modules/features2d/src/descriptors.cpp b/modules/features2d/src/descriptors.cpp index 25b18cb704..12d485bfe2 100644 --- a/modules/features2d/src/descriptors.cpp +++ b/modules/features2d/src/descriptors.cpp @@ -96,6 +96,11 @@ void DescriptorExtractor::read( const FileNode& ) void DescriptorExtractor::write( FileStorage& ) const {} +bool DescriptorExtractor::empty() const +{ + return false; +} + void DescriptorExtractor::removeBorderKeypoints( vector& keypoints, Size imageSize, int borderSize ) { @@ -361,4 +366,9 @@ int OpponentColorDescriptorExtractor::descriptorType() const return descriptorExtractor->descriptorType(); } +bool OpponentColorDescriptorExtractor::empty() const +{ + return descriptorExtractor.empty() || (DescriptorExtractor*)(descriptorExtractor)->empty(); +} + } diff --git a/modules/features2d/src/detectors.cpp b/modules/features2d/src/detectors.cpp index 96dd1f1e46..83c10523b5 100644 --- a/modules/features2d/src/detectors.cpp +++ b/modules/features2d/src/detectors.cpp @@ -96,6 +96,11 @@ void FeatureDetector::read( const FileNode& ) void FeatureDetector::write( FileStorage& ) const {} +bool FeatureDetector::empty() const +{ + return false; +} + Ptr FeatureDetector::create( const string& detectorType ) { FeatureDetector* fd = 0; @@ -488,6 +493,11 @@ GridAdaptedFeatureDetector::GridAdaptedFeatureDetector( const Ptrempty(); +} + struct ResponseComparator { bool operator() (const KeyPoint& a, const KeyPoint& b) @@ -544,6 +554,11 @@ PyramidAdaptedFeatureDetector::PyramidAdaptedFeatureDetector( const Ptrempty(); +} + void PyramidAdaptedFeatureDetector::detectImpl( const Mat& image, vector& keypoints, const Mat& mask ) const { Mat src = image; diff --git a/modules/features2d/src/matchers.cpp b/modules/features2d/src/matchers.cpp index 155a598a5b..f2a868dec6 100755 --- a/modules/features2d/src/matchers.cpp +++ b/modules/features2d/src/matchers.cpp @@ -213,7 +213,7 @@ void DescriptorMatcher::clear() bool DescriptorMatcher::empty() const { - return trainDescCollection.size() == 0; + return trainDescCollection.empty(); } void DescriptorMatcher::train() @@ -848,6 +848,11 @@ void GenericDescriptorMatcher::read( const FileNode& ) void GenericDescriptorMatcher::write( FileStorage& ) const {} +bool GenericDescriptorMatcher::empty() const +{ + return true; +} + /* * Factory function for GenericDescriptorMatch creating */ @@ -994,13 +999,18 @@ void OneWayDescriptorMatcher::write( FileStorage& fs ) const base->Write (fs); } +bool OneWayDescriptorMatcher::empty() const +{ + return base.empty() || base->empty(); +} + Ptr OneWayDescriptorMatcher::clone( bool emptyTrainData ) const { OneWayDescriptorMatcher* matcher = new OneWayDescriptorMatcher( params ); if( !emptyTrainData ) { - CV_Error( CV_StsNotImplemented, "deep clone dunctionality is not implemented, because " + CV_Error( CV_StsNotImplemented, "deep clone functionality is not implemented, because " "OneWayDescriptorBase has not copy constructor or clone method "); //matcher->base; @@ -1175,6 +1185,11 @@ void FernDescriptorMatcher::write( FileStorage& fs ) const // classifier->write(fs); } +bool FernDescriptorMatcher::empty() const +{ + return classifier.empty() || classifier->empty(); +} + Ptr FernDescriptorMatcher::clone( bool emptyTrainData ) const { FernDescriptorMatcher* matcher = new FernDescriptorMatcher( params ); @@ -1262,6 +1277,12 @@ void VectorDescriptorMatcher::write (FileStorage& fs) const extractor->write (fs); } +bool VectorDescriptorMatcher::empty() const +{ + return extractor.empty() || extractor->empty() || + matcher.empty() || matcher->empty(); +} + Ptr VectorDescriptorMatcher::clone( bool emptyTrainData ) const { // TODO clone extractor diff --git a/modules/features2d/src/planardetect.cpp b/modules/features2d/src/planardetect.cpp index 767407e66d..33eb0dec5a 100644 --- a/modules/features2d/src/planardetect.cpp +++ b/modules/features2d/src/planardetect.cpp @@ -771,6 +771,10 @@ void FernClassifier::clear() vector().swap(posteriors); } +bool FernClassifier::empty() const +{ + return features.empty(); +} int FernClassifier::getLeaf(int fern, const Mat& _patch) const { diff --git a/tests/cv/src/afeatures2d.cpp b/tests/cv/src/afeatures2d.cpp index 3072984930..59a4ac228c 100644 --- a/tests/cv/src/afeatures2d.cpp +++ b/tests/cv/src/afeatures2d.cpp @@ -73,6 +73,8 @@ protected: void CV_FeatureDetectorTest::emptyDataTest() { + assert( !fdetector.empty() && !fdetector->empty() ); + // One image. Mat image; vector keypoints; @@ -172,7 +174,7 @@ void CV_FeatureDetectorTest::compareKeypointSets( const vector& validK void CV_FeatureDetectorTest::regressionTest() { - assert( !fdetector.empty() ); + assert( !fdetector.empty() && !fdetector->empty() ); string imgFilename = string(ts->get_data_path()) + FEATURES2D_DIR + "/" + IMAGE_FILENAME; string resFilename = string(ts->get_data_path()) + DETECTOR_DIR + "/" + string(name) + ".xml.gz"; @@ -229,7 +231,7 @@ void CV_FeatureDetectorTest::regressionTest() void CV_FeatureDetectorTest::run( int /*start_from*/ ) { - if( fdetector.empty() ) + if( fdetector.empty() || fdetector->empty() ) { ts->printf( CvTS::LOG, "Feature detector is empty.\n" ); ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); @@ -293,7 +295,7 @@ public: CvTest( testName, "cv::DescriptorExtractor::compute" ), maxDist(_maxDist), prevTime(_prevTime), dextractor(_dextractor), distance(d) {} protected: - virtual void createDescriptorExtractor() {} + virtual void createDescriptorExtractor(){} void compareDescriptors( const Mat& validDescriptors, const Mat& calcDescriptors ) { @@ -329,7 +331,7 @@ protected: void emptyDataTest() { - assert( !dextractor.empty() ); + assert( !dextractor.empty() && !dextractor->empty() ); // One image. Mat image; @@ -374,7 +376,7 @@ protected: void regressionTest() { - assert( !dextractor.empty() ); + assert( !dextractor.empty() && !dextractor->empty() ); // Read the test image. string imgFilename = string(ts->get_data_path()) + FEATURES2D_DIR + "/" + IMAGE_FILENAME; @@ -449,7 +451,7 @@ protected: void run(int) { createDescriptorExtractor(); - if( dextractor.empty() ) + if( dextractor.empty() || dextractor->empty() ) { ts->printf(CvTS::LOG, "Descriptor extractor is empty.\n"); ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); @@ -495,9 +497,16 @@ public: protected: virtual void createDescriptorExtractor() { + string filename = string(CV_DescriptorExtractorTest::ts->get_data_path()) + + FEATURES2D_DIR + "/calonder_classifier.rtc"; CV_DescriptorExtractorTest::dextractor = - new CalonderDescriptorExtractor( string(CV_DescriptorExtractorTest::ts->get_data_path()) + - FEATURES2D_DIR + "/calonder_classifier.rtc"); + new CalonderDescriptorExtractor( filename ); + if( CV_DescriptorExtractorTest::dextractor->empty() ) + { + stringstream ss; ss << "Calonder descriptor extractor can not be loaded from file" << filename<< endl; + CV_DescriptorExtractorTest::ts->printf( CvTS::LOG, ss.str().c_str() ); + CV_DescriptorExtractorTest::ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); + } } }; @@ -531,7 +540,8 @@ private: void CV_DescriptorMatcherTest::emptyDataTest() { - assert( !dmatcher.empty() ); + assert( !dmatcher.empty() && !dmatcher->empty() ); + Mat queryDescriptors, trainDescriptors, mask; vector trainDescriptorCollection, masks; vector matches;