diff --git a/modules/features2d/include/opencv2/features2d/features2d.hpp b/modules/features2d/include/opencv2/features2d/features2d.hpp index b0034e9a1..2f3d89763 100644 --- a/modules/features2d/include/opencv2/features2d/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d/features2d.hpp @@ -1451,148 +1451,97 @@ protected: /* * Dynamic Feature Detectors */ + +/** \brief A feature detector parameter adjuster, this is used by the DynamicDetector + * and is a wrapper for FeatureDetector that allow them to be adjusted after a detection + */ +class CV_EXPORTS AdjusterAdapter: public FeatureDetector { +public: + /** pure virtual interface + */ + virtual ~AdjusterAdapter() { + } + /** too few features were detected so, adjust the detector params accordingly + * \param min the minimum number of desired features + * \param n_detected the number previously detected + */ + virtual void tooFew(int min, int n_detected) = 0; + /** too many features were detected so, adjust the detector params accordingly + * \param max the maximum number of desired features + * \param n_detected the number previously detected + */ + virtual void tooMany(int max, int n_detected) = 0; + /** are params maxed out or still valid? + * \return false if the parameters can't be adjusted any more + */ + virtual bool good() const = 0; +}; /** \brief an adaptively adjusting detector that iteratively detects until the desired number * of features are detected. * Beware that this is not thread safe - as the adjustment of parameters breaks the const * of the detection routine... * /TODO Make this const correct and thread safe */ -template -class DynamicDetectorAdaptor: public FeatureDetector { +class CV_EXPORTS DynamicDetector: public FeatureDetector { public: /** \param min_features the minimum desired features * \param max_features the maximum desired number of features * \param max_iters the maximum number of times to try to adjust the feature detector params * for the FastAdjuster this can be high, but with Star or Surf this can get time consuming - * \param a a copy of an Adjuster that will do the detection and parameter adjustment + * \param a an AdjusterAdapter that will do the detection and parameter adjustment */ - DynamicDetectorAdaptor(int min_features, int max_features, - int max_iters, const Adjuster& a = Adjuster()) : - escape_iters_(max_iters), min_features_(min_features), max_features_( - max_features), adjuster_(a) { - } + DynamicDetector(int min_features, int max_features, int max_iters, + const Ptr& a); protected: - virtual void detectImpl(const cv::Mat& image, - std::vector& keypoints, const cv::Mat& mask = - cv::Mat()) const { - //for oscillation testing - bool down = false; - bool up = false; - - //flag for whether the correct threshhold has been reached - bool thresh_good = false; - - //this is bad but adjuster should persist from detection to detection - Adjuster& adjuster = const_cast (adjuster_); - - //break if the desired number hasn't been reached. - int iter_count = escape_iters_; - - do { - keypoints.clear(); - - //the adjuster takes care of calling the detector with updated parameters - adjuster.detect(image, mask, keypoints); - - if (int(keypoints.size()) < min_features_) { - down = true; - adjuster.tooFew(min_features_, keypoints.size()); - } else if (int(keypoints.size()) > max_features_) { - up = true; - adjuster.tooMany(max_features_, keypoints.size()); - } else - thresh_good = true; - } while (--iter_count >= 0 && !(down && up) && !thresh_good - && adjuster.good()); - } - + virtual void detectImpl(const cv::Mat& image, + std::vector& keypoints, const cv::Mat& mask = + cv::Mat()) const; private: int escape_iters_; int min_features_, max_features_; - Adjuster adjuster_; + Ptr adjuster_; }; -struct FastAdjuster { - FastAdjuster() : - thresh_(20) { - } - void detect(const Mat& img, const Mat& mask, std::vector< - KeyPoint>& keypoints) const { - FastFeatureDetector(thresh_, true).detect(img, keypoints, mask); - } - void tooFew(int min, int n_detected) { - //fast is easy to adjust - thresh_--; - } - void tooMany(int max, int n_detected) { - //fast is easy to adjust - thresh_++; - } - - //return whether or not the threshhold is beyond - //a useful point - bool good() const { - return (thresh_ > 1) && (thresh_ < 200); - } +class FastAdjuster: public AdjusterAdapter { +public: + FastAdjuster(int init_thresh = 20, bool nonmax = true); + virtual void tooFew(int min, int n_detected); + virtual void tooMany(int max, int n_detected); + virtual bool good() const; +protected: + virtual void detectImpl(const cv::Mat& image, + std::vector& keypoints, const cv::Mat& mask = + cv::Mat()) const; int thresh_; + bool nonmax_; + }; -struct StarAdjuster { - StarAdjuster() : - thresh_(30) { - } - void detect(const Mat& img, const Mat& mask, std::vector< - KeyPoint>& keypoints) const { - StarFeatureDetector detector_tmp(16, thresh_, 10, 8, 3); - detector_tmp.detect(img, keypoints, mask); - } - void tooFew(int min, int n_detected) { - thresh_ *= 0.9; - if (thresh_ < 1.1) - thresh_ = 1.1; - } - void tooMany(int max, int n_detected) { - thresh_ *= 1.1; - } - - //return whether or not the threshhold is beyond - //a useful point - bool good() const { - return (thresh_ > 2) && (thresh_ < 200); - } +struct StarAdjuster: public AdjusterAdapter { + StarAdjuster(double initial_thresh = 30.0); + virtual void tooFew(int min, int n_detected); + virtual void tooMany(int max, int n_detected); + virtual bool good() const; +protected: + virtual void detectImpl(const cv::Mat& image, + std::vector& keypoints, const cv::Mat& mask = + cv::Mat()) const; double thresh_; }; -struct SurfAdjuster { - SurfAdjuster() : - thresh_(400.0) { - } - void detect(const Mat& img, const Mat& mask, std::vector< - KeyPoint>& keypoints) const { - SurfFeatureDetector detector_tmp(thresh_); - detector_tmp.detect(img, keypoints, mask); - } - void tooFew(int min, int n_detected) { - thresh_ *= 0.9; - if (thresh_ < 1.1) - thresh_ = 1.1; - } - void tooMany(int max, int n_detected) { - thresh_ *= 1.1; - } - - //return whether or not the threshhold is beyond - //a useful point - bool good() const { - return (thresh_ > 2) && (thresh_ < 1000); - } +struct SurfAdjuster: public AdjusterAdapter { + SurfAdjuster(); + virtual void tooFew(int min, int n_detected); + virtual void tooMany(int max, int n_detected); + virtual bool good() const; +protected: + virtual void detectImpl(const cv::Mat& image, + std::vector& keypoints, const cv::Mat& mask = + cv::Mat()) const; double thresh_; }; -typedef DynamicDetectorAdaptor FASTDynamicDetector; -typedef DynamicDetectorAdaptor StarDynamicDetector; -typedef DynamicDetectorAdaptor SurfDynamicDetector; CV_EXPORTS Mat windowedMatchingMask( const vector& keypoints1, const vector& keypoints2, float maxDeltaX, float maxDeltaY ); @@ -1865,22 +1814,15 @@ struct CV_EXPORTS L1 /* * Hamming distance functor - counts the bit differences between two strings - useful for the Brief descriptor - * bit count of A exclusive ored with B + * bit count of A exclusive XOR'ed with B */ struct CV_EXPORTS HammingLUT { typedef unsigned char ValueType; typedef int ResultType; - ResultType operator()( const unsigned char* a, const unsigned char* b, int size ) const - { - ResultType result = 0; - for (int i = 0; i < size; i++) - { - result += byteBitsLookUp(a[i] ^ b[i]); - } - return result; - } + ResultType operator()( const unsigned char* a, const unsigned char* b, int size ) const; + /** \brief given a byte, count the bits using a compile time generated look up table * \param b the byte to count bits. The look up table has an entry for all * values of b, where that entry is the number of bits. @@ -1889,32 +1831,17 @@ struct CV_EXPORTS HammingLUT static unsigned char byteBitsLookUp(unsigned char b); }; -#if __GNUC__ -/// Hamming distance functor -/// @todo Variable-length version, maybe default size=0 and specialize -/// @todo Need to choose C/SSE4 at runtime, but amortize this at matcher level for efficiency... +/// Hamming distance functor, this one will try to use gcc's __builtin_popcountl +/// but will fall back on HammingLUT if not available +/// bit count of A exclusive XOR'ed with B struct CV_EXPORTS Hamming { typedef unsigned char ValueType; typedef int ResultType; - - ResultType operator()(const unsigned char* a, const unsigned char* b, int size) const - { - /// @todo Non-GCC-specific version - ResultType result = 0; - for (int i = 0; i < size; i += sizeof(unsigned long)) - { - unsigned long a2 = *reinterpret_cast (a + i); - unsigned long b2 = *reinterpret_cast (b + i); - result += __builtin_popcountl(a2 ^ b2); - } - return result; - } + ResultType operator()(const unsigned char* a, const unsigned char* b, int size) const; }; -#else -typedef HammingLUT Hamming; -#endif + /****************************************************************************************\ * DMatch * diff --git a/modules/features2d/src/brief.cpp b/modules/features2d/src/brief.cpp index bc2978588..1df20321c 100644 --- a/modules/features2d/src/brief.cpp +++ b/modules/features2d/src/brief.cpp @@ -92,7 +92,30 @@ void pixelTests64(const Mat& sum, const std::vector& keypoints, Mat& d namespace cv { - +ResultType HammingLUT::operator()( const unsigned char* a, const unsigned char* b, int size ) const + { + ResultType result = 0; + for (int i = 0; i < size; i++) + { + result += byteBitsLookUp(a[i] ^ b[i]); + } + return result; + } +ResultType Hamming::operator()(const unsigned char* a, const unsigned char* b, int size) const +{ +#if __GNUC__ + ResultType result = 0; + for (int i = 0; i < size; i += sizeof(unsigned long)) + { + unsigned long a2 = *reinterpret_cast (a + i); + unsigned long b2 = *reinterpret_cast (b + i); + result += __builtin_popcountl(a2 ^ b2); + } + return result; +#else + return HammingLUT()(a,b,size); +#endif +} BriefDescriptorExtractor::BriefDescriptorExtractor(int bytes) : bytes_(bytes), test_fn_(NULL) { diff --git a/modules/features2d/src/detectors.cpp b/modules/features2d/src/detectors.cpp index 259e0aaef..4c4204346 100644 --- a/modules/features2d/src/detectors.cpp +++ b/modules/features2d/src/detectors.cpp @@ -528,7 +528,7 @@ Ptr createFeatureDetector( const string& detectorType ) } else if( !detectorType.compare( "DynamicFAST" ) ) { - fd = new FASTDynamicDetector(400,500,5); + fd = new DynamicDetector(400,500,5,new FastAdjuster()); } else if( !detectorType.compare( "STAR" ) ) { @@ -536,7 +536,7 @@ Ptr createFeatureDetector( const string& detectorType ) } else if( !detectorType.compare( "DynamicSTAR" ) ) { - fd = new StarDynamicDetector(400,500,5); + fd = new DynamicDetector(400,500,5,new StarAdjuster()); } else if( !detectorType.compare( "SIFT" ) ) { @@ -549,7 +549,7 @@ Ptr createFeatureDetector( const string& detectorType ) } else if( !detectorType.compare( "DynamicSURF" ) ) { - fd = new SurfDynamicDetector(400,500,5); + fd =new DynamicDetector(400,500,5,new SurfAdjuster()); } else if( !detectorType.compare( "MSER" ) ) { diff --git a/modules/features2d/src/dynamic.cpp b/modules/features2d/src/dynamic.cpp new file mode 100644 index 000000000..67f64fd96 --- /dev/null +++ b/modules/features2d/src/dynamic.cpp @@ -0,0 +1,149 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// + // + // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + // + // By downloading, copying, installing or using the software you agree to this license. + // If you do not agree to this license, do not download, install, + // copy or use the software. + // + // + // License Agreement + // For Open Source Computer Vision Library + // + // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. + // Copyright (C) 2009-2010, Willow Garage Inc., all rights reserved. + // Third party copyrights are property of their respective owners. + // + // Redistribution and use in source and binary forms, with or without modification, + // are permitted provided that the following conditions are met: + // + // * Redistribution's of source code must retain the above copyright notice, + // this list of conditions and the following disclaimer. + // + // * Redistribution's in binary form must reproduce the above copyright notice, + // this list of conditions and the following disclaimer in the documentation + // and/or other materials provided with the distribution. + // + // * The name of the copyright holders may not be used to endorse or promote products + // derived from this software without specific prior written permission. + // + // This software is provided by the copyright holders and contributors "as is" and + // any express or implied warranties, including, but not limited to, the implied + // warranties of merchantability and fitness for a particular purpose are disclaimed. + // In no event shall the Intel Corporation or contributors be liable for any direct, + // indirect, incidental, special, exemplary, or consequential damages + // (including, but not limited to, procurement of substitute goods or services; + // loss of use, data, or profits; or business interruption) however caused + // and on any theory of liability, whether in contract, strict liability, + // or tort (including negligence or otherwise) arising in any way out of + // the use of this software, even if advised of the possibility of such damage. + // + //M*/ + +#include "precomp.hpp" +namespace cv { +DynamicDetector::DynamicDetector(int min_features, + int max_features, int max_iters, const Ptr& a) : + escape_iters_(max_iters), min_features_(min_features), max_features_( + max_features), adjuster_(a) { +} +void DynamicDetector::detectImpl(const cv::Mat& image, std::vector< + cv::KeyPoint>& keypoints, const cv::Mat& mask) const { + //for oscillation testing + bool down = false; + bool up = false; + + //flag for whether the correct threshhold has been reached + bool thresh_good = false; + + //this is bad but adjuster should persist from detection to detection + AdjusterAdapter& adjuster = const_cast (*adjuster_); + + //break if the desired number hasn't been reached. + int iter_count = escape_iters_; + + do { + keypoints.clear(); + + //the adjuster takes care of calling the detector with updated parameters + adjuster.detect(image, keypoints,mask); + + if (int(keypoints.size()) < min_features_) { + down = true; + adjuster.tooFew(min_features_, keypoints.size()); + } else if (int(keypoints.size()) > max_features_) { + up = true; + adjuster.tooMany(max_features_, keypoints.size()); + } else + thresh_good = true; + } while (--iter_count >= 0 && !(down && up) && !thresh_good + && adjuster.good()); +} + +FastAdjuster::FastAdjuster(int init_thresh, bool nonmax) : + thresh_(init_thresh), nonmax_(nonmax) { +} +void FastAdjuster::detectImpl(const cv::Mat& image, + std::vector& keypoints, const cv::Mat& mask) const { + FastFeatureDetector(thresh_, nonmax_).detect(image, keypoints, mask); +} +void FastAdjuster::tooFew(int min, int n_detected) { + //fast is easy to adjust + thresh_--; +} +void FastAdjuster::tooMany(int max, int n_detected) { + //fast is easy to adjust + thresh_++; +} + +//return whether or not the threshhold is beyond +//a useful point +bool FastAdjuster::good() const { + return (thresh_ > 1) && (thresh_ < 200); +} + +StarAdjuster::StarAdjuster(double initial_thresh) : + thresh_(initial_thresh) { +} +void StarAdjuster::detectImpl(const cv::Mat& image, + std::vector& keypoints, const cv::Mat& mask) const { + StarFeatureDetector detector_tmp(16, thresh_, 10, 8, 3); + detector_tmp.detect(image, keypoints, mask); +} +void StarAdjuster::tooFew(int min, int n_detected) { + thresh_ *= 0.9; + if (thresh_ < 1.1) + thresh_ = 1.1; +} +void StarAdjuster::tooMany(int max, int n_detected) { + thresh_ *= 1.1; +} + +bool StarAdjuster::good() const { + return (thresh_ > 2) && (thresh_ < 200); +} + +SurfAdjuster::SurfAdjuster() : + thresh_(400.0) { +} +void SurfAdjuster::detectImpl(const cv::Mat& image, + std::vector& keypoints, const cv::Mat& mask) const { + SurfFeatureDetector detector_tmp(thresh_); + detector_tmp.detect(image, keypoints, mask); +} +void SurfAdjuster::tooFew(int min, int n_detected) { + thresh_ *= 0.9; + if (thresh_ < 1.1) + thresh_ = 1.1; +} +void SurfAdjuster::tooMany(int max, int n_detected) { + thresh_ *= 1.1; +} + +//return whether or not the threshhold is beyond +//a useful point +bool SurfAdjuster::good() const { + return (thresh_ > 2) && (thresh_ < 1000); +} + +}