refactoring dynamic detectors
authorEthan Rublee <no@email>
Tue, 23 Nov 2010 22:26:36 +0000 (22:26 +0000)
committerEthan Rublee <no@email>
Tue, 23 Nov 2010 22:26:36 +0000 (22:26 +0000)
modules/features2d/include/opencv2/features2d/features2d.hpp
modules/features2d/src/brief.cpp
modules/features2d/src/detectors.cpp
modules/features2d/src/dynamic.cpp [new file with mode: 0644]

index b0034e9..2f3d897 100644 (file)
@@ -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<typename Adjuster>
-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<AdjusterAdapter>& a);
 protected:
-    virtual void detectImpl(const cv::Mat& image,
-            std::vector<cv::KeyPoint>& 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&> (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<cv::KeyPoint>& keypoints, const cv::Mat& mask =
+                                       cv::Mat()) const;
 private:
        int escape_iters_;
        int min_features_, max_features_;
-       Adjuster adjuster_;
+       Ptr<AdjusterAdapter> 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<cv::KeyPoint>& 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<cv::KeyPoint>& 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<cv::KeyPoint>& keypoints, const cv::Mat& mask =
+                                       cv::Mat()) const;
        double thresh_;
 };
 
-typedef DynamicDetectorAdaptor<FastAdjuster> FASTDynamicDetector;
-typedef DynamicDetectorAdaptor<StarAdjuster> StarDynamicDetector;
-typedef DynamicDetectorAdaptor<SurfAdjuster> SurfDynamicDetector;
 
 CV_EXPORTS Mat windowedMatchingMask( const vector<KeyPoint>& keypoints1, const vector<KeyPoint>& 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<const unsigned long*> (a + i);
-            unsigned long b2 = *reinterpret_cast<const unsigned long*> (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                                            *
index bc29785..1df2032 100644 (file)
@@ -92,7 +92,30 @@ void pixelTests64(const Mat& sum, const std::vector<KeyPoint>& 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<const unsigned long*> (a + i);
+        unsigned long b2 = *reinterpret_cast<const unsigned long*> (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)
 {
index 259e0aa..4c42043 100644 (file)
@@ -528,7 +528,7 @@ Ptr<FeatureDetector> 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<FeatureDetector> 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<FeatureDetector> 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 (file)
index 0000000..67f64fd
--- /dev/null
@@ -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<AdjusterAdapter>& 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<AdjusterAdapter&> (*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<cv::KeyPoint>& 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<cv::KeyPoint>& 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<cv::KeyPoint>& 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);
+}
+
+}