From 21f42115a8da708a6a196b136c3d0fcd8a4fc7b7 Mon Sep 17 00:00:00 2001
From: Lukas <mr.bobukas@gmail.com>
Date: Fri, 31 Aug 2012 13:59:46 +0200
Subject: [PATCH] Partial patch for Bug #2325 Fixing python bindings for surf
 by splitting the SURF class into two classes:
 SurfFeatureDetector SurfDescriptorExtractor. Additionally,
 SURF now computes the integral image only for one time.

---
 .../nonfree/include/opencv2/nonfree/features2d.hpp |  101 ++++++++++-----
 modules/nonfree/src/nonfree_init.cpp               |   28 ++++-
 modules/nonfree/src/surf.cpp                       |  133 ++++++++++++--------
 3 files changed, 168 insertions(+), 94 deletions(-)

diff --git a/modules/nonfree/include/opencv2/nonfree/features2d.hpp b/modules/nonfree/include/opencv2/nonfree/features2d.hpp
index 4fe27b1..3370e4c 100644
--- a/modules/nonfree/include/opencv2/nonfree/features2d.hpp
+++ b/modules/nonfree/include/opencv2/nonfree/features2d.hpp
@@ -52,7 +52,7 @@ namespace cv
 
 /*!
  SIFT implementation.
- 
+
  The class implements SIFT algorithm by D. Lowe.
 */
 class CV_EXPORTS_W SIFT : public Feature2D
@@ -64,10 +64,10 @@ public:
 
     //! returns the descriptor size in floats (128)
     CV_WRAP int descriptorSize() const;
-    
+
     //! returns the descriptor type
     CV_WRAP int descriptorType() const;
-    
+
     //! finds the keypoints using SIFT algorithm
     void operator()(InputArray img, InputArray mask,
                     vector<KeyPoint>& keypoints) const;
@@ -77,9 +77,9 @@ public:
                     vector<KeyPoint>& keypoints,
                     OutputArray descriptors,
                     bool useProvidedKeypoints=false) const;
-    
+
     AlgorithmInfo* info() const;
-    
+
     void buildGaussianPyramid( const Mat& base, vector<Mat>& pyr, int nOctaves ) const;
     void buildDoGPyramid( const vector<Mat>& pyr, vector<Mat>& dogpyr ) const;
     void findScaleSpaceExtrema( const vector<Mat>& gauss_pyr, const vector<Mat>& dog_pyr,
@@ -88,7 +88,7 @@ public:
 protected:
     void detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const;
     void computeImpl( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors ) const;
-    
+
     CV_PROP_RW int nfeatures;
     CV_PROP_RW int nOctaveLayers;
     CV_PROP_RW double contrastThreshold;
@@ -98,53 +98,88 @@ protected:
 
 typedef SIFT SiftFeatureDetector;
 typedef SIFT SiftDescriptorExtractor;
-    
+
 /*!
  SURF implementation.
- 
+
  The class implements SURF algorithm by H. Bay et al.
  */
-class CV_EXPORTS_W SURF : public Feature2D
+
+class CV_EXPORTS_W SurfFeatureDetector : public FeatureDetector
 {
 public:
     //! the default constructor
-    CV_WRAP SURF();
+    CV_WRAP SurfFeatureDetector();
+
     //! 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);
+    explicit CV_WRAP SurfFeatureDetector(double hessianThreshold,
+                      int nOctaves=4, int nOctaveLayers=2);
 
-    //! returns the descriptor size in float's (64 or 128)
-    CV_WRAP int descriptorSize() const;
-    
-    //! returns the descriptor type
-    CV_WRAP int descriptorType() const;
-    
     //! finds the keypoints using fast hessian detector used in SURF
     void operator()(InputArray img, InputArray mask,
-                    CV_OUT vector<KeyPoint>& 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 vector<KeyPoint>& keypoints,
-                    OutputArray descriptors,
-                    bool useProvidedKeypoints=false) const;
-    
+            CV_OUT vector<KeyPoint>& keypoints) const;
+
     AlgorithmInfo* info() const;
-    
+
     CV_PROP_RW double hessianThreshold;
     CV_PROP_RW int nOctaves;
     CV_PROP_RW int nOctaveLayers;
+
+protected:
+    void detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat()) const;
+    void detectImplCached( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask, Mat& integralImage) const;
+
+};
+
+
+class CV_EXPORTS_W SurfDescriptorExtractor : public DescriptorExtractor
+{
+public:
+    //! the default constructor
+    CV_WRAP SurfDescriptorExtractor();
+
+    //! the full constructor taking all the necessary parameters
+    explicit CV_WRAP SurfDescriptorExtractor(bool extended, 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;
+
+    AlgorithmInfo* info() const;
+
     CV_PROP_RW bool extended;
     CV_PROP_RW bool upright;
-    
+
 protected:
-    
-    void detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const;
     void computeImpl( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors ) const;
+    void computeImplCached( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors, Mat& integralImage) const;
+};
+
+class CV_EXPORTS_W SURF : public SurfDescriptorExtractor, SurfFeatureDetector
+{
+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);
+
+    //! 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 vector<KeyPoint>& keypoints,
+            OutputArray descriptors,
+            bool useProvidedKeypoints=false) const;
+
+    //! finds the keypoints using fast hessian detector used in SURF
+    void operator()(InputArray img, InputArray mask,
+            CV_OUT vector<KeyPoint>& keypoints) const;
+
+    AlgorithmInfo* info() const;
+
 };
