From 0cfd795303c414aada6d10701e0de4995841210c Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Thu, 16 Oct 2014 16:33:21 +0400 Subject: [PATCH 1/5] refactored xfeatures2d in the same style as features2d --- modules/ccalib/src/ccalib.cpp | 4 +- modules/text/samples/webcam_demo.cpp | 3 +- .../include/opencv2/xfeatures2d.hpp | 147 ++---------------- .../include/opencv2/xfeatures2d/nonfree.hpp | 81 +--------- modules/xfeatures2d/perf/perf_surf.cpp | 14 +- .../samples/bagofwords_classification.cpp | 29 +++- .../samples/shape_transformation.cpp | 15 +- modules/xfeatures2d/samples/surf_matcher.cpp | 9 +- .../xfeatures2d/samples/video_homography.cpp | 11 +- modules/xfeatures2d/src/brief.cpp | 50 +++++- modules/xfeatures2d/src/freak.cpp | 136 ++++++++++++++-- modules/xfeatures2d/src/sift.cpp | 82 ++++++---- modules/xfeatures2d/src/stardetector.cpp | 60 +++++-- modules/xfeatures2d/src/surf.cpp | 38 ++--- modules/xfeatures2d/src/surf.hpp | 39 ++++- modules/xfeatures2d/src/surf.ocl.cpp | 2 +- modules/xfeatures2d/src/xfeatures2d_init.cpp | 56 ------- modules/xfeatures2d/test/test_detectors.cpp | 20 +-- modules/xfeatures2d/test/test_features2d.cpp | 35 +++-- modules/xfeatures2d/test/test_keypoints.cpp | 11 +- .../test_rotation_and_scale_invariance.cpp | 29 ++-- 21 files changed, 421 insertions(+), 450 deletions(-) diff --git a/modules/ccalib/src/ccalib.cpp b/modules/ccalib/src/ccalib.cpp index bd2e11cab..6f2398942 100644 --- a/modules/ccalib/src/ccalib.cpp +++ b/modules/ccalib/src/ccalib.cpp @@ -93,7 +93,7 @@ bool CustomPattern::init(Mat& image, const float pixel_size, OutputArray output) if (!detector) // if no detector chosen, use default { - detector = FeatureDetector::create("ORB"); + detector = ORB::create(); detector->set("nFeatures", 2000); detector->set("scaleFactor", 1.15); detector->set("nLevels", 30); @@ -108,7 +108,7 @@ bool CustomPattern::init(Mat& image, const float pixel_size, OutputArray output) refineKeypointsPos(img_roi, keypoints); if (!descriptorExtractor) // if no extractor chosen, use default - descriptorExtractor = DescriptorExtractor::create("ORB"); + descriptorExtractor = ORB::create(); descriptorExtractor->compute(img_roi, keypoints, descriptor); if (!descriptorMatcher) diff --git a/modules/text/samples/webcam_demo.cpp b/modules/text/samples/webcam_demo.cpp index 3042ee218..5160e7e65 100644 --- a/modules/text/samples/webcam_demo.cpp +++ b/modules/text/samples/webcam_demo.cpp @@ -191,7 +191,8 @@ int main(int argc, char* argv[]) { //Extract MSER vector > contours; - MSER(21,(int)(0.00002*grey.cols*grey.rows),(int)(0.05*grey.cols*grey.rows),1,0.7)(grey, contours); + Ptr mser = MSER::create(21,(int)(0.00002*grey.cols*grey.rows),(int)(0.05*grey.cols*grey.rows),1,0.7); + mser->detectAndStore(grey, contours); //Convert the output of MSER to suitable input for the grouping/recognition algorithms if (contours.size() > 0) diff --git a/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp b/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp index 011e64b54..ba501d3be 100644 --- a/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp +++ b/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp @@ -47,106 +47,23 @@ namespace cv namespace xfeatures2d { -CV_EXPORTS bool initModule_xfeatures2d(void); - /*! FREAK implementation */ -class CV_EXPORTS FREAK : public DescriptorExtractor +class CV_EXPORTS FREAK : public Feature2D { public: - /** Constructor - * @param orientationNormalized enable orientation normalization - * @param scaleNormalized enable scale normalization - * @param patternScale scaling of the description pattern - * @param nbOctave number of octaves covered by the detected keypoints - * @param selectedPairs (optional) user defined selected pairs - */ - explicit FREAK( bool orientationNormalized = true, - bool scaleNormalized = true, - float patternScale = 22.0f, - int nOctaves = 4, - const std::vector& selectedPairs = std::vector()); - FREAK( const FREAK& rhs ); - FREAK& operator=( const FREAK& ); - - virtual ~FREAK(); - - /** returns the descriptor length in bytes */ - virtual int descriptorSize() const; - - /** returns the descriptor type */ - virtual int descriptorType() const; - - /** returns the default norm type */ - virtual int defaultNorm() const; - - /** select the 512 "best description pairs" - * @param images grayscale images set - * @param keypoints set of detected keypoints - * @param corrThresh correlation threshold - * @param verbose print construction information - * @return list of best pair indexes - */ - std::vector selectPairs( const std::vector& images, std::vector >& keypoints, - const double corrThresh = 0.7, bool verbose = true ); - - AlgorithmInfo* info() const; enum { NB_SCALES = 64, NB_PAIRS = 512, NB_ORIENPAIRS = 45 }; -protected: - virtual void computeImpl( InputArray image, std::vector& keypoints, OutputArray descriptors ) const; - void buildPattern(); - - template - imgType meanIntensity( InputArray image, InputArray integral, const float kp_x, const float kp_y, - const unsigned int scale, const unsigned int rot, const unsigned int point ) const; - - template - void computeDescriptors( InputArray image, std::vector& keypoints, OutputArray descriptors ) const; - - template - void extractDescriptor(srcMatType *pointsValue, void ** ptr) const; - - bool orientationNormalized; //true if the orientation is normalized, false otherwise - bool scaleNormalized; //true if the scale is normalized, false otherwise - double patternScale; //scaling of the pattern - int nOctaves; //number of octaves - bool extAll; // true if all pairs need to be extracted for pairs selection - - double patternScale0; - int nOctaves0; - std::vector selectedPairs0; - - struct PatternPoint - { - float x; // x coordinate relative to center - float y; // x coordinate relative to center - float sigma; // Gaussian smoothing sigma - }; - - struct DescriptionPair - { - uchar i; // index of the first point - uchar j; // index of the second point - }; - - struct OrientationPair - { - uchar i; // index of the first point - uchar j; // index of the second point - int weight_dx; // dx/(norm_sq))*4096 - int weight_dy; // dy/(norm_sq))*4096 - }; - - std::vector patternLookup; // look-up table for the pattern points (position+sigma of all points at all scales and orientation) - int patternSizes[NB_SCALES]; // size of the pattern at a specific scale (used to check if a point is within image boundaries) - DescriptionPair descriptionPairs[NB_PAIRS]; - OrientationPair orientationPairs[NB_ORIENPAIRS]; + static Ptr create(bool orientationNormalized = true, + bool scaleNormalized = true, + float patternScale = 22.0f, + int nOctaves = 4, + const std::vector& selectedPairs = std::vector()); }; @@ -155,63 +72,23 @@ protected: The class implements the keypoint detector introduced by K. Konolige. */ -class CV_EXPORTS_W StarDetector : public FeatureDetector +class CV_EXPORTS StarDetector : public FeatureDetector { public: //! the full constructor - CV_WRAP StarDetector(int _maxSize=45, int _responseThreshold=30, - int _lineThresholdProjected=10, - int _lineThresholdBinarized=8, - int _suppressNonmaxSize=5); - - //! finds the keypoints in the image - CV_WRAP_AS(detect) void operator()(const Mat& image, - CV_OUT std::vector& keypoints) const; - - AlgorithmInfo* info() const; - -protected: - void detectImpl( InputArray image, std::vector& keypoints, InputArray mask=noArray() ) const; - - int maxSize; - int responseThreshold; - int lineThresholdProjected; - int lineThresholdBinarized; - int suppressNonmaxSize; + static Ptr create(int maxSize=45, int responseThreshold=30, + int lineThresholdProjected=10, + int lineThresholdBinarized=8, + int suppressNonmaxSize=5); }; -typedef StarDetector StarFeatureDetector; - /* * BRIEF Descriptor */ class CV_EXPORTS BriefDescriptorExtractor : public DescriptorExtractor { public: - static const int PATCH_SIZE = 48; - static const int KERNEL_SIZE = 9; - - // bytes is a length of descriptor in bytes. It can be equal 16, 32 or 64 bytes. - BriefDescriptorExtractor( int bytes = 32 ); - - virtual void read( const FileNode& ); - virtual void write( FileStorage& ) const; - - virtual int descriptorSize() const; - virtual int descriptorType() const; - virtual int defaultNorm() const; - - /// @todo read and write for brief - - AlgorithmInfo* info() const; - -protected: - virtual void computeImpl(InputArray image, std::vector& keypoints, OutputArray descriptors) const; - - typedef void(*PixelTestFn)(InputArray, const std::vector&, OutputArray); - - int bytes_; - PixelTestFn test_fn_; + static Ptr create( int bytes = 32 ); }; } diff --git a/modules/xfeatures2d/include/opencv2/xfeatures2d/nonfree.hpp b/modules/xfeatures2d/include/opencv2/xfeatures2d/nonfree.hpp index eaa60bc2b..4fc288071 100644 --- a/modules/xfeatures2d/include/opencv2/xfeatures2d/nonfree.hpp +++ b/modules/xfeatures2d/include/opencv2/xfeatures2d/nonfree.hpp @@ -58,45 +58,9 @@ namespace xfeatures2d class CV_EXPORTS_W SIFT : public Feature2D { public: - CV_WRAP explicit SIFT( int nfeatures = 0, int nOctaveLayers = 3, - double contrastThreshold = 0.04, double edgeThreshold = 10, - double sigma = 1.6); - - //! returns the descriptor size in floats (128) - CV_WRAP int descriptorSize() const; - - //! returns the descriptor type - CV_WRAP int descriptorType() const; - - //! returns the default norm type - CV_WRAP int defaultNorm() const; - - //! finds the keypoints using SIFT algorithm - void operator()(InputArray img, InputArray mask, - std::vector& keypoints) const; - //! finds the keypoints and computes descriptors for them using SIFT algorithm. - //! Optionally it can compute descriptors for the user-provided keypoints - void operator()(InputArray img, InputArray mask, - std::vector& keypoints, - OutputArray descriptors, - bool useProvidedKeypoints = false) const; - - AlgorithmInfo* info() const; - - void buildGaussianPyramid( const Mat& base, std::vector& pyr, int nOctaves ) const; - void buildDoGPyramid( const std::vector& pyr, std::vector& dogpyr ) const; - void findScaleSpaceExtrema( const std::vector& gauss_pyr, const std::vector& dog_pyr, - std::vector& keypoints ) const; - -protected: - void detectImpl( InputArray image, std::vector& keypoints, InputArray mask = noArray() ) const; - void computeImpl( InputArray image, std::vector& keypoints, OutputArray descriptors ) const; - - CV_PROP_RW int nfeatures; - CV_PROP_RW int nOctaveLayers; - CV_PROP_RW double contrastThreshold; - CV_PROP_RW double edgeThreshold; - CV_PROP_RW double sigma; + CV_WRAP static Ptr create( int nfeatures = 0, int nOctaveLayers = 3, + double contrastThreshold = 0.04, double edgeThreshold = 10, + double sigma = 1.6); }; typedef SIFT SiftFeatureDetector; @@ -110,42 +74,9 @@ typedef SIFT SiftDescriptorExtractor; class CV_EXPORTS_W SURF : public Feature2D { public: - //! the default constructor - CV_WRAP SURF(); - //! the full constructor taking all the necessary parameters - explicit CV_WRAP SURF(double hessianThreshold, - int nOctaves = 4, int nOctaveLayers = 2, - bool extended = true, bool upright = false); - - //! returns the descriptor size in float's (64 or 128) - CV_WRAP int descriptorSize() const; - - //! returns the descriptor type - CV_WRAP int descriptorType() const; - - //! returns the descriptor type - CV_WRAP int defaultNorm() const; - - //! finds the keypoints using fast hessian detector used in SURF - void operator()(InputArray img, InputArray mask, - CV_OUT std::vector& keypoints) const; - //! finds the keypoints and computes their descriptors. Optionally it can compute descriptors for the user-provided keypoints - void operator()(InputArray img, InputArray mask, - CV_OUT std::vector& keypoints, - OutputArray descriptors, - bool useProvidedKeypoints = false) const; - - AlgorithmInfo* info() const; - - CV_PROP_RW double hessianThreshold; - CV_PROP_RW int nOctaves; - CV_PROP_RW int nOctaveLayers; - CV_PROP_RW bool extended; - CV_PROP_RW bool upright; - -protected: - void detectImpl( InputArray image, std::vector& keypoints, InputArray mask = noArray() ) const; - void computeImpl( InputArray image, std::vector& keypoints, OutputArray descriptors ) const; + CV_WRAP static Ptr create(double hessianThreshold=100, + int nOctaves = 4, int nOctaveLayers = 3, + bool extended = false, bool upright = false); }; typedef SURF SurfFeatureDetector; diff --git a/modules/xfeatures2d/perf/perf_surf.cpp b/modules/xfeatures2d/perf/perf_surf.cpp index 1fa6965ca..165c4bb2e 100644 --- a/modules/xfeatures2d/perf/perf_surf.cpp +++ b/modules/xfeatures2d/perf/perf_surf.cpp @@ -21,10 +21,10 @@ PERF_TEST_P(surf, detect, testing::Values(SURF_IMAGES)) Mat mask; declare.in(frame).time(90); - SURF detector; + Ptr detector = SURF::create(); vector points; - TEST_CYCLE() detector(frame, mask, points); + TEST_CYCLE() detector->detect(frame, points, mask); SANITY_CHECK_KEYPOINTS(points, 1e-3); } @@ -38,12 +38,12 @@ PERF_TEST_P(surf, extract, testing::Values(SURF_IMAGES)) Mat mask; declare.in(frame).time(90); - SURF detector; + Ptr detector = SURF::create(); vector points; vector descriptors; - detector(frame, mask, points); + detector->detect(frame, points, mask); - TEST_CYCLE() detector(frame, mask, points, descriptors, true); + TEST_CYCLE() detector->compute(frame, points, descriptors); SANITY_CHECK(descriptors, 1e-4); } @@ -56,11 +56,11 @@ PERF_TEST_P(surf, full, testing::Values(SURF_IMAGES)) Mat mask; declare.in(frame).time(90); - SURF detector; + Ptr detector = SURF::create(); vector points; vector descriptors; - TEST_CYCLE() detector(frame, mask, points, descriptors, false); + TEST_CYCLE() detector->detectAndCompute(frame, mask, points, descriptors, false); SANITY_CHECK_KEYPOINTS(points, 1e-3); SANITY_CHECK(descriptors, 1e-4); diff --git a/modules/xfeatures2d/samples/bagofwords_classification.cpp b/modules/xfeatures2d/samples/bagofwords_classification.cpp index a327c1bce..3ad77ba66 100644 --- a/modules/xfeatures2d/samples/bagofwords_classification.cpp +++ b/modules/xfeatures2d/samples/bagofwords_classification.cpp @@ -2512,6 +2512,23 @@ static void computeGnuPlotOutput( const string& resPath, const string& objClassN vocData.savePrecRecallToGnuplot( resPath + plotsDir + "/" + plotFile, precision, recall, ap, objClassName, CV_VOC_PLOT_PNG ); } +static Ptr createByName(const String& name) +{ + if( name == "SIFT" ) + return SIFT::create(); + if( name == "SURF" ) + return SURF::create(); + if( name == "ORB" ) + return ORB::create(); + if( name == "BRISK" ) + return BRISK::create(); + if( name == "KAZE" ) + return KAZE::create(); + if( name == "AKAZE" ) + return AKAZE::create(); + return Ptr(); +} + int main(int argc, char** argv) { if( argc != 3 && argc != 6 ) @@ -2520,9 +2537,6 @@ int main(int argc, char** argv) return -1; } - initModule_features2d(); - initModule_xfeatures2d(); - const string vocPath = argv[1], resPath = argv[2]; // Read or set default parameters @@ -2563,8 +2577,13 @@ int main(int argc, char** argv) } // Create detector, descriptor, matcher. - Ptr featureDetector = FeatureDetector::create( ddmParams.detectorType ); - Ptr descExtractor = DescriptorExtractor::create( ddmParams.descriptorType ); + if( ddmParams.detectorType != ddmParams.descriptorType ) + { + cout << "detector and descriptor should be the same\n"; + return -1; + } + Ptr featureDetector = createByName( ddmParams.detectorType ); + Ptr descExtractor = featureDetector; Ptr bowExtractor; if( !featureDetector || !descExtractor ) { diff --git a/modules/xfeatures2d/samples/shape_transformation.cpp b/modules/xfeatures2d/samples/shape_transformation.cpp index e21160748..33a57ef93 100644 --- a/modules/xfeatures2d/samples/shape_transformation.cpp +++ b/modules/xfeatures2d/samples/shape_transformation.cpp @@ -34,20 +34,15 @@ int main(int argc, char** argv) return -1; } - // detecting keypoints - SurfFeatureDetector detector(5000); + // detecting keypoints & computing descriptors + Ptr surf = SURF::create(5000); vector keypoints1, keypoints2; - detector.detect(img1, keypoints1); - detector.detect(img2, keypoints2); - - // computing descriptors - SurfDescriptorExtractor extractor; Mat descriptors1, descriptors2; - extractor.compute(img1, keypoints1, descriptors1); - extractor.compute(img2, keypoints2, descriptors2); + surf->detectAndCompute(img1, Mat(), keypoints1, descriptors1); + surf->detectAndCompute(img2, Mat(), keypoints2, descriptors2); // matching descriptors - BFMatcher matcher(extractor.defaultNorm()); + BFMatcher matcher(surf->defaultNorm()); vector matches; matcher.match(descriptors1, descriptors2, matches); diff --git a/modules/xfeatures2d/samples/surf_matcher.cpp b/modules/xfeatures2d/samples/surf_matcher.cpp index beb3e3ba4..1c367f17a 100644 --- a/modules/xfeatures2d/samples/surf_matcher.cpp +++ b/modules/xfeatures2d/samples/surf_matcher.cpp @@ -35,18 +35,17 @@ static double getTime() return work_end /((double)getTickFrequency() )* 1000.; } -template struct SURFDetector { - KPDetector surf; + Ptr surf; SURFDetector(double hessian = 800.0) - :surf(hessian) { + surf = SURF::create(hessian); } template void operator()(const T& in, const T& mask, std::vector& pts, T& descriptors, bool useProvided = false) { - surf(in, mask, pts, descriptors, useProvided); + surf->detectAndCompute(in, mask, pts, descriptors, useProvided); } }; @@ -191,7 +190,7 @@ int main(int argc, char* argv[]) descriptors2 = _descriptors2.getMat(ACCESS_RW); //instantiate detectors/matchers - SURFDetector surf; + SURFDetector surf; SURFMatcher matcher; diff --git a/modules/xfeatures2d/samples/video_homography.cpp b/modules/xfeatures2d/samples/video_homography.cpp index b06975e23..d68eee506 100644 --- a/modules/xfeatures2d/samples/video_homography.cpp +++ b/modules/xfeatures2d/samples/video_homography.cpp @@ -123,7 +123,7 @@ int main(int ac, char ** av) return 1; } - BriefDescriptorExtractor brief(32); + Ptr brief = BriefDescriptorExtractor::create(32); VideoCapture capture; capture.open(atoi(av[1])); @@ -143,7 +143,7 @@ int main(int ac, char ** av) vector matches; - BFMatcher desc_matcher(brief.defaultNorm()); + BFMatcher desc_matcher(brief->defaultNorm()); vector train_pts, query_pts; vector train_kpts, query_kpts; @@ -154,7 +154,7 @@ int main(int ac, char ** av) bool ref_live = true; Mat train_desc, query_desc; - FastFeatureDetector detector(10, true); + Ptr detector = FastFeatureDetector::create(10, true); Mat H_prev = Mat::eye(3, 3, CV_32FC1); for (;;) @@ -165,9 +165,8 @@ int main(int ac, char ** av) cvtColor(frame, gray, COLOR_RGB2GRAY); - detector.detect(gray, query_kpts); //Find interest points - - brief.compute(gray, query_kpts, query_desc); //Compute brief descriptors at each keypoint location + detector->detect(gray, query_kpts); //Find interest points + brief->compute(gray, query_kpts, query_desc); //Compute brief descriptors at each keypoint location if (!train_kpts.empty()) { diff --git a/modules/xfeatures2d/src/brief.cpp b/modules/xfeatures2d/src/brief.cpp index 58d3d5c88..ec131cbfa 100644 --- a/modules/xfeatures2d/src/brief.cpp +++ b/modules/xfeatures2d/src/brief.cpp @@ -52,9 +52,41 @@ namespace cv namespace xfeatures2d { +/* + * BRIEF Descriptor + */ +class BriefDescriptorExtractorImpl : public BriefDescriptorExtractor +{ +public: + enum { PATCH_SIZE = 48, KERNEL_SIZE = 9 }; + + // bytes is a length of descriptor in bytes. It can be equal 16, 32 or 64 bytes. + BriefDescriptorExtractorImpl( int bytes = 32 ); + + virtual void read( const FileNode& ); + virtual void write( FileStorage& ) const; + + virtual int descriptorSize() const; + virtual int descriptorType() const; + virtual int defaultNorm() const; + + virtual void compute(InputArray image, std::vector& keypoints, OutputArray descriptors); + +protected: + typedef void(*PixelTestFn)(InputArray, const std::vector&, OutputArray); + + int bytes_; + PixelTestFn test_fn_; +}; + +Ptr BriefDescriptorExtractor::create( int bytes ) +{ + return makePtr(bytes); +} + inline int smoothedSum(const Mat& sum, const KeyPoint& pt, int y, int x) { - static const int HALF_KERNEL = BriefDescriptorExtractor::KERNEL_SIZE / 2; + static const int HALF_KERNEL = BriefDescriptorExtractorImpl::KERNEL_SIZE / 2; int img_y = (int)(pt.pt.y + 0.5) + y; int img_x = (int)(pt.pt.x + 0.5) + x; @@ -99,7 +131,7 @@ static void pixelTests64(InputArray _sum, const std::vector& keypoints } } -BriefDescriptorExtractor::BriefDescriptorExtractor(int bytes) : +BriefDescriptorExtractorImpl::BriefDescriptorExtractorImpl(int bytes) : bytes_(bytes), test_fn_(NULL) { switch (bytes) @@ -118,22 +150,22 @@ BriefDescriptorExtractor::BriefDescriptorExtractor(int bytes) : } } -int BriefDescriptorExtractor::descriptorSize() const +int BriefDescriptorExtractorImpl::descriptorSize() const { return bytes_; } -int BriefDescriptorExtractor::descriptorType() const +int BriefDescriptorExtractorImpl::descriptorType() const { return CV_8UC1; } -int BriefDescriptorExtractor::defaultNorm() const +int BriefDescriptorExtractorImpl::defaultNorm() const { return NORM_HAMMING; } -void BriefDescriptorExtractor::read( const FileNode& fn) +void BriefDescriptorExtractorImpl::read( const FileNode& fn) { int dSize = fn["descriptorSize"]; switch (dSize) @@ -153,12 +185,14 @@ void BriefDescriptorExtractor::read( const FileNode& fn) bytes_ = dSize; } -void BriefDescriptorExtractor::write( FileStorage& fs) const +void BriefDescriptorExtractorImpl::write( FileStorage& fs) const { fs << "descriptorSize" << bytes_; } -void BriefDescriptorExtractor::computeImpl(InputArray image, std::vector& keypoints, OutputArray descriptors) const +void BriefDescriptorExtractorImpl::compute(InputArray image, + std::vector& keypoints, + OutputArray descriptors) { // Construct integral image for fast smoothing (box filter) Mat sum; diff --git a/modules/xfeatures2d/src/freak.cpp b/modules/xfeatures2d/src/freak.cpp index 4eb7e5df4..dbb30d195 100644 --- a/modules/xfeatures2d/src/freak.cpp +++ b/modules/xfeatures2d/src/freak.cpp @@ -46,6 +46,99 @@ namespace cv namespace xfeatures2d { +/*! + FREAK implementation + */ +class FREAK_Impl : public FREAK +{ +public: + /** Constructor + * @param orientationNormalized enable orientation normalization + * @param scaleNormalized enable scale normalization + * @param patternScale scaling of the description pattern + * @param nbOctave number of octaves covered by the detected keypoints + * @param selectedPairs (optional) user defined selected pairs + */ + explicit FREAK_Impl( bool orientationNormalized = true, + bool scaleNormalized = true, + float patternScale = 22.0f, + int nOctaves = 4, + const std::vector& selectedPairs = std::vector()); + + virtual ~FREAK_Impl(); + + /** returns the descriptor length in bytes */ + virtual int descriptorSize() const; + + /** returns the descriptor type */ + virtual int descriptorType() const; + + /** returns the default norm type */ + virtual int defaultNorm() const; + + /** select the 512 "best description pairs" + * @param images grayscale images set + * @param keypoints set of detected keypoints + * @param corrThresh correlation threshold + * @param verbose print construction information + * @return list of best pair indexes + */ + std::vector selectPairs( const std::vector& images, std::vector >& keypoints, + const double corrThresh = 0.7, bool verbose = true ); + virtual void compute( InputArray image, std::vector& keypoints, OutputArray descriptors ); + +protected: + + void buildPattern(); + + template + imgType meanIntensity( InputArray image, InputArray integral, const float kp_x, const float kp_y, + const unsigned int scale, const unsigned int rot, const unsigned int point ); + + template + void computeDescriptors( InputArray image, std::vector& keypoints, OutputArray descriptors ); + + template + void extractDescriptor(srcMatType *pointsValue, void ** ptr); + + bool orientationNormalized; //true if the orientation is normalized, false otherwise + bool scaleNormalized; //true if the scale is normalized, false otherwise + double patternScale; //scaling of the pattern + int nOctaves; //number of octaves + bool extAll; // true if all pairs need to be extracted for pairs selection + + double patternScale0; + int nOctaves0; + std::vector selectedPairs0; + + struct PatternPoint + { + float x; // x coordinate relative to center + float y; // x coordinate relative to center + float sigma; // Gaussian smoothing sigma + }; + + struct DescriptionPair + { + uchar i; // index of the first point + uchar j; // index of the second point + }; + + struct OrientationPair + { + uchar i; // index of the first point + uchar j; // index of the second point + int weight_dx; // dx/(norm_sq))*4096 + int weight_dy; // dy/(norm_sq))*4096 + }; + + std::vector patternLookup; // look-up table for the pattern points (position+sigma of all points at all scales and orientation) + int patternSizes[NB_SCALES]; // size of the pattern at a specific scale (used to check if a point is within image boundaries) + DescriptionPair descriptionPairs[NB_PAIRS]; + OrientationPair orientationPairs[NB_ORIENPAIRS]; +}; + + static const double FREAK_LOG2 = 0.693147180559945; static const int FREAK_NB_ORIENTATION = 256; static const int FREAK_NB_POINTS = 43; @@ -55,7 +148,7 @@ static const int FREAK_NB_PAIRS = FREAK::NB_PAIRS; static const int FREAK_NB_ORIENPAIRS = FREAK::NB_ORIENPAIRS; // default pairs -static const int FREAK_DEF_PAIRS[FREAK::NB_PAIRS] = +static const int FREAK_DEF_PAIRS[FREAK_Impl::NB_PAIRS] = { 404,431,818,511,181,52,311,874,774,543,719,230,417,205,11, 560,149,265,39,306,165,857,250,8,61,15,55,717,44,412, @@ -108,7 +201,7 @@ struct sortMean } }; -void FREAK::buildPattern() +void FREAK_Impl::buildPattern() { if( patternScale == patternScale0 && nOctaves == nOctaves0 && !patternLookup.empty() ) return; @@ -229,7 +322,7 @@ void FREAK::buildPattern() } } -void FREAK::computeImpl( InputArray _image, std::vector& keypoints, OutputArray _descriptors ) const +void FREAK_Impl::compute( InputArray _image, std::vector& keypoints, OutputArray _descriptors ) { Mat image = _image.getMat(); if( image.empty() ) @@ -237,7 +330,7 @@ void FREAK::computeImpl( InputArray _image, std::vector& keypoints, Ou if( keypoints.empty() ) return; - ((FREAK*)this)->buildPattern(); + ((FREAK_Impl*)this)->buildPattern(); // Convert to gray if not already Mat grayImage = image; @@ -271,7 +364,7 @@ void FREAK::computeImpl( InputArray _image, std::vector& keypoints, Ou } template -void FREAK::extractDescriptor(srcMatType *pointsValue, void ** ptr) const +void FREAK_Impl::extractDescriptor(srcMatType *pointsValue, void ** ptr) { std::bitset** ptrScalar = (std::bitset**) ptr; @@ -293,7 +386,7 @@ void FREAK::extractDescriptor(srcMatType *pointsValue, void ** ptr) const #if CV_SSE2 template <> -void FREAK::extractDescriptor(uchar *pointsValue, void ** ptr) const +void FREAK_Impl::extractDescriptor(uchar *pointsValue, void ** ptr) { __m128i** ptrSSE = (__m128i**) ptr; @@ -352,7 +445,7 @@ void FREAK::extractDescriptor(uchar *pointsValue, void ** ptr) const #endif template -void FREAK::computeDescriptors( InputArray _image, std::vector& keypoints, OutputArray _descriptors ) const { +void FREAK_Impl::computeDescriptors( InputArray _image, std::vector& keypoints, OutputArray _descriptors ){ Mat image = _image.getMat(); Mat imgIntegral; @@ -529,12 +622,13 @@ void FREAK::computeDescriptors( InputArray _image, std::vector& keypoi // simply take average on a square patch, not even gaussian approx template -imgType FREAK::meanIntensity( InputArray _image, InputArray _integral, +imgType FREAK_Impl::meanIntensity( InputArray _image, InputArray _integral, const float kp_x, const float kp_y, const unsigned int scale, const unsigned int rot, - const unsigned int point) const { + const unsigned int point) +{ Mat image = _image.getMat(), integral = _integral.getMat(); // get point position in image const PatternPoint& FreakPoint = patternLookup[scale*FREAK_NB_ORIENTATION*FREAK_NB_POINTS + rot*FREAK_NB_POINTS + point]; @@ -584,7 +678,7 @@ imgType FREAK::meanIntensity( InputArray _image, InputArray _integral, } // pair selection algorithm from a set of training images and corresponding keypoints -std::vector FREAK::selectPairs(const std::vector& images +std::vector FREAK_Impl::selectPairs(const std::vector& images , std::vector >& keypoints , const double corrTresh , bool verbose ) @@ -599,7 +693,7 @@ std::vector FREAK::selectPairs(const std::vector& images for( size_t i = 0;i < images.size(); ++i ) { Mat descriptorsTmp; - computeImpl(images[i],keypoints[i],descriptorsTmp); + compute(images[i],keypoints[i],descriptorsTmp); descriptors.push_back(descriptorsTmp); } @@ -705,31 +799,41 @@ void FREAKImpl::drawPattern() // ------------------------------------------------- /* FREAK interface implementation */ -FREAK::FREAK( bool _orientationNormalized, bool _scaleNormalized +FREAK_Impl::FREAK_Impl( bool _orientationNormalized, bool _scaleNormalized , float _patternScale, int _nOctaves, const std::vector& _selectedPairs ) : orientationNormalized(_orientationNormalized), scaleNormalized(_scaleNormalized), patternScale(_patternScale), nOctaves(_nOctaves), extAll(false), nOctaves0(0), selectedPairs0(_selectedPairs) { } -FREAK::~FREAK() +FREAK_Impl::~FREAK_Impl() { } -int FREAK::descriptorSize() const +int FREAK_Impl::descriptorSize() const { return FREAK_NB_PAIRS / 8; // descriptor length in bytes } -int FREAK::descriptorType() const +int FREAK_Impl::descriptorType() const { return CV_8U; } -int FREAK::defaultNorm() const +int FREAK_Impl::defaultNorm() const { return NORM_HAMMING; } +Ptr FREAK::create(bool orientationNormalized, + bool scaleNormalized, + float patternScale, + int nOctaves, + const std::vector& selectedPairs) +{ + return makePtr(orientationNormalized, scaleNormalized, + patternScale, nOctaves, selectedPairs); +} + } } // END NAMESPACE CV diff --git a/modules/xfeatures2d/src/sift.cpp b/modules/xfeatures2d/src/sift.cpp index ca1f52337..4ed1e4142 100644 --- a/modules/xfeatures2d/src/sift.cpp +++ b/modules/xfeatures2d/src/sift.cpp @@ -111,6 +111,53 @@ namespace cv namespace xfeatures2d { +/*! + SIFT implementation. + + The class implements SIFT algorithm by D. Lowe. + */ +class SIFT_Impl : public SIFT +{ +public: + explicit SIFT_Impl( int nfeatures = 0, int nOctaveLayers = 3, + double contrastThreshold = 0.04, double edgeThreshold = 10, + double sigma = 1.6); + + //! returns the descriptor size in floats (128) + int descriptorSize() const; + + //! returns the descriptor type + int descriptorType() const; + + //! returns the default norm type + int defaultNorm() const; + + //! finds the keypoints and computes descriptors for them using SIFT algorithm. + //! Optionally it can compute descriptors for the user-provided keypoints + void detectAndCompute(InputArray img, InputArray mask, + std::vector& keypoints, + OutputArray descriptors, + bool useProvidedKeypoints = false); + + void buildGaussianPyramid( const Mat& base, std::vector& pyr, int nOctaves ) const; + void buildDoGPyramid( const std::vector& pyr, std::vector& dogpyr ) const; + void findScaleSpaceExtrema( const std::vector& gauss_pyr, const std::vector& dog_pyr, + std::vector& keypoints ) const; + +protected: + CV_PROP_RW int nfeatures; + CV_PROP_RW int nOctaveLayers; + CV_PROP_RW double contrastThreshold; + CV_PROP_RW double edgeThreshold; + CV_PROP_RW double sigma; +}; + +Ptr SIFT::create( int _nfeatures, int _nOctaveLayers, + double _contrastThreshold, double _edgeThreshold, double _sigma ) +{ + return makePtr(_nfeatures, _nOctaveLayers, _contrastThreshold, _edgeThreshold, _sigma); +} + /******************************* Defs and macros *****************************/ // default width of descriptor histogram array @@ -196,7 +243,7 @@ static Mat createInitialImage( const Mat& img, bool doubleImageSize, float sigma } -void SIFT::buildGaussianPyramid( const Mat& base, std::vector& pyr, int nOctaves ) const +void SIFT_Impl::buildGaussianPyramid( const Mat& base, std::vector& pyr, int nOctaves ) const { std::vector sig(nOctaveLayers + 3); pyr.resize(nOctaves*(nOctaveLayers + 3)); @@ -236,7 +283,7 @@ void SIFT::buildGaussianPyramid( const Mat& base, std::vector& pyr, int nOc } -void SIFT::buildDoGPyramid( const std::vector& gpyr, std::vector& dogpyr ) const +void SIFT_Impl::buildDoGPyramid( const std::vector& gpyr, std::vector& dogpyr ) const { int nOctaves = (int)gpyr.size()/(nOctaveLayers + 3); dogpyr.resize( nOctaves*(nOctaveLayers + 2) ); @@ -434,7 +481,7 @@ static bool adjustLocalExtrema( const std::vector& dog_pyr, KeyPoint& kpt, // // Detects features at extrema in DoG scale space. Bad features are discarded // based on contrast and ratio of principal curvatures. -void SIFT::findScaleSpaceExtrema( const std::vector& gauss_pyr, const std::vector& dog_pyr, +void SIFT_Impl::findScaleSpaceExtrema( const std::vector& gauss_pyr, const std::vector& dog_pyr, std::vector& keypoints ) const { int nOctaves = (int)gauss_pyr.size()/(nOctaveLayers + 3); @@ -687,40 +734,33 @@ static void calcDescriptors(const std::vector& gpyr, const std::vector& keypoints) const -{ - (*this)(_image, _mask, keypoints, noArray()); -} - - -void SIFT::operator()(InputArray _image, InputArray _mask, +void SIFT_Impl::detectAndCompute(InputArray _image, InputArray _mask, std::vector& keypoints, OutputArray _descriptors, - bool useProvidedKeypoints) const + bool useProvidedKeypoints) { int firstOctave = -1, actualNOctaves = 0, actualNLayers = 0; Mat image = _image.getMat(), mask = _mask.getMat(); @@ -805,15 +845,5 @@ void SIFT::operator()(InputArray _image, InputArray _mask, } } -void SIFT::detectImpl( InputArray image, std::vector& keypoints, InputArray mask) const -{ - (*this)(image.getMat(), mask.getMat(), keypoints, noArray()); -} - -void SIFT::computeImpl( InputArray image, std::vector& keypoints, OutputArray descriptors) const -{ - (*this)(image, Mat(), keypoints, descriptors, true); -} - } } diff --git a/modules/xfeatures2d/src/stardetector.cpp b/modules/xfeatures2d/src/stardetector.cpp index 0233d792e..96ed1a326 100644 --- a/modules/xfeatures2d/src/stardetector.cpp +++ b/modules/xfeatures2d/src/stardetector.cpp @@ -46,6 +46,43 @@ namespace cv namespace xfeatures2d { +/*! + The "Star" Detector. + + The class implements the keypoint detector introduced by K. Konolige. + */ +class StarDetectorImpl : public StarDetector +{ +public: + //! the full constructor + StarDetectorImpl(int _maxSize=45, int _responseThreshold=30, + int _lineThresholdProjected=10, + int _lineThresholdBinarized=8, + int _suppressNonmaxSize=5); + + void detect( InputArray image, std::vector& keypoints, InputArray mask=noArray() ); + +protected: + int maxSize; + int responseThreshold; + int lineThresholdProjected; + int lineThresholdBinarized; + int suppressNonmaxSize; +}; + +Ptr StarDetector::create(int _maxSize, + int _responseThreshold, + int _lineThresholdProjected, + int _lineThresholdBinarized, + int _suppressNonmaxSize) +{ + return makePtr(_maxSize, _responseThreshold, + _lineThresholdProjected, + _lineThresholdBinarized, + _suppressNonmaxSize); +} + + template static void computeIntegralImages( const Mat& matI, Mat& matS, Mat& matT, Mat& _FT, int iiType ) @@ -432,7 +469,7 @@ StarDetectorSuppressNonmax( const Mat& responses, const Mat& sizes, } } -StarDetector::StarDetector(int _maxSize, int _responseThreshold, +StarDetectorImpl::StarDetectorImpl(int _maxSize, int _responseThreshold, int _lineThresholdProjected, int _lineThresholdBinarized, int _suppressNonmaxSize) @@ -443,32 +480,27 @@ StarDetector::StarDetector(int _maxSize, int _responseThreshold, {} -void StarDetector::detectImpl( InputArray _image, std::vector& keypoints, InputArray _mask ) const +void StarDetectorImpl::detect( InputArray _image, std::vector& keypoints, InputArray _mask ) { Mat image = _image.getMat(), mask = _mask.getMat(), grayImage = image; if( image.channels() > 1 ) cvtColor( image, grayImage, COLOR_BGR2GRAY ); - (*this)(grayImage, keypoints); - KeyPointsFilter::runByPixelsMask( keypoints, mask ); -} - -void StarDetector::operator()(const Mat& img, std::vector& keypoints) const -{ Mat responses, sizes; int border; // Use 32-bit integers if we won't overflow in the integral image - if ((img.depth() == CV_8U || img.depth() == CV_8S) && - (img.rows * img.cols) < 8388608 ) // 8388608 = 2 ^ (32 - 8(bit depth) - 1(sign bit)) - border = StarDetectorComputeResponses( img, responses, sizes, maxSize, CV_32S ); + if ((grayImage.depth() == CV_8U || grayImage.depth() == CV_8S) && + (int)grayImage.total() < 8388608 ) // 8388608 = 2 ^ (32 - 8(bit depth) - 1(sign bit)) + border = StarDetectorComputeResponses( grayImage, responses, sizes, maxSize, CV_32S ); else - border = StarDetectorComputeResponses( img, responses, sizes, maxSize, CV_64F ); + border = StarDetectorComputeResponses( grayImage, responses, sizes, maxSize, CV_64F ); keypoints.clear(); if( border >= 0 ) StarDetectorSuppressNonmax( responses, sizes, keypoints, border, - responseThreshold, lineThresholdProjected, - lineThresholdBinarized, suppressNonmaxSize ); + responseThreshold, lineThresholdProjected, + lineThresholdBinarized, suppressNonmaxSize ); + KeyPointsFilter::runByPixelsMask( keypoints, mask ); } } diff --git a/modules/xfeatures2d/src/surf.cpp b/modules/xfeatures2d/src/surf.cpp index 7a985211f..673817e73 100644 --- a/modules/xfeatures2d/src/surf.cpp +++ b/modules/xfeatures2d/src/surf.cpp @@ -867,16 +867,7 @@ struct SURFInvoker : ParallelLoopBody }; -SURF::SURF() -{ - hessianThreshold = 100; - extended = false; - upright = false; - nOctaves = 4; - nOctaveLayers = 3; -} - -SURF::SURF(double _threshold, int _nOctaves, int _nOctaveLayers, bool _extended, bool _upright) +SURF_Impl::SURF_Impl(double _threshold, int _nOctaves, int _nOctaveLayers, bool _extended, bool _upright) { hessianThreshold = _threshold; extended = _extended; @@ -885,20 +876,15 @@ SURF::SURF(double _threshold, int _nOctaves, int _nOctaveLayers, bool _extended, nOctaveLayers = _nOctaveLayers; } -int SURF::descriptorSize() const { return extended ? 128 : 64; } -int SURF::descriptorType() const { return CV_32F; } -int SURF::defaultNorm() const { return NORM_L2; } +int SURF_Impl::descriptorSize() const { return extended ? 128 : 64; } +int SURF_Impl::descriptorType() const { return CV_32F; } +int SURF_Impl::defaultNorm() const { return NORM_L2; } -void SURF::operator()(InputArray imgarg, InputArray maskarg, - CV_OUT std::vector& keypoints) const -{ - (*this)(imgarg, maskarg, keypoints, noArray(), false); -} -void SURF::operator()(InputArray _img, InputArray _mask, +void SURF_Impl::detectAndCompute(InputArray _img, InputArray _mask, CV_OUT std::vector& keypoints, OutputArray _descriptors, - bool useProvidedKeypoints) const + bool useProvidedKeypoints) { int imgtype = _img.type(), imgcn = CV_MAT_CN(imgtype); bool doDescriptors = _descriptors.needed(); @@ -1012,17 +998,11 @@ void SURF::operator()(InputArray _img, InputArray _mask, } } - -void SURF::detectImpl( InputArray image, std::vector& keypoints, InputArray mask) const +Ptr SURF::create(double _threshold, int _nOctaves, int _nOctaveLayers, bool _extended, bool _upright) { - (*this)(image.getMat(), mask.getMat(), keypoints, noArray(), false); + return makePtr(_threshold, _nOctaves, _nOctaveLayers, _extended, _upright); } - -void SURF::computeImpl( InputArray image, std::vector& keypoints, OutputArray descriptors) const -{ - (*this)(image, Mat(), keypoints, descriptors, true); -} - + } } diff --git a/modules/xfeatures2d/src/surf.hpp b/modules/xfeatures2d/src/surf.hpp index 9438ac66c..59b2e8e26 100644 --- a/modules/xfeatures2d/src/surf.hpp +++ b/modules/xfeatures2d/src/surf.hpp @@ -10,6 +10,41 @@ namespace xfeatures2d //! Speeded up robust features, port from CUDA module. ////////////////////////////////// SURF ////////////////////////////////////////// +/*! + SURF implementation. + + The class implements SURF algorithm by H. Bay et al. + */ +class SURF_Impl : public SURF +{ +public: + //! the full constructor taking all the necessary parameters + explicit CV_WRAP SURF_Impl(double hessianThreshold, + int nOctaves = 4, int nOctaveLayers = 2, + bool extended = true, bool upright = false); + + //! returns the descriptor size in float's (64 or 128) + CV_WRAP int descriptorSize() const; + + //! returns the descriptor type + CV_WRAP int descriptorType() const; + + //! returns the descriptor type + CV_WRAP int defaultNorm() const; + + //! finds the keypoints and computes their descriptors. + // Optionally it can compute descriptors for the user-provided keypoints + void detectAndCompute(InputArray img, InputArray mask, + CV_OUT std::vector& keypoints, + OutputArray descriptors, + bool useProvidedKeypoints = false); + + CV_PROP_RW double hessianThreshold; + CV_PROP_RW int nOctaves; + CV_PROP_RW int nOctaveLayers; + CV_PROP_RW bool extended; + CV_PROP_RW bool upright; +}; class SURF_OCL { @@ -29,7 +64,7 @@ public: //! the full constructor taking all the necessary parameters SURF_OCL(); - bool init(const SURF* params); + bool init(const SURF_Impl* params); //! returns the descriptor size in float's (64 or 128) int descriptorSize() const { return params->extended ? 128 : 64; } @@ -71,7 +106,7 @@ protected: bool detectKeypoints(UMat &keypoints); - const SURF* params; + const SURF_Impl* params; //! max keypoints = min(keypointsRatio * img.size().area(), 65535) UMat sum, intBuffer; diff --git a/modules/xfeatures2d/src/surf.ocl.cpp b/modules/xfeatures2d/src/surf.ocl.cpp index f2057162c..b12ebd319 100644 --- a/modules/xfeatures2d/src/surf.ocl.cpp +++ b/modules/xfeatures2d/src/surf.ocl.cpp @@ -79,7 +79,7 @@ SURF_OCL::SURF_OCL() status = -1; } -bool SURF_OCL::init(const SURF* p) +bool SURF_OCL::init(const SURF_Impl* p) { params = p; if(status < 0) diff --git a/modules/xfeatures2d/src/xfeatures2d_init.cpp b/modules/xfeatures2d/src/xfeatures2d_init.cpp index 9db5c83fd..317867a59 100644 --- a/modules/xfeatures2d/src/xfeatures2d_init.cpp +++ b/modules/xfeatures2d/src/xfeatures2d_init.cpp @@ -41,59 +41,3 @@ //M*/ #include "precomp.hpp" - -namespace cv -{ -namespace xfeatures2d -{ - -/////////////////////////////////////////////////////////////////////////////////////////////////////////// - -CV_INIT_ALGORITHM(BriefDescriptorExtractor, "Feature2D.BRIEF", - obj.info()->addParam(obj, "bytes", obj.bytes_)) - -/////////////////////////////////////////////////////////////////////////////////////////////////////////// - -CV_INIT_ALGORITHM(StarDetector, "Feature2D.STAR", - obj.info()->addParam(obj, "maxSize", obj.maxSize); - obj.info()->addParam(obj, "responseThreshold", obj.responseThreshold); - obj.info()->addParam(obj, "lineThresholdProjected", obj.lineThresholdProjected); - obj.info()->addParam(obj, "lineThresholdBinarized", obj.lineThresholdBinarized); - obj.info()->addParam(obj, "suppressNonmaxSize", obj.suppressNonmaxSize)) - -/////////////////////////////////////////////////////////////////////////////////////////////////////////// - -CV_INIT_ALGORITHM(FREAK, "Feature2D.FREAK", - obj.info()->addParam(obj, "orientationNormalized", obj.orientationNormalized); - obj.info()->addParam(obj, "scaleNormalized", obj.scaleNormalized); - obj.info()->addParam(obj, "patternScale", obj.patternScale); - obj.info()->addParam(obj, "nbOctave", obj.nOctaves)) - -/////////////////////////////////////////////////////////////////////////////////////////////////////////// - -CV_INIT_ALGORITHM(SURF, "Feature2D.SURF", - obj.info()->addParam(obj, "hessianThreshold", obj.hessianThreshold); - obj.info()->addParam(obj, "nOctaves", obj.nOctaves); - obj.info()->addParam(obj, "nOctaveLayers", obj.nOctaveLayers); - obj.info()->addParam(obj, "extended", obj.extended); - obj.info()->addParam(obj, "upright", obj.upright)) - -/////////////////////////////////////////////////////////////////////////////////////////////////////////// - -CV_INIT_ALGORITHM(SIFT, "Feature2D.SIFT", - obj.info()->addParam(obj, "nFeatures", obj.nfeatures); - obj.info()->addParam(obj, "nOctaveLayers", obj.nOctaveLayers); - obj.info()->addParam(obj, "contrastThreshold", obj.contrastThreshold); - obj.info()->addParam(obj, "edgeThreshold", obj.edgeThreshold); - obj.info()->addParam(obj, "sigma", obj.sigma)) - -/////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool initModule_xfeatures2d(void) -{ - Ptr sift = createSIFT_ptr_hidden(), surf = createSURF_ptr_hidden(); - return sift->info() != 0 && surf->info() != 0; -} - -} -} diff --git a/modules/xfeatures2d/test/test_detectors.cpp b/modules/xfeatures2d/test/test_detectors.cpp index e93a20d6e..810f59712 100644 --- a/modules/xfeatures2d/test/test_detectors.cpp +++ b/modules/xfeatures2d/test/test_detectors.cpp @@ -61,7 +61,7 @@ public: ~CV_DetectorsTest(); protected: void run(int); - template bool testDetector(const Mat& img, const T& detector, vector& expected); + bool testDetector(const Mat& img, Ptr detector, vector& expected); void LoadExpected(const string& file, vector& out); }; @@ -153,10 +153,10 @@ struct WrapPoint struct sortByR { bool operator()(const KeyPoint& kp1, const KeyPoint& kp2) { return norm(kp1.pt) < norm(kp2.pt); } }; -template bool CV_DetectorsTest::testDetector(const Mat& img, const T& detector, vector& exp) +bool CV_DetectorsTest::testDetector(const Mat& img, Ptr detector, vector& exp) { vector orig_kpts; - detector(img, orig_kpts); + detector->detect(img, orig_kpts); typedef void (*TransfFunc )(const Mat&, Mat&, Mat& FransfFunc); const TransfFunc transfFunc[] = { getRotation, getZoom, getBlur, getBrightness }; @@ -173,7 +173,7 @@ template bool CV_DetectorsTest::testDetector(const Mat& img, const T& for(size_t i = 0; i < case_num; ++i) { transfFunc[i](img, affs[i], new_imgs[i]); - detector(new_imgs[i], new_kpts[i]); + detector->detect(new_imgs[i], new_kpts[i]); transform(orig_kpts.begin(), orig_kpts.end(), back_inserter(transf_kpts[i]), WrapPoint(affs[i])); //show(names[i], new_imgs[i], new_kpts[i], transf_kpts[i]); } @@ -253,14 +253,6 @@ template bool CV_DetectorsTest::testDetector(const Mat& img, const T& return true; } -struct SurfNoMaskWrap -{ - const SURF& detector; - SurfNoMaskWrap(const SURF& surf) : detector(surf) {} - SurfNoMaskWrap& operator=(const SurfNoMaskWrap&); - void operator()(const Mat& img, vector& kpts) const { detector(img, Mat(), kpts); } -}; - void CV_DetectorsTest::LoadExpected(const string& file, vector& out) { Mat mat_exp; @@ -298,14 +290,14 @@ void CV_DetectorsTest::run( int /*start_from*/ ) if (exp.empty()) return; - if (!testDetector(to_test, SurfNoMaskWrap(SURF(1536+512+512, 2)), exp)) + if (!testDetector(to_test, SURF::create(1536+512+512, 2), exp)) return; LoadExpected(string(ts->get_data_path()) + "detectors/star.xml", exp); if (exp.empty()) return; - if (!testDetector(to_test, StarDetector(45, 30, 10, 8, 5), exp)) + if (!testDetector(to_test, StarDetector::create(45, 30, 10, 8, 5), exp)) return; ts->set_failed_test_info( cvtest::TS::OK); diff --git a/modules/xfeatures2d/test/test_features2d.cpp b/modules/xfeatures2d/test/test_features2d.cpp index 81ba8da18..ecac5d119 100644 --- a/modules/xfeatures2d/test/test_features2d.cpp +++ b/modules/xfeatures2d/test/test_features2d.cpp @@ -977,19 +977,19 @@ void CV_DescriptorMatcherTest::run( int ) TEST( Features2d_Detector_SIFT, regression ) { - CV_FeatureDetectorTest test( "detector-sift", FeatureDetector::create("SIFT") ); + CV_FeatureDetectorTest test( "detector-sift", SIFT::create() ); test.safe_run(); } TEST( Features2d_Detector_SURF, regression ) { - CV_FeatureDetectorTest test( "detector-surf", FeatureDetector::create("SURF") ); + CV_FeatureDetectorTest test( "detector-surf", SURF::create() ); test.safe_run(); } TEST( Features2d_Detector_STAR, regression ) { - CV_FeatureDetectorTest test( "detector-star", FeatureDetector::create("STAR") ); + CV_FeatureDetectorTest test( "detector-star", StarDetector::create() ); test.safe_run(); } @@ -999,14 +999,14 @@ TEST( Features2d_Detector_STAR, regression ) TEST( Features2d_DescriptorExtractor_SIFT, regression ) { CV_DescriptorExtractorTest > test( "descriptor-sift", 0.03f, - DescriptorExtractor::create("SIFT") ); + SIFT::create() ); test.safe_run(); } TEST( Features2d_DescriptorExtractor_SURF, regression ) { CV_DescriptorExtractorTest > test( "descriptor-surf", 0.05f, - DescriptorExtractor::create("SURF") ); + SURF::create() ); test.safe_run(); } @@ -1014,14 +1014,14 @@ TEST( Features2d_DescriptorExtractor_FREAK, regression ) { // TODO adjust the parameters below CV_DescriptorExtractorTest test( "descriptor-freak", (CV_DescriptorExtractorTest::DistanceType)12.f, - DescriptorExtractor::create("FREAK") ); + FREAK::create() ); test.safe_run(); } TEST( Features2d_DescriptorExtractor_BRIEF, regression ) { CV_DescriptorExtractorTest test( "descriptor-brief", 1, - DescriptorExtractor::create("BRIEF") ); + BriefDescriptorExtractor::create() ); test.safe_run(); } @@ -1049,10 +1049,10 @@ TEST(Features2d_BruteForceDescriptorMatcher_knnMatch, regression) const int sz = 100; const int k = 3; - Ptr ext = DescriptorExtractor::create("SURF"); + Ptr ext = SURF::create(); ASSERT_TRUE(ext != NULL); - Ptr det = FeatureDetector::create("SURF"); + Ptr det = SURF::create(); //"%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n" ASSERT_TRUE(det != NULL); @@ -1104,13 +1104,13 @@ TEST(Features2d_BruteForceDescriptorMatcher_knnMatch, regression) class CV_DetectPlanarTest : public cvtest::BaseTest { public: - CV_DetectPlanarTest(const string& _fname, int _min_ninliers) : fname(_fname), min_ninliers(_min_ninliers) {} + CV_DetectPlanarTest(const string& _fname, int _min_ninliers, const Ptr& _f2d) + : fname(_fname), min_ninliers(_min_ninliers), f2d(_f2d) {} protected: void run(int) { - Ptr f = Algorithm::create("Feature2D." + fname); - if(!f) + if(f2d.empty()) return; string path = string(ts->get_data_path()) + "detectors_descriptors_evaluation/planar/"; string imgname1 = path + "box.png"; @@ -1125,15 +1125,15 @@ protected: } vector kpt1, kpt2; Mat d1, d2; - f->operator()(img1, Mat(), kpt1, d1); - f->operator()(img1, Mat(), kpt2, d2); + f2d->detectAndCompute(img1, Mat(), kpt1, d1); + f2d->detectAndCompute(img1, Mat(), kpt2, d2); for( size_t i = 0; i < kpt1.size(); i++ ) CV_Assert(kpt1[i].response > 0 ); for( size_t i = 0; i < kpt2.size(); i++ ) CV_Assert(kpt2[i].response > 0 ); vector matches; - BFMatcher(f->defaultNorm(), true).match(d1, d2, matches); + BFMatcher(f2d->defaultNorm(), true).match(d1, d2, matches); vector pt1, pt2; for( size_t i = 0; i < matches.size(); i++ ) { @@ -1154,10 +1154,11 @@ protected: string fname; int min_ninliers; + Ptr f2d; }; -TEST(Features2d_SIFTHomographyTest, regression) { CV_DetectPlanarTest test("SIFT", 80); test.safe_run(); } -TEST(Features2d_SURFHomographyTest, regression) { CV_DetectPlanarTest test("SURF", 80); test.safe_run(); } +TEST(Features2d_SIFTHomographyTest, regression) { CV_DetectPlanarTest test("SIFT", 80, SIFT::create()); test.safe_run(); } +TEST(Features2d_SURFHomographyTest, regression) { CV_DetectPlanarTest test("SURF", 80, SURF::create()); test.safe_run(); } class FeatureDetectorUsingMaskTest : public cvtest::BaseTest { diff --git a/modules/xfeatures2d/test/test_keypoints.cpp b/modules/xfeatures2d/test/test_keypoints.cpp index 03eea8a88..e714331a4 100644 --- a/modules/xfeatures2d/test/test_keypoints.cpp +++ b/modules/xfeatures2d/test/test_keypoints.cpp @@ -55,13 +55,12 @@ const string IMAGE_FILENAME = "tsukuba.png"; class CV_FeatureDetectorKeypointsTest : public cvtest::BaseTest { public: - CV_FeatureDetectorKeypointsTest(const Ptr& _detector) : + explicit CV_FeatureDetectorKeypointsTest(const Ptr& _detector) : detector(_detector) {} protected: virtual void run(int) { - cv::initModule_features2d(); CV_Assert(detector); string imgFilename = string(ts->get_data_path()) + FEATURES2D_DIR + "/" + IMAGE_FILENAME; @@ -113,7 +112,7 @@ protected: ts->set_failed_test_info(cvtest::TS::OK); } - Ptr detector; + Ptr detector; }; @@ -121,18 +120,18 @@ protected: TEST(Features2d_Detector_Keypoints_SURF, validation) { - CV_FeatureDetectorKeypointsTest test(Algorithm::create("Feature2D.SURF")); + CV_FeatureDetectorKeypointsTest test(xfeatures2d::SURF::create()); test.safe_run(); } TEST(Features2d_Detector_Keypoints_SIFT, validation) { - CV_FeatureDetectorKeypointsTest test(FeatureDetector::create("SIFT")); + CV_FeatureDetectorKeypointsTest test(xfeatures2d::SIFT::create()); test.safe_run(); } TEST(Features2d_Detector_Keypoints_Star, validation) { - CV_FeatureDetectorKeypointsTest test(Algorithm::create("Feature2D.STAR")); + CV_FeatureDetectorKeypointsTest test(xfeatures2d::StarDetector::create()); test.safe_run(); } diff --git a/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp b/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp index c0d7c531b..46d328205 100644 --- a/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp +++ b/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp @@ -616,7 +616,7 @@ protected: */ TEST(Features2d_RotationInvariance_Detector_SURF, regression) { - DetectorRotationInvarianceTest test(Algorithm::create("Feature2D.SURF"), + DetectorRotationInvarianceTest test(SURF::create(), 0.44f, 0.76f); test.safe_run(); @@ -624,7 +624,7 @@ TEST(Features2d_RotationInvariance_Detector_SURF, regression) TEST(Features2d_RotationInvariance_Detector_SIFT, DISABLED_regression) { - DetectorRotationInvarianceTest test(Algorithm::create("Feature2D.SIFT"), + DetectorRotationInvarianceTest test(SIFT::create(), 0.45f, 0.70f); test.safe_run(); @@ -635,8 +635,8 @@ TEST(Features2d_RotationInvariance_Detector_SIFT, DISABLED_regression) */ TEST(Features2d_RotationInvariance_Descriptor_SURF, regression) { - DescriptorRotationInvarianceTest test(Algorithm::create("Feature2D.SURF"), - Algorithm::create("Feature2D.SURF"), + DescriptorRotationInvarianceTest test(SURF::create(), + SURF::create(), NORM_L1, 0.83f); test.safe_run(); @@ -644,8 +644,8 @@ TEST(Features2d_RotationInvariance_Descriptor_SURF, regression) TEST(Features2d_RotationInvariance_Descriptor_SIFT, regression) { - DescriptorRotationInvarianceTest test(Algorithm::create("Feature2D.SIFT"), - Algorithm::create("Feature2D.SIFT"), + DescriptorRotationInvarianceTest test(SIFT::create(), + SIFT::create(), NORM_L1, 0.98f); test.safe_run(); @@ -656,7 +656,7 @@ TEST(Features2d_RotationInvariance_Descriptor_SIFT, regression) */ TEST(Features2d_ScaleInvariance_Detector_SURF, regression) { - DetectorScaleInvarianceTest test(Algorithm::create("Feature2D.SURF"), + DetectorScaleInvarianceTest test(SURF::create(), 0.64f, 0.84f); test.safe_run(); @@ -664,7 +664,7 @@ TEST(Features2d_ScaleInvariance_Detector_SURF, regression) TEST(Features2d_ScaleInvariance_Detector_SIFT, regression) { - DetectorScaleInvarianceTest test(Algorithm::create("Feature2D.SIFT"), + DetectorScaleInvarianceTest test(SIFT::create(), 0.69f, 0.99f); test.safe_run(); @@ -675,8 +675,8 @@ TEST(Features2d_ScaleInvariance_Detector_SIFT, regression) */ TEST(Features2d_ScaleInvariance_Descriptor_SURF, regression) { - DescriptorScaleInvarianceTest test(Algorithm::create("Feature2D.SURF"), - Algorithm::create("Feature2D.SURF"), + DescriptorScaleInvarianceTest test(SURF::create(), + SURF::create(), NORM_L1, 0.61f); test.safe_run(); @@ -684,8 +684,8 @@ TEST(Features2d_ScaleInvariance_Descriptor_SURF, regression) TEST(Features2d_ScaleInvariance_Descriptor_SIFT, regression) { - DescriptorScaleInvarianceTest test(Algorithm::create("Feature2D.SIFT"), - Algorithm::create("Feature2D.SIFT"), + DescriptorScaleInvarianceTest test(SIFT::create(), + SIFT::create(), NORM_L1, 0.78f); test.safe_run(); @@ -698,11 +698,10 @@ TEST(Features2d_RotationInvariance2_Detector_SURF, regression) line(cross, Point(30, 50), Point(69, 50), Scalar(100), 3); line(cross, Point(50, 30), Point(50, 69), Scalar(100), 3); - SURF surf(8000., 3, 4, true, false); + Ptr surf = SURF::create(8000., 3, 4, true, false); vector keypoints; - - surf(cross, noArray(), keypoints); + surf->detect(cross, keypoints); ASSERT_EQ(keypoints.size(), (vector::size_type) 5); ASSERT_LT( fabs(keypoints[1].response - keypoints[2].response), 1e-6); From 763954f815050f4e94b85870a02b674b16d011b1 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Thu, 16 Oct 2014 20:04:09 +0400 Subject: [PATCH 2/5] fixed xfeatures2d tests --- modules/xfeatures2d/src/stardetector.cpp | 5 +++++ modules/xfeatures2d/test/test_detectors.cpp | 2 +- modules/xfeatures2d/test/test_features2d.cpp | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/xfeatures2d/src/stardetector.cpp b/modules/xfeatures2d/src/stardetector.cpp index 96ed1a326..91df25f67 100644 --- a/modules/xfeatures2d/src/stardetector.cpp +++ b/modules/xfeatures2d/src/stardetector.cpp @@ -483,6 +483,11 @@ StarDetectorImpl::StarDetectorImpl(int _maxSize, int _responseThreshold, void StarDetectorImpl::detect( InputArray _image, std::vector& keypoints, InputArray _mask ) { Mat image = _image.getMat(), mask = _mask.getMat(), grayImage = image; + if( image.empty() ) + { + keypoints.clear(); + return; + } if( image.channels() > 1 ) cvtColor( image, grayImage, COLOR_BGR2GRAY ); Mat responses, sizes; diff --git a/modules/xfeatures2d/test/test_detectors.cpp b/modules/xfeatures2d/test/test_detectors.cpp index 810f59712..72f5539ed 100644 --- a/modules/xfeatures2d/test/test_detectors.cpp +++ b/modules/xfeatures2d/test/test_detectors.cpp @@ -290,7 +290,7 @@ void CV_DetectorsTest::run( int /*start_from*/ ) if (exp.empty()) return; - if (!testDetector(to_test, SURF::create(1536+512+512, 2), exp)) + if (!testDetector(to_test, SURF::create(1536+512+512, 2, 2, true, false), exp)) return; LoadExpected(string(ts->get_data_path()) + "detectors/star.xml", exp); diff --git a/modules/xfeatures2d/test/test_features2d.cpp b/modules/xfeatures2d/test/test_features2d.cpp index ecac5d119..3b14fc31f 100644 --- a/modules/xfeatures2d/test/test_features2d.cpp +++ b/modules/xfeatures2d/test/test_features2d.cpp @@ -1223,12 +1223,12 @@ protected: TEST(Features2d_SIFT_using_mask, regression) { - FeatureDetectorUsingMaskTest test(Algorithm::create("Feature2D.SIFT")); + FeatureDetectorUsingMaskTest test(SIFT::create()); test.safe_run(); } TEST(DISABLED_Features2d_SURF_using_mask, regression) { - FeatureDetectorUsingMaskTest test(Algorithm::create("Feature2D.SURF")); + FeatureDetectorUsingMaskTest test(SURF::create()); test.safe_run(); } From 218358a5d5e4cbfc033cf83bb7addd77a5867ad1 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Thu, 16 Oct 2014 22:00:19 +0400 Subject: [PATCH 3/5] corrected text detection once again to match the new MSER interface --- modules/text/samples/webcam_demo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/text/samples/webcam_demo.cpp b/modules/text/samples/webcam_demo.cpp index 5160e7e65..125ff0e56 100644 --- a/modules/text/samples/webcam_demo.cpp +++ b/modules/text/samples/webcam_demo.cpp @@ -191,8 +191,9 @@ int main(int argc, char* argv[]) { //Extract MSER vector > contours; + vector bboxes; Ptr mser = MSER::create(21,(int)(0.00002*grey.cols*grey.rows),(int)(0.05*grey.cols*grey.rows),1,0.7); - mser->detectAndStore(grey, contours); + mser->detectRegions(grey, contours, bboxes); //Convert the output of MSER to suitable input for the grouping/recognition algorithms if (contours.size() > 0) From 6c63139f7a7b7fd8433539b7cdc86380384021e4 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Fri, 17 Oct 2014 14:18:28 +0400 Subject: [PATCH 4/5] added properties setter/getter to SURF --- .../include/opencv2/xfeatures2d/nonfree.hpp | 1 + modules/xfeatures2d/src/surf.cpp | 34 +++++++++++++++++++ modules/xfeatures2d/src/surf.hpp | 3 ++ 3 files changed, 38 insertions(+) diff --git a/modules/xfeatures2d/include/opencv2/xfeatures2d/nonfree.hpp b/modules/xfeatures2d/include/opencv2/xfeatures2d/nonfree.hpp index 4fc288071..412818abd 100644 --- a/modules/xfeatures2d/include/opencv2/xfeatures2d/nonfree.hpp +++ b/modules/xfeatures2d/include/opencv2/xfeatures2d/nonfree.hpp @@ -74,6 +74,7 @@ typedef SIFT SiftDescriptorExtractor; class CV_EXPORTS_W SURF : public Feature2D { public: + enum { HESSIAN_THRESHOLD = 10000, NOCTAVES=10001, NOCTAVE_LAYERS=10002, EXTENDED=10003, UPRIGHT=10004 }; CV_WRAP static Ptr create(double hessianThreshold=100, int nOctaves = 4, int nOctaveLayers = 3, bool extended = false, bool upright = false); diff --git a/modules/xfeatures2d/src/surf.cpp b/modules/xfeatures2d/src/surf.cpp index 673817e73..00f3a37ca 100644 --- a/modules/xfeatures2d/src/surf.cpp +++ b/modules/xfeatures2d/src/surf.cpp @@ -876,6 +876,40 @@ SURF_Impl::SURF_Impl(double _threshold, int _nOctaves, int _nOctaveLayers, bool nOctaveLayers = _nOctaveLayers; } +void SURF_Impl::set(int prop, double value) +{ + if( prop == HESSIAN_THRESHOLD ) + hessianThreshold = value; + else if( prop == NOCTAVES ) + nOctaves = cvRound(value); + else if( prop == NOCTAVE_LAYERS ) + nOctaveLayers = cvRound(value); + else if( prop == EXTENDED ) + extended = value != 0; + else if( prop == UPRIGHT ) + upright = value != 0; + else + CV_Error(Error::StsBadArg, ""); +} + +double SURF_Impl::get(int prop) const +{ + double value = 0; + if( prop == HESSIAN_THRESHOLD ) + value = hessianThreshold; + else if( prop == NOCTAVES ) + value = nOctaves; + else if( prop == NOCTAVE_LAYERS ) + value = nOctaveLayers; + else if( prop == EXTENDED ) + value = extended; + else if( prop == UPRIGHT ) + value = upright; + else + CV_Error(Error::StsBadArg, ""); + return value; +} + int SURF_Impl::descriptorSize() const { return extended ? 128 : 64; } int SURF_Impl::descriptorType() const { return CV_32F; } int SURF_Impl::defaultNorm() const { return NORM_L2; } diff --git a/modules/xfeatures2d/src/surf.hpp b/modules/xfeatures2d/src/surf.hpp index 59b2e8e26..5a52be345 100644 --- a/modules/xfeatures2d/src/surf.hpp +++ b/modules/xfeatures2d/src/surf.hpp @@ -32,6 +32,9 @@ public: //! returns the descriptor type CV_WRAP int defaultNorm() const; + void set(int, double); + double get(int) const; + //! finds the keypoints and computes their descriptors. // Optionally it can compute descriptors for the user-provided keypoints void detectAndCompute(InputArray img, InputArray mask, From fba1825a1aaba0b08af5a846d1439f964155360c Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Fri, 17 Oct 2014 14:23:09 +0400 Subject: [PATCH 5/5] fixed some more compile errors and test failures --- modules/ccalib/src/ccalib.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ccalib/src/ccalib.cpp b/modules/ccalib/src/ccalib.cpp index 6f2398942..dc7b9d34c 100644 --- a/modules/ccalib/src/ccalib.cpp +++ b/modules/ccalib/src/ccalib.cpp @@ -94,9 +94,9 @@ bool CustomPattern::init(Mat& image, const float pixel_size, OutputArray output) if (!detector) // if no detector chosen, use default { detector = ORB::create(); - detector->set("nFeatures", 2000); - detector->set("scaleFactor", 1.15); - detector->set("nLevels", 30); + detector->set(ORB::NFEATURES, 2000); + detector->set(ORB::SCALE_FACTOR, 1.15); + detector->set(ORB::NLEVELS, 30); } detector->detect(img_roi, keypoints);