-    
-typedef SURF SurfFeatureDetector;
-typedef SURF SurfDescriptorExtractor;
 
 } /* namespace cv */
 
diff --git a/modules/nonfree/src/nonfree_init.cpp b/modules/nonfree/src/nonfree_init.cpp
index 239e857..cf86df6 100644
--- a/modules/nonfree/src/nonfree_init.cpp
+++ b/modules/nonfree/src/nonfree_init.cpp
@@ -54,22 +54,38 @@ CV_INIT_ALGORITHM(SURF, "Feature2D.SURF",
                   obj.info()->addParam(obj, "extended", obj.extended);
                   obj.info()->addParam(obj, "upright", obj.upright));
 
+CV_INIT_ALGORITHM(SurfFeatureDetector, "Feature2D.SurfDetector",
+                  obj.info()->addParam(obj, "hessianThreshold", obj.hessianThreshold);
+                  obj.info()->addParam(obj, "nOctaves", obj.nOctaves);
+                  obj.info()->addParam(obj, "nOctaveLayers", obj.nOctaveLayers));
+
+CV_INIT_ALGORITHM(SurfDescriptorExtractor, "Feature2D.SurfExtractor",
+                  obj.info()->addParam(obj, "extended", obj.extended);
+                  obj.info()->addParam(obj, "upright", obj.upright));
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-CV_INIT_ALGORITHM(SIFT, "Feature2D.SIFT",    
+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_nonfree(void)
 {
-    Ptr<Algorithm> sift = createSIFT(), surf = createSURF();
-    return sift->info() != 0 && surf->info() != 0;
+    Ptr<Algorithm>
+            sift = createSIFT(),
+            surf = createSURF(),
+            surfDetector = createSurfFeatureDetector(),
+            surfExtractor = createSurfFeatureDetector();
+    return sift->info() != 0
+            && surf->info() != 0
+            && surfDetector->info() != 0
+            && surfExtractor->info() != 0
+            ;
 }
 
 }
-    
\ No newline at end of file
diff --git a/modules/nonfree/src/surf.cpp b/modules/nonfree/src/surf.cpp
index 8c601a8..c7f3653 100644
--- a/modules/nonfree/src/surf.cpp
+++ b/modules/nonfree/src/surf.cpp
@@ -854,8 +854,8 @@ 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 SurfDescriptorExtractor::descriptorSize() const { return extended ? 128 : 64; }
+int SurfDescriptorExtractor::descriptorType() const { return CV_32F; }
 
 void SURF::operator()(InputArray imgarg, InputArray maskarg,
                       CV_OUT vector<KeyPoint>& keypoints) const
@@ -868,8 +868,44 @@ void SURF::operator()(InputArray _img, InputArray _mask,
                       OutputArray _descriptors,
                       bool useProvidedKeypoints) const
 {
-    Mat img = _img.getMat(), mask = _mask.getMat(), mask1, sum, msum;
-    bool doDescriptors = _descriptors.needed();
+    Mat integralImage;
+    Mat img = _img.getMat();
+
+    // Compute keypoints only if we are not asked for evaluating the descriptors are some given locations:
+    if( !useProvidedKeypoints )
+    {
+        this->detectImplCached(img, keypoints, _mask.getMat(), integralImage);
+    }
+
+    this->computeImplCached(img, keypoints, _descriptors.getMatRef(), integralImage);
+
+
+}
+
+SurfFeatureDetector::SurfFeatureDetector()
+{
+    hessianThreshold = 100;
+    nOctaves = 4;
+    nOctaveLayers = 2;
+}
+
+SurfFeatureDetector::SurfFeatureDetector(double _threshold, int _nOctaves, int _nOctaveLayers)
+{
+    hessianThreshold = _threshold;
+    nOctaves = _nOctaves;
+    nOctaveLayers = _nOctaveLayers;
+}
+
+void SurfFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask) const
+{
+    Mat m;
+    this->detectImplCached(image, keypoints, mask, m);
+}
+
+void SurfFeatureDetector::detectImplCached( const Mat& img, vector<KeyPoint>& keypoints, const Mat& mask, Mat& integralImg) const
+{
+    Mat mask1, msum;
+
 
     CV_Assert(!img.empty() && img.depth() == CV_8U);
     if( img.channels() > 1 )
@@ -880,45 +916,56 @@ void SURF::operator()(InputArray _img, InputArray _mask,
     CV_Assert(nOctaves > 0);
     CV_Assert(nOctaveLayers > 0);
 
-    integral(img, sum, CV_32S);
+    integral(img, integralImg, CV_32S);
 
-    // Compute keypoints only if we are not asked for evaluating the descriptors are some given locations:
-    if( !useProvidedKeypoints )
+
+    if( !mask.empty() )
     {
-        if( !mask.empty() )
-        {
-            cv::min(mask, 1, mask1);
-            integral(mask1, msum, CV_32S);
-        }
-        fastHessianDetector( sum, msum, keypoints, nOctaves, nOctaveLayers, (float)hessianThreshold );
+        cv::min(mask, 1, mask1);
+        integral(mask1, msum, CV_32S);
     }
+    fastHessianDetector( integralImg, msum, keypoints, nOctaves, nOctaveLayers, (float)hessianThreshold );
+}
+
+
+SurfDescriptorExtractor::SurfDescriptorExtractor()
+{
+    extended = true;
+    upright = false;
+}
+
+SurfDescriptorExtractor::SurfDescriptorExtractor(bool _extended, bool _upright)
+{
+    extended = _extended;
+    upright = _upright;
+}
+
+void SurfDescriptorExtractor::computeImpl( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors ) const
+{
+    Mat m;
+    this->computeImplCached(image, keypoints, descriptors, m);
+}
+
+void SurfDescriptorExtractor::computeImplCached( const Mat& img, vector<KeyPoint>& keypoints, Mat& descriptors, Mat& integralImg) const
+{
+    CV_Assert(!img.empty() && img.depth() == CV_8U);
+    if( img.channels() > 1 )
+        cvtColor(img, img, COLOR_BGR2GRAY);
+
+    if (integralImg.empty())
+        integral(img, integralImg, CV_32S);
 
     int i, j, N = (int)keypoints.size();
     if( N > 0 )
     {
-        Mat descriptors;
-        bool _1d = false;
         int dcols = extended ? 128 : 64;
         size_t dsize = dcols*sizeof(float);
 
-        if( doDescriptors )
-        {
-            _1d = _descriptors.kind() == _InputArray::STD_VECTOR && _descriptors.type() == CV_32F;
-            if( _1d )
-            {
-                _descriptors.create(N*dcols, 1, CV_32F);
-                descriptors = _descriptors.getMat().reshape(1, N);
-            }
-            else
-            {
-                _descriptors.create(N, dcols, CV_32F);
-                descriptors = _descriptors.getMat();
-            }
-        }
+        descriptors.create(N, dcols, CV_32F);
 
         // we call SURFInvoker in any case, even if we do not need descriptors,
         // since it computes orientation of each feature.
-        parallel_for(BlockedRange(0, N), SURFInvoker(img, sum, keypoints, descriptors, extended, upright) );
+        parallel_for(BlockedRange(0, N), SURFInvoker(img, integralImg, keypoints, descriptors, extended, upright) );
 
         // remove keypoints that were marked for deletion
         for( i = j = 0; i < N; i++ )
@@ -928,36 +975,12 @@ void SURF::operator()(InputArray _img, InputArray _mask,
                 if( i > j )
                 {
                     keypoints[j] = keypoints[i];
-                    if( doDescriptors )
-                        memcpy( descriptors.ptr(j), descriptors.ptr(i), dsize);
+                    memcpy( descriptors.ptr(j), descriptors.ptr(i), dsize);
                 }
                 j++;
             }
         }
-        if( N > j )
-        {
-            N = j;
-            keypoints.resize(N);
-            if( doDescriptors )
-            {
-                Mat d = descriptors.rowRange(0, N);
-                if( _1d )
-                    d = d.reshape(1, N*dcols);
-                d.copyTo(_descriptors);
-            }
-        }
     }
 }
 
-
-void SURF::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask) const
-{
-    (*this)(image, mask, keypoints, noArray(), false);
-}
-
-void SURF::computeImpl( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors) const
-{
-    (*this)(image, Mat(), keypoints, descriptors, true);
-}
-
 }
-- 
1.7.6.1

