OpenCV with the refactored features2d compiles! contrib is broken for now; the tests...
authorVadim Pisarevsky <vadim.pisarevsky@gmail.com>
Wed, 15 Oct 2014 18:49:17 +0000 (22:49 +0400)
committerVadim Pisarevsky <vadim.pisarevsky@gmail.com>
Wed, 15 Oct 2014 18:49:17 +0000 (22:49 +0400)
27 files changed:
modules/features2d/include/opencv2/features2d.hpp
modules/features2d/perf/opencl/perf_orb.cpp
modules/features2d/perf/perf_orb.cpp
modules/features2d/src/akaze.cpp
modules/features2d/src/blobdetector.cpp
modules/features2d/src/brisk.cpp
modules/features2d/src/feature2d.cpp [new file with mode: 0644]
modules/features2d/src/features2d_init.cpp [deleted file]
modules/features2d/src/gftt.cpp [moved from modules/features2d/src/detectors.cpp with 100% similarity]
modules/features2d/src/kaze.cpp
modules/features2d/src/kaze/AKAZEConfig.h
modules/features2d/src/kaze/AKAZEFeatures.cpp
modules/features2d/src/kaze/AKAZEFeatures.h
modules/features2d/src/kaze/KAZEFeatures.cpp
modules/features2d/src/kaze/KAZEFeatures.h
modules/features2d/src/kaze/TEvolution.h
modules/features2d/src/kaze/nldiffusion_functions.cpp
modules/features2d/src/kaze/nldiffusion_functions.h
modules/features2d/src/mser.cpp
modules/features2d/src/orb.cpp
modules/features2d/test/test_descriptors_regression.cpp
modules/features2d/test/test_detectors_regression.cpp
modules/features2d/test/test_keypoints.cpp
modules/features2d/test/test_mser.cpp
modules/features2d/test/test_orb.cpp
modules/stitching/src/matchers.cpp
modules/videostab/src/global_motion.cpp

index 4262f1c..e922291 100644 (file)
@@ -110,6 +110,10 @@ public:
                                  CV_OUT std::vector<KeyPoint>& keypoints,
                                  InputArray mask=noArray() );
 
+    virtual void detect( InputArrayOfArrays images,
+                         std::vector<std::vector<KeyPoint> >& keypoints,
+                         InputArrayOfArrays masks=noArray() );
+
     /*
      * Compute the descriptors for a set of keypoints in an image.
      * image        The image.
@@ -120,6 +124,10 @@ public:
                                   CV_OUT CV_IN_OUT std::vector<KeyPoint>& keypoints,
                                   OutputArray descriptors );
 
+    virtual void compute( InputArrayOfArrays images,
+                          std::vector<std::vector<KeyPoint> >& keypoints,
+                          OutputArrayOfArrays descriptors );
+
     /* Detects keypoints and computes the descriptors */
     CV_WRAP virtual void detectAndCompute( InputArray image, InputArray mask,
                                            CV_OUT std::vector<KeyPoint>& keypoints,
@@ -146,7 +154,7 @@ public:
     CV_WRAP static Ptr<BRISK> create(int thresh=30, int octaves=3, float patternScale=1.0f);
     // custom setup
     CV_WRAP static Ptr<BRISK> create(const std::vector<float> &radiusList, const std::vector<int> &numberList,
-        float dMax=5.85f, float dMin=8.2f, const std::vector<int> indexChange=std::vector<int>());
+        float dMax=5.85f, float dMin=8.2f, const std::vector<int>& indexChange=std::vector<int>());
 };
 
 /*!
@@ -174,6 +182,13 @@ public:
 class CV_EXPORTS_W MSER : public Feature2D
 {
 public:
+    enum
+    {
+        DELTA=10000, MIN_AREA=10001, MAX_AREA=10002, PASS2_ONLY=10003,
+        MAX_EVOLUTION=10004, AREA_THRESHOLD=10005,
+        MIN_MARGIN=10006, EDGE_BLUR_SIZE=10007
+    };
+
     //! the full constructor
     CV_WRAP static Ptr<MSER> create( int _delta=5, int _min_area=60, int _max_area=14400,
           double _max_variation=0.25, double _min_diversity=.2,
@@ -181,7 +196,7 @@ public:
           double _min_margin=0.003, int _edge_blur_size=5 );
 
     CV_WRAP virtual int detectAndLabel( InputArray image, OutputArray label,
-                                        OutputArray stats=noArray() ) const = 0;
+                                        OutputArray stats=noArray() ) = 0;
 };
 
 //! detects corners using FAST algorithm by E. Rosten
@@ -199,13 +214,16 @@ public:
         TYPE_5_8 = 0, TYPE_7_12 = 1, TYPE_9_16 = 2
     };
 
-    CV_WRAP static Ptr<FastFeatureDetector> create( int threshold=10, bool nonmaxSuppression=true, int type=TYPE_9_16 );
+    CV_WRAP static Ptr<FastFeatureDetector> create( int threshold=10,
+                                                    bool nonmaxSuppression=true,
+                                                    int type=FastFeatureDetector::TYPE_9_16 );
 };
 
 
 class CV_EXPORTS_W GFTTDetector : public Feature2D
 {
 public:
+    enum { USE_HARRIS_DETECTOR=10000 };
     CV_WRAP static Ptr<GFTTDetector> create( int maxCorners=1000, double qualityLevel=0.01, double minDistance=1,
                                              int blockSize=3, bool useHarrisDetector=false, double k=0.04 );
 };
@@ -282,7 +300,7 @@ public:
         DESCRIPTOR_MLDB = 5
     };
 
-    CV_WRAP static Ptr<AKAZE> create(int descriptor_type=DESCRIPTOR_MLDB,
+    CV_WRAP static Ptr<AKAZE> create(int descriptor_type=AKAZE::DESCRIPTOR_MLDB,
                                      int descriptor_size = 0, int descriptor_channels = 3,
                                      float threshold = 0.001f, int octaves = 4,
                                      int sublevels = 4, int diffusivity = KAZE::DIFF_PM_G2);
@@ -535,8 +553,6 @@ public:
     virtual bool isMaskSupported() const { return true; }
 
     virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const;
-
-    AlgorithmInfo* info() const;
 protected:
     virtual void knnMatchImpl( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, int k,
         InputArrayOfArrays masks=noArray(), bool compactResult=false );
@@ -569,8 +585,6 @@ public:
     virtual bool isMaskSupported() const;
 
     virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const;
-
-    AlgorithmInfo* info() const;
 protected:
     static void convertToDMatches( const DescriptorCollection& descriptors,
                                    const Mat& indices, const Mat& distances,
index c551dee..e9aadf5 100644 (file)
@@ -22,10 +22,10 @@ OCL_PERF_TEST_P(ORBFixture, ORB_Detect, ORB_IMAGES)
     mframe.copyTo(frame);
 
     declare.in(frame);
-    ORB detector(1500, 1.3f, 1);
+    Ptr<ORB> detector = ORB::create(1500, 1.3f, 1);
     vector<KeyPoint> points;
 
-    OCL_TEST_CYCLE() detector(frame, mask, points);
+    OCL_TEST_CYCLE() detector->detect(frame, points, mask);
 
     std::sort(points.begin(), points.end(), comparators::KeypointGreater());
     SANITY_CHECK_KEYPOINTS(points, 1e-5);
@@ -44,14 +44,14 @@ OCL_PERF_TEST_P(ORBFixture, ORB_Extract, ORB_IMAGES)
 
     declare.in(frame);
 
-    ORB detector(1500, 1.3f, 1);
+    Ptr<ORB> detector = ORB::create(1500, 1.3f, 1);
     vector<KeyPoint> points;
-    detector(frame, mask, points);
+    detector->detect(frame, points, mask);
     std::sort(points.begin(), points.end(), comparators::KeypointGreater());
 
     UMat descriptors;
 
-    OCL_TEST_CYCLE() detector(frame, mask, points, descriptors, true);
+    OCL_TEST_CYCLE() detector->compute(frame, points, descriptors);
 
     SANITY_CHECK(descriptors);
 }
@@ -68,12 +68,12 @@ OCL_PERF_TEST_P(ORBFixture, ORB_Full, ORB_IMAGES)
     mframe.copyTo(frame);
 
     declare.in(frame);
-    ORB detector(1500, 1.3f, 1);
+    Ptr<ORB> detector = ORB::create(1500, 1.3f, 1);
 
     vector<KeyPoint> points;
     UMat descriptors;
 
-    OCL_TEST_CYCLE() detector(frame, mask, points, descriptors, false);
+    OCL_TEST_CYCLE() detector->detectAndCompute(frame, mask, points, descriptors, false);
 
     ::perf::sort(points, descriptors);
     SANITY_CHECK_KEYPOINTS(points, 1e-5);
index 1c181c4..96cfc3e 100644 (file)
@@ -22,10 +22,10 @@ PERF_TEST_P(orb, detect, testing::Values(ORB_IMAGES))
 
     Mat mask;
     declare.in(frame);
-    ORB detector(1500, 1.3f, 1);
+    Ptr<ORB> detector = ORB::create(1500, 1.3f, 1);
     vector<KeyPoint> points;
 
-    TEST_CYCLE() detector(frame, mask, points);
+    TEST_CYCLE() detector->detect(frame, points, mask);
 
     sort(points.begin(), points.end(), comparators::KeypointGreater());
     SANITY_CHECK_KEYPOINTS(points, 1e-5);
@@ -42,14 +42,14 @@ PERF_TEST_P(orb, extract, testing::Values(ORB_IMAGES))
     Mat mask;
     declare.in(frame);
 
-    ORB detector(1500, 1.3f, 1);
+    Ptr<ORB> detector = ORB::create(1500, 1.3f, 1);
     vector<KeyPoint> points;
-    detector(frame, mask, points);
+    detector->detect(frame, points, mask);
     sort(points.begin(), points.end(), comparators::KeypointGreater());
 
     Mat descriptors;
 
-    TEST_CYCLE() detector(frame, mask, points, descriptors, true);
+    TEST_CYCLE() detector->compute(frame, points, descriptors);
 
     SANITY_CHECK(descriptors);
 }
@@ -64,12 +64,12 @@ PERF_TEST_P(orb, full, testing::Values(ORB_IMAGES))
 
     Mat mask;
     declare.in(frame);
-    ORB detector(1500, 1.3f, 1);
+    Ptr<ORB> detector = ORB::create(1500, 1.3f, 1);
 
     vector<KeyPoint> points;
     Mat descriptors;
 
-    TEST_CYCLE() detector(frame, mask, points, descriptors, false);
+    TEST_CYCLE() detector->detectAndCompute(frame, mask, points, descriptors, false);
 
     perf::sort(points, descriptors);
     SANITY_CHECK_KEYPOINTS(points, 1e-5);
index d875b46..b72b940 100644 (file)
@@ -52,22 +52,15 @@ http://www.robesafe.com/personal/pablo.alcantarilla/papers/Alcantarilla13bmvc.pd
 #include "kaze/AKAZEFeatures.h"
 
 #include <iostream>
-using namespace std;
 
 namespace cv
 {
-    AKAZE::AKAZE()
-        : descriptor(DESCRIPTOR_MLDB)
-        , descriptor_channels(3)
-        , descriptor_size(0)
-        , threshold(0.001f)
-        , octaves(4)
-        , sublevels(4)
-        , diffusivity(DIFF_PM_G2)
-    {
-    }
+    using namespace std;
 
-    AKAZE::AKAZE(int _descriptor_type, int _descriptor_size, int _descriptor_channels,
+    class AKAZE_Impl : public AKAZE
+    {
+    public:
+        AKAZE_Impl(int _descriptor_type, int _descriptor_size, int _descriptor_channels,
                  float _threshold, int _octaves, int _sublevels, int _diffusivity)
         : descriptor(_descriptor_type)
         , descriptor_channels(_descriptor_channels)
@@ -76,181 +69,139 @@ namespace cv
         , octaves(_octaves)
         , sublevels(_sublevels)
         , diffusivity(_diffusivity)
-    {
-
-    }
-
-    AKAZE::~AKAZE()
-    {
-
-    }
-
-    // returns the descriptor size in bytes
-    int AKAZE::descriptorSize() const
-    {
-        switch (descriptor)
         {
-        case cv::DESCRIPTOR_KAZE:
-        case cv::DESCRIPTOR_KAZE_UPRIGHT:
-            return 64;
+        }
 
-        case cv::DESCRIPTOR_MLDB:
-        case cv::DESCRIPTOR_MLDB_UPRIGHT:
-            // We use the full length binary descriptor -> 486 bits
-            if (descriptor_size == 0)
-            {
-                int t = (6 + 36 + 120) * descriptor_channels;
-                return (int)ceil(t / 8.);
-            }
-            else
-            {
-                // We use the random bit selection length binary descriptor
-                return (int)ceil(descriptor_size / 8.);
-            }
+        virtual ~AKAZE_Impl()
+        {
 
-        default:
-            return -1;
         }
-    }
 
-    // returns the descriptor type
-    int AKAZE::descriptorType() const
-    {
-        switch (descriptor)
+        // returns the descriptor size in bytes
+        int descriptorSize() const
         {
-        case cv::DESCRIPTOR_KAZE:
-        case cv::DESCRIPTOR_KAZE_UPRIGHT:
-                return CV_32F;
-
-        case cv::DESCRIPTOR_MLDB:
-        case cv::DESCRIPTOR_MLDB_UPRIGHT:
-                return CV_8U;
+            switch (descriptor)
+            {
+            case DESCRIPTOR_KAZE:
+            case DESCRIPTOR_KAZE_UPRIGHT:
+                return 64;
+
+            case DESCRIPTOR_MLDB:
+            case DESCRIPTOR_MLDB_UPRIGHT:
+                // We use the full length binary descriptor -> 486 bits
+                if (descriptor_size == 0)
+                {
+                    int t = (6 + 36 + 120) * descriptor_channels;
+                    return (int)ceil(t / 8.);
+                }
+                else
+                {
+                    // We use the random bit selection length binary descriptor
+                    return (int)ceil(descriptor_size / 8.);
+                }
 
             default:
                 return -1;
+            }
         }
-    }
 
-    // returns the default norm type
-    int AKAZE::defaultNorm() const
-    {
-        switch (descriptor)
+        // returns the descriptor type
+        int descriptorType() const
         {
-        case cv::DESCRIPTOR_KAZE:
-        case cv::DESCRIPTOR_KAZE_UPRIGHT:
-            return cv::NORM_L2;
+            switch (descriptor)
+            {
+            case DESCRIPTOR_KAZE:
+            case DESCRIPTOR_KAZE_UPRIGHT:
+                    return CV_32F;
 
-        case cv::DESCRIPTOR_MLDB:
-        case cv::DESCRIPTOR_MLDB_UPRIGHT:
-            return cv::NORM_HAMMING;
+            case DESCRIPTOR_MLDB:
+            case DESCRIPTOR_MLDB_UPRIGHT:
+                    return CV_8U;
 
-        default:
-            return -1;
+                default:
+                    return -1;
+            }
         }
-    }
-
 
-    void AKAZE::operator()(InputArray image, InputArray mask,
-        std::vector<KeyPoint>& keypoints,
-        OutputArray descriptors,
-        bool useProvidedKeypoints) const
-    {
-        cv::Mat img = image.getMat();
-        if (img.type() != CV_8UC1)
-            cvtColor(image, img, COLOR_BGR2GRAY);
-
-        Mat img1_32;
-        img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0);
-
-        cv::Mat& desc = descriptors.getMatRef();
-
-        AKAZEOptions options;
-        options.descriptor = descriptor;
-        options.descriptor_channels = descriptor_channels;
-        options.descriptor_size = descriptor_size;
-        options.img_width = img.cols;
-        options.img_height = img.rows;
-        options.dthreshold = threshold;
-        options.omax = octaves;
-        options.nsublevels = sublevels;
-        options.diffusivity = diffusivity;
+        // returns the default norm type
+        int defaultNorm() const
+        {
+            switch (descriptor)
+            {
+            case DESCRIPTOR_KAZE:
+            case DESCRIPTOR_KAZE_UPRIGHT:
+                return NORM_L2;
 
-        AKAZEFeatures impl(options);
-        impl.Create_Nonlinear_Scale_Space(img1_32);
+            case DESCRIPTOR_MLDB:
+            case DESCRIPTOR_MLDB_UPRIGHT:
+                return NORM_HAMMING;
 
-        if (!useProvidedKeypoints)
-        {
-            impl.Feature_Detection(keypoints);
+            default:
+                return -1;
+            }
         }
 
-        if (!mask.empty())
+        void detectAndCompute(InputArray image, InputArray mask,
+                              std::vector<KeyPoint>& keypoints,
+                              OutputArray descriptors,
+                              bool useProvidedKeypoints)
         {
-            cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat());
-        }
-
-        impl.Compute_Descriptors(keypoints, desc);
-
-        CV_Assert((!desc.rows || desc.cols == descriptorSize()));
-        CV_Assert((!desc.rows || (desc.type() == descriptorType())));
-    }
-
-    void AKAZE::detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const
-    {
-        cv::Mat img = image.getMat();
-        if (img.type() != CV_8UC1)
-            cvtColor(image, img, COLOR_BGR2GRAY);
-
-        Mat img1_32;
-        img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0);
+            Mat img = image.getMat();
+            if (img.type() != CV_8UC1)
+                cvtColor(image, img, COLOR_BGR2GRAY);
+
+            Mat img1_32;
+            img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0);
+
+            AKAZEOptions options;
+            options.descriptor = descriptor;
+            options.descriptor_channels = descriptor_channels;
+            options.descriptor_size = descriptor_size;
+            options.img_width = img.cols;
+            options.img_height = img.rows;
+            options.dthreshold = threshold;
+            options.omax = octaves;
+            options.nsublevels = sublevels;
+            options.diffusivity = diffusivity;
+
+            AKAZEFeatures impl(options);
+            impl.Create_Nonlinear_Scale_Space(img1_32);
+
+            if (!useProvidedKeypoints)
+            {
+                impl.Feature_Detection(keypoints);
+            }
 
-        AKAZEOptions options;
-        options.descriptor = descriptor;
-        options.descriptor_channels = descriptor_channels;
-        options.descriptor_size = descriptor_size;
-        options.img_width = img.cols;
-        options.img_height = img.rows;
-        options.dthreshold = threshold;
-        options.omax = octaves;
-        options.nsublevels = sublevels;
-        options.diffusivity = diffusivity;
+            if (!mask.empty())
+            {
+                KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat());
+            }
 
-        AKAZEFeatures impl(options);
-        impl.Create_Nonlinear_Scale_Space(img1_32);
-        impl.Feature_Detection(keypoints);
+            if( descriptors.needed() )
+            {
+                Mat& desc = descriptors.getMatRef();
+                impl.Compute_Descriptors(keypoints, desc);
 
-        if (!mask.empty())
-        {
-            cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat());
+                CV_Assert((!desc.rows || desc.cols == descriptorSize()));
+                CV_Assert((!desc.rows || (desc.type() == descriptorType())));
+            }
         }
-    }
 
-    void AKAZE::computeImpl(InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const
+        int descriptor;
+        int descriptor_channels;
+        int descriptor_size;
+        float threshold;
+        int octaves;
+        int sublevels;
+        int diffusivity;
+    };
+
+    Ptr<AKAZE> AKAZE::create(int descriptor_type,
+                             int descriptor_size, int descriptor_channels,
+                             float threshold, int octaves,
+                             int sublevels, int diffusivity)
     {
-        cv::Mat img = image.getMat();
-        if (img.type() != CV_8UC1)
-            cvtColor(image, img, COLOR_BGR2GRAY);
-
-        Mat img1_32;
-        img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0);
-
-        cv::Mat& desc = descriptors.getMatRef();
-
-        AKAZEOptions options;
-        options.descriptor = descriptor;
-        options.descriptor_channels = descriptor_channels;
-        options.descriptor_size = descriptor_size;
-        options.img_width = img.cols;
-        options.img_height = img.rows;
-        options.dthreshold = threshold;
-        options.omax = octaves;
-        options.nsublevels = sublevels;
-        options.diffusivity = diffusivity;
-
-        AKAZEFeatures impl(options);
-        impl.Create_Nonlinear_Scale_Space(img1_32);
-        impl.Compute_Descriptors(keypoints, desc);
-
-        CV_Assert((!desc.rows || desc.cols == descriptorSize()));
-        CV_Assert((!desc.rows || (desc.type() == descriptorType())));
+        return makePtr<AKAZE_Impl>(descriptor_type, descriptor_size, descriptor_channels,
+                                   threshold, octaves, sublevels, diffusivity);
     }
 }
index b9511e9..daf1d36 100644 (file)
@@ -75,11 +75,10 @@ protected:
       double confidence;
   };
 
-  virtual void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
+  virtual void detect( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() );
   virtual void findBlobs(InputArray image, InputArray binaryImage, std::vector<Center> &centers) const;
 
   Params params;
-  AlgorithmInfo* info() const;
 };
 
 /*
@@ -173,22 +172,22 @@ void SimpleBlobDetector::Params::write(cv::FileStorage& fs) const
     fs << "maxConvexity" << maxConvexity;
 }
 
-SimpleBlobDetector::SimpleBlobDetector(const SimpleBlobDetector::Params &parameters) :
+SimpleBlobDetectorImpl::SimpleBlobDetectorImpl(const SimpleBlobDetector::Params &parameters) :
 params(parameters)
 {
 }
 
-void SimpleBlobDetector::read( const cv::FileNode& fn )
+void SimpleBlobDetectorImpl::read( const cv::FileNode& fn )
 {
     params.read(fn);
 }
 
-void SimpleBlobDetector::write( cv::FileStorage& fs ) const
+void SimpleBlobDetectorImpl::write( cv::FileStorage& fs ) const
 {
     params.write(fs);
 }
 
-void SimpleBlobDetector::findBlobs(InputArray _image, InputArray _binaryImage, std::vector<Center> &centers) const
+void SimpleBlobDetectorImpl::findBlobs(InputArray _image, InputArray _binaryImage, std::vector<Center> &centers) const
 {
     Mat image = _image.getMat(), binaryImage = _binaryImage.getMat();
     (void)image;
@@ -302,7 +301,7 @@ void SimpleBlobDetector::findBlobs(InputArray _image, InputArray _binaryImage, s
 #endif
 }
 
-void SimpleBlobDetector::detectImpl(InputArray image, std::vector<cv::KeyPoint>& keypoints, InputArray) const
+void SimpleBlobDetectorImpl::detect(InputArray image, std::vector<cv::KeyPoint>& keypoints, InputArray)
 {
     //TODO: support mask
     keypoints.clear();
@@ -365,3 +364,10 @@ void SimpleBlobDetector::detectImpl(InputArray image, std::vector<cv::KeyPoint>&
         keypoints.push_back(kpt);
     }
 }
+
+Ptr<SimpleBlobDetector> SimpleBlobDetector::create(const SimpleBlobDetector::Params& params)
+{
+    return makePtr<SimpleBlobDetectorImpl>(params);
+}
+
+}
index 3163de7..1facb3e 100644 (file)
@@ -42,9 +42,7 @@
  the IEEE International Conference on Computer Vision (ICCV2011).
  */
 
-#include <opencv2/features2d.hpp>
-#include <opencv2/core.hpp>
-#include <opencv2/imgproc.hpp>
+#include "precomp.hpp"
 #include <fstream>
 #include <stdlib.h>
 
@@ -53,7 +51,6 @@
 namespace cv
 {
 
-
 class BRISK_Impl : public BRISK
 {
 public:
@@ -62,17 +59,36 @@ public:
     explicit BRISK_Impl(const std::vector<float> &radiusList, const std::vector<int> &numberList,
         float dMax=5.85f, float dMin=8.2f, const std::vector<int> indexChange=std::vector<int>());
 
+    virtual ~BRISK_Impl();
+
+    int descriptorSize() const
+    {
+        return strings_;
+    }
+
+    int descriptorType() const
+    {
+        return CV_8U;
+    }
+
+    int defaultNorm() const
+    {
+        return NORM_HAMMING;
+    }
+
     // call this to generate the kernel:
     // circle of radius r (pixels), with n points;
     // short pairings with dMax, long pairings with dMin
-    void generateKernel(std::vector<float> &radiusList,
-        std::vector<int> &numberList, float dMax=5.85f, float dMin=8.2f,
-        std::vector<int> indexChange=std::vector<int>());
+    void generateKernel(const std::vector<float> &radiusList,
+        const std::vector<int> &numberList, float dMax=5.85f, float dMin=8.2f,
+        const std::vector<int> &indexChange=std::vector<int>());
 
-protected:
+    void detectAndCompute( InputArray image, InputArray mask,
+                     CV_OUT std::vector<KeyPoint>& keypoints,
+                     OutputArray descriptors,
+                     bool useProvidedKeypoints );
 
-    void computeImpl( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const;
-    void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
+protected:
 
     void computeKeypointsNoOrientation(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const;
     void computeDescriptorsAndOrOrientation(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints,
@@ -256,16 +272,16 @@ protected:
   static const float basicSize_;
 };
 
-const float BRISK::basicSize_ = 12.0f;
-const unsigned int BRISK::scales_ = 64;
-const float BRISK::scalerange_ = 30.f; // 40->4 Octaves - else, this needs to be adjusted...
-const unsigned int BRISK::n_rot_ = 1024; // discretization of the rotation look-up
+const float BRISK_Impl::basicSize_ = 12.0f;
+const unsigned int BRISK_Impl::scales_ = 64;
+const float BRISK_Impl::scalerange_ = 30.f; // 40->4 Octaves - else, this needs to be adjusted...
+const unsigned int BRISK_Impl::n_rot_ = 1024; // discretization of the rotation look-up
 
 const float BriskScaleSpace::safetyFactor_ = 1.0f;
 const float BriskScaleSpace::basicSize_ = 12.0f;
 
 // constructors
-BRISK::BRISK(int thresh, int octaves_in, float patternScale)
+BRISK_Impl::BRISK_Impl(int thresh, int octaves_in, float patternScale)
 {
   threshold = thresh;
   octaves = octaves_in;
@@ -291,10 +307,12 @@ BRISK::BRISK(int thresh, int octaves_in, float patternScale)
   nList[4] = 20;
 
   generateKernel(rList, nList, (float)(5.85 * patternScale), (float)(8.2 * patternScale));
-
 }
-BRISK::BRISK(std::vector<float> &radiusList, std::vector<int> &numberList, float dMax, float dMin,
-                                                   std::vector<int> indexChange)
+
+BRISK_Impl::BRISK_Impl(const std::vector<float> &radiusList,
+                       const std::vector<int> &numberList,
+                       float dMax, float dMin,
+                       const std::vector<int> indexChange)
 {
   generateKernel(radiusList, numberList, dMax, dMin, indexChange);
   threshold = 20;
@@ -302,10 +320,12 @@ BRISK::BRISK(std::vector<float> &radiusList, std::vector<int> &numberList, float
 }
 
 void
-BRISK::generateKernel(std::vector<float> &radiusList, std::vector<int> &numberList, float dMax,
-                                         float dMin, std::vector<int> indexChange)
+BRISK_Impl::generateKernel(const std::vector<float> &radiusList,
+                           const std::vector<int> &numberList,
+                           float dMax, float dMin,
+                           const std::vector<int>& _indexChange)
 {
-
+  std::vector<int> indexChange = _indexChange;
   dMax_ = dMax;
   dMin_ = dMin;
 
@@ -427,7 +447,7 @@ BRISK::generateKernel(std::vector<float> &radiusList, std::vector<int> &numberLi
 
 // simple alternative:
 inline int
-BRISK::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const float key_x,
+BRISK_Impl::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const float key_x,
                                             const float key_y, const unsigned int scale, const unsigned int rot,
                                             const unsigned int point) const
 {
@@ -594,8 +614,8 @@ RoiPredicate(const float minX, const float minY, const float maxX, const float m
 
 // computes the descriptor
 void
-BRISK::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
-                   OutputArray _descriptors, bool useProvidedKeypoints) const
+BRISK_Impl::detectAndCompute( InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
+                              OutputArray _descriptors, bool useProvidedKeypoints)
 {
   bool doOrientation=true;
   if (useProvidedKeypoints)
@@ -609,7 +629,7 @@ BRISK::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>& k
 }
 
 void
-BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
+BRISK_Impl::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
                                      OutputArray _descriptors, bool doDescriptors, bool doOrientation,
                                      bool useProvidedKeypoints) const
 {
@@ -775,25 +795,8 @@ BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, s
   delete[] _values;
 }
 
-int
-BRISK::descriptorSize() const
-{
-  return strings_;
-}
 
-int
-BRISK::descriptorType() const
-{
-  return CV_8U;
-}
-
-int
-BRISK::defaultNorm() const
-{
-  return NORM_HAMMING;
-}
-
-BRISK::~BRISK()
+BRISK_Impl::~BRISK_Impl()
 {
   delete[] patternPoints_;
   delete[] shortPairs_;
@@ -803,14 +806,7 @@ BRISK::~BRISK()
 }
 
 void
-BRISK::operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const
-{
-  computeKeypointsNoOrientation(image, mask, keypoints);
-  computeDescriptorsAndOrOrientation(image, mask, keypoints, cv::noArray(), false, true, true);
-}
-
-void
-BRISK::computeKeypointsNoOrientation(InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints) const
+BRISK_Impl::computeKeypointsNoOrientation(InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints) const
 {
   Mat image = _image.getMat(), mask = _mask.getMat();
   if( image.type() != CV_8UC1 )
@@ -821,20 +817,7 @@ BRISK::computeKeypointsNoOrientation(InputArray _image, InputArray _mask, std::v
   briskScaleSpace.getKeypoints(threshold, keypoints);
 
   // remove invalid points
-  removeInvalidPoints(mask, keypoints);
-}
-
-
-void
-BRISK::detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const
-{
-    (*this)(image.getMat(), mask.getMat(), keypoints);
-}
-
-void
-    BRISK::computeImpl( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const
-{
-    (*this)(image, Mat(), keypoints, descriptors, true);
+  KeyPointsFilter::runByPixelsMask(keypoints, mask);
 }
 
 // construct telling the octaves number:
@@ -2084,7 +2067,7 @@ BriskLayer::BriskLayer(const cv::Mat& img_in, float scale_in, float offset_in)
   scale_ = scale_in;
   offset_ = offset_in;
   // create an agast detector
-  fast_9_16_ = makePtr<FastFeatureDetector>(1, true, FastFeatureDetector::TYPE_9_16);
+  fast_9_16_ = FastFeatureDetector::create(1, true, FastFeatureDetector::TYPE_9_16);
   makeOffsets(pixel_5_8_, (int)img_.step, 8);
   makeOffsets(pixel_9_16_, (int)img_.step, 16);
 }
@@ -2106,7 +2089,7 @@ BriskLayer::BriskLayer(const BriskLayer& layer, int mode)
     offset_ = 0.5f * scale_ - 0.5f;
   }
   scores_ = cv::Mat::zeros(img_.rows, img_.cols, CV_8U);
-  fast_9_16_ = makePtr<FastFeatureDetector>(1, false, FastFeatureDetector::TYPE_9_16);
+  fast_9_16_ = FastFeatureDetector::create(1, false, FastFeatureDetector::TYPE_9_16);
   makeOffsets(pixel_5_8_, (int)img_.step, 8);
   makeOffsets(pixel_9_16_, (int)img_.step, 16);
 }
@@ -2318,4 +2301,16 @@ BriskLayer::twothirdsample(const cv::Mat& srcimg, cv::Mat& dstimg)
   resize(srcimg, dstimg, dstimg.size(), 0, 0, INTER_AREA);
 }
 
+Ptr<BRISK> BRISK::create(int thresh, int octaves, float patternScale)
+{
+    return makePtr<BRISK_Impl>(thresh, octaves, patternScale);
+}
+
+// custom setup
+Ptr<BRISK> BRISK::create(const std::vector<float> &radiusList, const std::vector<int> &numberList,
+                         float dMax, float dMin, const std::vector<int>& indexChange)
+{
+    return makePtr<BRISK_Impl>(radiusList, numberList, dMax, dMin, indexChange);
+}
+
 }
diff --git a/modules/features2d/src/feature2d.cpp b/modules/features2d/src/feature2d.cpp
new file mode 100644 (file)
index 0000000..039b33d
--- /dev/null
@@ -0,0 +1,159 @@
+/*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, 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
+{
+
+using std::vector;
+
+Feature2D::~Feature2D() {}
+
+/*
+ * Detect keypoints in an image.
+ * image        The image.
+ * keypoints    The detected keypoints.
+ * mask         Mask specifying where to look for keypoints (optional). Must be a char
+ *              matrix with non-zero values in the region of interest.
+ */
+void Feature2D::detect( InputArray image,
+                        std::vector<KeyPoint>& keypoints,
+                        InputArray mask )
+{
+    detectAndCompute(image, mask, keypoints, noArray(), false);
+}
+
+
+void Feature2D::detect( InputArrayOfArrays _images,
+                        std::vector<std::vector<KeyPoint> >& keypoints,
+                        InputArrayOfArrays _masks )
+{
+    vector<Mat> images, masks;
+
+    _images.getMatVector(images);
+    size_t i, nimages = images.size();
+
+    if( !_masks.empty() )
+    {
+        _masks.getMatVector(masks);
+        CV_Assert(masks.size() == nimages);
+    }
+
+    keypoints.resize(nimages);
+
+    for( i = 0; i < nimages; i++ )
+    {
+        detect(images[i], keypoints[i], masks.empty() ? Mat() : masks[i] );
+    }
+}
+
+/*
+ * Compute the descriptors for a set of keypoints in an image.
+ * image        The image.
+ * keypoints    The input keypoints. Keypoints for which a descriptor cannot be computed are removed.
+ * descriptors  Copmputed descriptors. Row i is the descriptor for keypoint i.
+ */
+void Feature2D::compute( InputArray image,
+                         std::vector<KeyPoint>& keypoints,
+                         OutputArray descriptors )
+{
+    detectAndCompute(image, noArray(), keypoints, descriptors, true);
+}
+
+void Feature2D::compute( InputArrayOfArrays _images,
+                         std::vector<std::vector<KeyPoint> >& keypoints,
+                         OutputArrayOfArrays _descriptors )
+{
+    if( !_descriptors.needed() )
+        return;
+
+    vector<Mat> images;
+
+    _images.getMatVector(images);
+    size_t i, nimages = images.size();
+
+    CV_Assert( keypoints.size() == nimages );
+    CV_Assert( _descriptors.kind() == _InputArray::STD_VECTOR_MAT );
+
+    vector<Mat>& descriptors = *(vector<Mat>*)_descriptors.getObj();
+    descriptors.resize(nimages);
+
+    for( i = 0; i < nimages; i++ )
+    {
+        compute(images[i], keypoints[i], descriptors[i]);
+    }
+}
+
+
+/* Detects keypoints and computes the descriptors */
+void Feature2D::detectAndCompute( InputArray, InputArray,
+                                  std::vector<KeyPoint>&,
+                                  OutputArray,
+                                  bool )
+{
+    CV_Error(Error::StsNotImplemented, "");
+}
+
+int Feature2D::descriptorSize() const
+{
+    return 0;
+}
+
+int Feature2D::descriptorType() const
+{
+    return CV_32F;
+}
+
+int Feature2D::defaultNorm() const
+{
+    int tp = descriptorType();
+    return tp == CV_8U ? NORM_HAMMING : NORM_L2;
+}
+
+// Return true if detector object is empty
+bool Feature2D::empty() const
+{
+    return true;
+}
+
+}
diff --git a/modules/features2d/src/features2d_init.cpp b/modules/features2d/src/features2d_init.cpp
deleted file mode 100644 (file)
index b23a889..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*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, 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"
-
-#if 0
-
-using namespace cv;
-
-Ptr<Feature2D> Feature2D::create( const String& feature2DType )
-{
-    return Algorithm::create<Feature2D>("Feature2D." + feature2DType);
-}
-
-/////////////////////// AlgorithmInfo for various detector & descriptors ////////////////////////////
-
-/* NOTE!!!
-   All the AlgorithmInfo-related stuff should be in the same file as initModule_features2d().
-   Otherwise, linker may throw away some seemingly unused stuff.
-*/
-
-CV_INIT_ALGORITHM(BRISK, "Feature2D.BRISK",
-                   obj.info()->addParam(obj, "thres", obj.threshold);
-                   obj.info()->addParam(obj, "octaves", obj.octaves))
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-CV_INIT_ALGORITHM(FastFeatureDetector, "Feature2D.FAST",
-                  obj.info()->addParam(obj, "threshold", obj.threshold);
-                  obj.info()->addParam(obj, "nonmaxSuppression", obj.nonmaxSuppression);
-                  obj.info()->addParam(obj, "type", obj.type))
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-CV_INIT_ALGORITHM(MSER, "Feature2D.MSER",
-                  obj.info()->addParam(obj, "delta", obj.delta);
-                  obj.info()->addParam(obj, "minArea", obj.minArea);
-                  obj.info()->addParam(obj, "maxArea", obj.maxArea);
-                  obj.info()->addParam(obj, "maxVariation", obj.maxVariation);
-                  obj.info()->addParam(obj, "minDiversity", obj.minDiversity);
-                  obj.info()->addParam(obj, "maxEvolution", obj.maxEvolution);
-                  obj.info()->addParam(obj, "areaThreshold", obj.areaThreshold);
-                  obj.info()->addParam(obj, "minMargin", obj.minMargin);
-                  obj.info()->addParam(obj, "edgeBlurSize", obj.edgeBlurSize))
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-CV_INIT_ALGORITHM(ORB, "Feature2D.ORB",
-                  obj.info()->addParam(obj, "nFeatures", obj.nfeatures);
-                  obj.info()->addParam(obj, "scaleFactor", obj.scaleFactor);
-                  obj.info()->addParam(obj, "nLevels", obj.nlevels);
-                  obj.info()->addParam(obj, "firstLevel", obj.firstLevel);
-                  obj.info()->addParam(obj, "edgeThreshold", obj.edgeThreshold);
-                  obj.info()->addParam(obj, "patchSize", obj.patchSize);
-                  obj.info()->addParam(obj, "WTA_K", obj.WTA_K);
-                  obj.info()->addParam(obj, "scoreType", obj.scoreType);
-                  obj.info()->addParam(obj, "fastThreshold", obj.fastThreshold))
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-CV_INIT_ALGORITHM(GFTTDetector, "Feature2D.GFTT",
-                  obj.info()->addParam(obj, "nfeatures", obj.nfeatures);
-                  obj.info()->addParam(obj, "qualityLevel", obj.qualityLevel);
-                  obj.info()->addParam(obj, "minDistance", obj.minDistance);
-                  obj.info()->addParam(obj, "useHarrisDetector", obj.useHarrisDetector);
-                  obj.info()->addParam(obj, "k", obj.k))
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-CV_INIT_ALGORITHM(KAZE, "Feature2D.KAZE",
-                  obj.info()->addParam(obj, "upright", obj.upright);
-                  obj.info()->addParam(obj, "extended", obj.extended);
-                  obj.info()->addParam(obj, "threshold", obj.threshold);
-                  obj.info()->addParam(obj, "octaves", obj.octaves);
-                  obj.info()->addParam(obj, "sublevels", obj.sublevels);
-                  obj.info()->addParam(obj, "diffusivity", obj.diffusivity))
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-CV_INIT_ALGORITHM(AKAZE, "Feature2D.AKAZE",
-                  obj.info()->addParam(obj, "descriptor", obj.descriptor);
-                  obj.info()->addParam(obj, "descriptor_channels", obj.descriptor_channels);
-                  obj.info()->addParam(obj, "descriptor_size", obj.descriptor_size);
-                  obj.info()->addParam(obj, "threshold", obj.threshold);
-                  obj.info()->addParam(obj, "octaves", obj.octaves);
-                  obj.info()->addParam(obj, "sublevels", obj.sublevels);
-                  obj.info()->addParam(obj, "diffusivity", obj.diffusivity))
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-
-CV_INIT_ALGORITHM(SimpleBlobDetector, "Feature2D.SimpleBlob",
-                  obj.info()->addParam(obj, "thresholdStep",    obj.params.thresholdStep);
-                  obj.info()->addParam(obj, "minThreshold",     obj.params.minThreshold);
-                  obj.info()->addParam(obj, "maxThreshold",     obj.params.maxThreshold);
-                  obj.info()->addParam_(obj, "minRepeatability", (sizeof(size_t) == sizeof(uint64))?Param::UINT64 : Param::UNSIGNED_INT, &obj.params.minRepeatability, false, 0, 0);
-                  obj.info()->addParam(obj, "minDistBetweenBlobs", obj.params.minDistBetweenBlobs);
-                  obj.info()->addParam(obj, "filterByColor",    obj.params.filterByColor);
-                  obj.info()->addParam(obj, "blobColor",        obj.params.blobColor);
-                  obj.info()->addParam(obj, "filterByArea",     obj.params.filterByArea);
-                  obj.info()->addParam(obj, "maxArea",          obj.params.maxArea);
-                  obj.info()->addParam(obj, "filterByCircularity", obj.params.filterByCircularity);
-                  obj.info()->addParam(obj, "maxCircularity",   obj.params.maxCircularity);
-                  obj.info()->addParam(obj, "filterByInertia",  obj.params.filterByInertia);
-                  obj.info()->addParam(obj, "maxInertiaRatio",  obj.params.maxInertiaRatio);
-                  obj.info()->addParam(obj, "filterByConvexity", obj.params.filterByConvexity);
-                  obj.info()->addParam(obj, "maxConvexity",     obj.params.maxConvexity);
-                  )
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-class CV_EXPORTS HarrisDetector : public GFTTDetector
-{
-public:
-    HarrisDetector( int maxCorners=1000, double qualityLevel=0.01, double minDistance=1,
-                    int blockSize=3, bool useHarrisDetector=true, double k=0.04 );
-    AlgorithmInfo* info() const;
-};
-
-inline HarrisDetector::HarrisDetector( int _maxCorners, double _qualityLevel, double _minDistance,
-                    int _blockSize, bool _useHarrisDetector, double _k )
-    : GFTTDetector( _maxCorners, _qualityLevel, _minDistance, _blockSize, _useHarrisDetector, _k ) {}
-
-CV_INIT_ALGORITHM(HarrisDetector, "Feature2D.HARRIS",
-                  obj.info()->addParam(obj, "nfeatures", obj.nfeatures);
-                  obj.info()->addParam(obj, "qualityLevel", obj.qualityLevel);
-                  obj.info()->addParam(obj, "minDistance", obj.minDistance);
-                  obj.info()->addParam(obj, "useHarrisDetector", obj.useHarrisDetector);
-                  obj.info()->addParam(obj, "k", obj.k))
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-CV_INIT_ALGORITHM(BFMatcher, "DescriptorMatcher.BFMatcher",
-                  obj.info()->addParam(obj, "normType", obj.normType);
-                  obj.info()->addParam(obj, "crossCheck", obj.crossCheck))
-
-CV_INIT_ALGORITHM(FlannBasedMatcher, "DescriptorMatcher.FlannBasedMatcher",)
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool cv::initModule_features2d(void)
-{
-    bool all = true;
-    all &= !BRISK_info_auto.name().empty();
-    all &= !FastFeatureDetector_info_auto.name().empty();
-    all &= !MSER_info_auto.name().empty();
-    all &= !ORB_info_auto.name().empty();
-    all &= !GFTTDetector_info_auto.name().empty();
-    all &= !KAZE_info_auto.name().empty();
-    all &= !AKAZE_info_auto.name().empty();
-    all &= !HarrisDetector_info_auto.name().empty();
-    all &= !BFMatcher_info_auto.name().empty();
-    all &= !FlannBasedMatcher_info_auto.name().empty();
-
-    return all;
-}
-
-#endif
index d16e988..83eeecc 100644 (file)
@@ -140,5 +140,11 @@ namespace cv
         int diffusivity;
     };
 
-
+    Ptr<KAZE> KAZE::create(bool extended, bool upright,
+                            float threshold,
+                            int octaves, int sublevels,
+                            int diffusivity)
+    {
+        return makePtr<KAZE_Impl>(extended, upright, threshold, octaves, sublevels, diffusivity);
+    }
 }
index 2ea21f3..806d25c 100644 (file)
@@ -22,12 +22,12 @@ struct AKAZEOptions {
         , soffset(1.6f)
         , derivative_factor(1.5f)
         , sderivatives(1.0)
-        , diffusivity(cv::DIFF_PM_G2)
+        , diffusivity(KAZE::DIFF_PM_G2)
 
         , dthreshold(0.001f)
         , min_dthreshold(0.00001f)
 
-        , descriptor(cv::DESCRIPTOR_MLDB)
+        , descriptor(AKAZE::DESCRIPTOR_MLDB)
         , descriptor_size(0)
         , descriptor_channels(3)
         , descriptor_pattern_size(10)
index 59e260f..7988584 100644 (file)
@@ -61,14 +61,14 @@ void AKAZEFeatures::Allocate_Memory_Evolution(void) {
 
     for (int j = 0; j < options_.nsublevels; j++) {
       TEvolution step;
-      step.Lx = cv::Mat::zeros(level_height, level_width, CV_32F);
-      step.Ly = cv::Mat::zeros(level_height, level_width, CV_32F);
-      step.Lxx = cv::Mat::zeros(level_height, level_width, CV_32F);
-      step.Lxy = cv::Mat::zeros(level_height, level_width, CV_32F);
-      step.Lyy = cv::Mat::zeros(level_height, level_width, CV_32F);
-      step.Lt = cv::Mat::zeros(level_height, level_width, CV_32F);
-      step.Ldet = cv::Mat::zeros(level_height, level_width, CV_32F);
-      step.Lsmooth = cv::Mat::zeros(level_height, level_width, CV_32F);
+      step.Lx = Mat::zeros(level_height, level_width, CV_32F);
+      step.Ly = Mat::zeros(level_height, level_width, CV_32F);
+      step.Lxx = Mat::zeros(level_height, level_width, CV_32F);
+      step.Lxy = Mat::zeros(level_height, level_width, CV_32F);
+      step.Lyy = Mat::zeros(level_height, level_width, CV_32F);
+      step.Lt = Mat::zeros(level_height, level_width, CV_32F);
+      step.Ldet = Mat::zeros(level_height, level_width, CV_32F);
+      step.Lsmooth = Mat::zeros(level_height, level_width, CV_32F);
       step.esigma = options_.soffset*pow(2.f, (float)(j) / (float)(options_.nsublevels) + i);
       step.sigma_size = fRound(step.esigma);
       step.etime = 0.5f*(step.esigma*step.esigma);
@@ -97,7 +97,7 @@ void AKAZEFeatures::Allocate_Memory_Evolution(void) {
  * @param img Input image for which the nonlinear scale space needs to be created
  * @return 0 if the nonlinear scale space was created successfully, -1 otherwise
  */
-int AKAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat& img)
+int AKAZEFeatures::Create_Nonlinear_Scale_Space(const Mat& img)
 {
   CV_Assert(evolution_.size() > 0);
 
@@ -107,8 +107,8 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat& img)
   evolution_[0].Lt.copyTo(evolution_[0].Lsmooth);
 
   // Allocate memory for the flow and step images
-  cv::Mat Lflow = cv::Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
-  cv::Mat Lstep = cv::Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
+  Mat Lflow = Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
+  Mat Lstep = Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
 
   // First compute the kcontrast factor
   options_.kcontrast = compute_k_percentile(img, options_.kcontrast_percentile, 1.0f, options_.kcontrast_nbins, 0, 0);
@@ -121,8 +121,8 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat& img)
       options_.kcontrast = options_.kcontrast*0.75f;
 
       // Allocate memory for the resized flow and step images
-      Lflow = cv::Mat::zeros(evolution_[i].Lt.rows, evolution_[i].Lt.cols, CV_32F);
-      Lstep = cv::Mat::zeros(evolution_[i].Lt.rows, evolution_[i].Lt.cols, CV_32F);
+      Lflow = Mat::zeros(evolution_[i].Lt.rows, evolution_[i].Lt.cols, CV_32F);
+      Lstep = Mat::zeros(evolution_[i].Lt.rows, evolution_[i].Lt.cols, CV_32F);
     }
     else {
       evolution_[i - 1].Lt.copyTo(evolution_[i].Lt);
@@ -136,16 +136,16 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat& img)
 
     // Compute the conductivity equation
     switch (options_.diffusivity) {
-      case cv::DIFF_PM_G1:
+      case KAZE::DIFF_PM_G1:
         pm_g1(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
       break;
-      case cv::DIFF_PM_G2:
+      case KAZE::DIFF_PM_G2:
         pm_g2(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
       break;
-      case cv::DIFF_WEICKERT:
+      case KAZE::DIFF_WEICKERT:
         weickert_diffusivity(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
       break;
-      case cv::DIFF_CHARBONNIER:
+      case KAZE::DIFF_CHARBONNIER:
         charbonnier_diffusivity(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
       break;
       default:
@@ -155,7 +155,7 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat& img)
 
     // Perform FED n inner steps
     for (int j = 0; j < nsteps_[i - 1]; j++) {
-      cv::details::kaze::nld_step_scalar(evolution_[i].Lt, Lflow, Lstep, tsteps_[i - 1][j]);
+      nld_step_scalar(evolution_[i].Lt, Lflow, Lstep, tsteps_[i - 1][j]);
     }
   }
 
@@ -167,7 +167,7 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat& img)
  * @brief This method selects interesting keypoints through the nonlinear scale space
  * @param kpts Vector of detected keypoints
  */
-void AKAZEFeatures::Feature_Detection(std::vector<cv::KeyPoint>& kpts)
+void AKAZEFeatures::Feature_Detection(std::vector<KeyPoint>& kpts)
 {
   kpts.clear();
   Compute_Determinant_Hessian_Response();
@@ -176,7 +176,7 @@ void AKAZEFeatures::Feature_Detection(std::vector<cv::KeyPoint>& kpts)
 }
 
 /* ************************************************************************* */
-class MultiscaleDerivativesAKAZEInvoker : public cv::ParallelLoopBody
+class MultiscaleDerivativesAKAZEInvoker : public ParallelLoopBody
 {
 public:
     explicit MultiscaleDerivativesAKAZEInvoker(std::vector<TEvolution>& ev, const AKAZEOptions& opt)
@@ -185,7 +185,7 @@ public:
   {
   }
 
-  void operator()(const cv::Range& range) const
+  void operator()(const Range& range) const
   {
     std::vector<TEvolution>& evolution = *evolution_;
 
@@ -219,7 +219,7 @@ private:
  */
 void AKAZEFeatures::Compute_Multiscale_Derivatives(void)
 {
-  cv::parallel_for_(cv::Range(0, (int)evolution_.size()),
+  parallel_for_(Range(0, (int)evolution_.size()),
                                         MultiscaleDerivativesAKAZEInvoker(evolution_, options_));
 }
 
@@ -253,7 +253,7 @@ void AKAZEFeatures::Compute_Determinant_Hessian_Response(void) {
  * @brief This method finds extrema in the nonlinear scale space
  * @param kpts Vector of detected keypoints
  */
-void AKAZEFeatures::Find_Scale_Space_Extrema(std::vector<cv::KeyPoint>& kpts)
+void AKAZEFeatures::Find_Scale_Space_Extrema(std::vector<KeyPoint>& kpts)
 {
 
   float value = 0.0;
@@ -261,8 +261,8 @@ void AKAZEFeatures::Find_Scale_Space_Extrema(std::vector<cv::KeyPoint>& kpts)
   int npoints = 0, id_repeated = 0;
   int sigma_size_ = 0, left_x = 0, right_x = 0, up_y = 0, down_y = 0;
   bool is_extremum = false, is_repeated = false, is_out = false;
-  cv::KeyPoint point;
-  vector<cv::KeyPoint> kpts_aux;
+  KeyPoint point;
+  vector<KeyPoint> kpts_aux;
 
   // Set maximum size
   if (options_.descriptor == AKAZE::DESCRIPTOR_MLDB_UPRIGHT || options_.descriptor == AKAZE::DESCRIPTOR_MLDB) {
@@ -365,7 +365,7 @@ void AKAZEFeatures::Find_Scale_Space_Extrema(std::vector<cv::KeyPoint>& kpts)
   for (size_t i = 0; i < kpts_aux.size(); i++) {
 
     is_repeated = false;
-    const cv::KeyPoint& pt = kpts_aux[i];
+    const KeyPoint& pt = kpts_aux[i];
     for (size_t j = i + 1; j < kpts_aux.size(); j++) {
 
       // Compare response with the upper scale
@@ -392,7 +392,7 @@ void AKAZEFeatures::Find_Scale_Space_Extrema(std::vector<cv::KeyPoint>& kpts)
  * @brief This method performs subpixel refinement of the detected keypoints
  * @param kpts Vector of detected keypoints
  */
-void AKAZEFeatures::Do_Subpixel_Refinement(std::vector<cv::KeyPoint>& kpts)
+void AKAZEFeatures::Do_Subpixel_Refinement(std::vector<KeyPoint>& kpts)
 {
   float Dx = 0.0, Dy = 0.0, ratio = 0.0;
   float Dxx = 0.0, Dyy = 0.0, Dxy = 0.0;
@@ -433,7 +433,7 @@ void AKAZEFeatures::Do_Subpixel_Refinement(std::vector<cv::KeyPoint>& kpts)
     b(0) = -Dx;
     b(1) = -Dy;
 
-    cv::solve(A, b, dst, DECOMP_LU);
+    solve(A, b, dst, DECOMP_LU);
 
     if (fabs(dst(0)) <= 1.0f && fabs(dst(1)) <= 1.0f) {
         kpts[i].pt.x = x + dst(0);
@@ -456,10 +456,10 @@ void AKAZEFeatures::Do_Subpixel_Refinement(std::vector<cv::KeyPoint>& kpts)
 
 /* ************************************************************************* */
 
-class SURF_Descriptor_Upright_64_Invoker : public cv::ParallelLoopBody
+class SURF_Descriptor_Upright_64_Invoker : public ParallelLoopBody
 {
 public:
-  SURF_Descriptor_Upright_64_Invoker(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc, std::vector<TEvolution>& evolution)
+  SURF_Descriptor_Upright_64_Invoker(std::vector<KeyPoint>& kpts, Mat& desc, std::vector<TEvolution>& evolution)
     : keypoints_(&kpts)
     , descriptors_(&desc)
     , evolution_(&evolution)
@@ -474,18 +474,18 @@ public:
     }
   }
 
-  void Get_SURF_Descriptor_Upright_64(const cv::KeyPoint& kpt, float* desc) const;
+  void Get_SURF_Descriptor_Upright_64(const KeyPoint& kpt, float* desc) const;
 
 private:
-  std::vector<cv::KeyPoint>* keypoints_;
-  cv::Mat*                   descriptors_;
+  std::vector<KeyPoint>* keypoints_;
+  Mat*                   descriptors_;
   std::vector<TEvolution>*   evolution_;
 };
 
-class SURF_Descriptor_64_Invoker : public cv::ParallelLoopBody
+class SURF_Descriptor_64_Invoker : public ParallelLoopBody
 {
 public:
-  SURF_Descriptor_64_Invoker(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc, std::vector<TEvolution>& evolution)
+  SURF_Descriptor_64_Invoker(std::vector<KeyPoint>& kpts, Mat& desc, std::vector<TEvolution>& evolution)
     : keypoints_(&kpts)
     , descriptors_(&desc)
     , evolution_(&evolution)
@@ -501,18 +501,18 @@ public:
     }
   }
 
-  void Get_SURF_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const;
+  void Get_SURF_Descriptor_64(const KeyPoint& kpt, float* desc) const;
 
 private:
-  std::vector<cv::KeyPoint>* keypoints_;
-  cv::Mat*                   descriptors_;
+  std::vector<KeyPoint>* keypoints_;
+  Mat*                   descriptors_;
   std::vector<TEvolution>*   evolution_;
 };
 
-class MSURF_Upright_Descriptor_64_Invoker : public cv::ParallelLoopBody
+class MSURF_Upright_Descriptor_64_Invoker : public ParallelLoopBody
 {
 public:
-  MSURF_Upright_Descriptor_64_Invoker(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc, std::vector<TEvolution>& evolution)
+  MSURF_Upright_Descriptor_64_Invoker(std::vector<KeyPoint>& kpts, Mat& desc, std::vector<TEvolution>& evolution)
     : keypoints_(&kpts)
     , descriptors_(&desc)
     , evolution_(&evolution)
@@ -527,18 +527,18 @@ public:
     }
   }
 
-  void Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const;
+  void Get_MSURF_Upright_Descriptor_64(const KeyPoint& kpt, float* desc) const;
 
 private:
-  std::vector<cv::KeyPoint>* keypoints_;
-  cv::Mat*                   descriptors_;
+  std::vector<KeyPoint>* keypoints_;
+  Mat*                   descriptors_;
   std::vector<TEvolution>*   evolution_;
 };
 
-class MSURF_Descriptor_64_Invoker : public cv::ParallelLoopBody
+class MSURF_Descriptor_64_Invoker : public ParallelLoopBody
 {
 public:
-  MSURF_Descriptor_64_Invoker(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc, std::vector<TEvolution>& evolution)
+  MSURF_Descriptor_64_Invoker(std::vector<KeyPoint>& kpts, Mat& desc, std::vector<TEvolution>& evolution)
     : keypoints_(&kpts)
     , descriptors_(&desc)
     , evolution_(&evolution)
@@ -554,18 +554,18 @@ public:
     }
   }
 
-  void Get_MSURF_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const;
+  void Get_MSURF_Descriptor_64(const KeyPoint& kpt, float* desc) const;
 
 private:
-  std::vector<cv::KeyPoint>* keypoints_;
-  cv::Mat*                   descriptors_;
+  std::vector<KeyPoint>* keypoints_;
+  Mat*                   descriptors_;
   std::vector<TEvolution>*   evolution_;
 };
 
-class Upright_MLDB_Full_Descriptor_Invoker : public cv::ParallelLoopBody
+class Upright_MLDB_Full_Descriptor_Invoker : public ParallelLoopBody
 {
 public:
-  Upright_MLDB_Full_Descriptor_Invoker(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc, std::vector<TEvolution>& evolution, AKAZEOptions& options)
+  Upright_MLDB_Full_Descriptor_Invoker(std::vector<KeyPoint>& kpts, Mat& desc, std::vector<TEvolution>& evolution, AKAZEOptions& options)
     : keypoints_(&kpts)
     , descriptors_(&desc)
     , evolution_(&evolution)
@@ -581,24 +581,24 @@ public:
     }
   }
 
-  void Get_Upright_MLDB_Full_Descriptor(const cv::KeyPoint& kpt, unsigned char* desc) const;
+  void Get_Upright_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char* desc) const;
 
 private:
-  std::vector<cv::KeyPoint>* keypoints_;
-  cv::Mat*                   descriptors_;
+  std::vector<KeyPoint>* keypoints_;
+  Mat*                   descriptors_;
   std::vector<TEvolution>*   evolution_;
   AKAZEOptions*              options_;
 };
 
-class Upright_MLDB_Descriptor_Subset_Invoker : public cv::ParallelLoopBody
+class Upright_MLDB_Descriptor_Subset_Invoker : public ParallelLoopBody
 {
 public:
-  Upright_MLDB_Descriptor_Subset_Invoker(std::vector<cv::KeyPoint>& kpts,
-                                         cv::Mat& desc,
+  Upright_MLDB_Descriptor_Subset_Invoker(std::vector<KeyPoint>& kpts,
+                                         Mat& desc,
                                          std::vector<TEvolution>& evolution,
                                          AKAZEOptions& options,
-                                         cv::Mat descriptorSamples,
-                                         cv::Mat descriptorBits)
+                                         Mat descriptorSamples,
+                                         Mat descriptorBits)
     : keypoints_(&kpts)
     , descriptors_(&desc)
     , evolution_(&evolution)
@@ -616,22 +616,22 @@ public:
     }
   }
 
-  void Get_Upright_MLDB_Descriptor_Subset(const cv::KeyPoint& kpt, unsigned char* desc) const;
+  void Get_Upright_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char* desc) const;
 
 private:
-  std::vector<cv::KeyPoint>* keypoints_;
-  cv::Mat*                   descriptors_;
+  std::vector<KeyPoint>* keypoints_;
+  Mat*                   descriptors_;
   std::vector<TEvolution>*   evolution_;
   AKAZEOptions*              options_;
 
-  cv::Mat descriptorSamples_;  // List of positions in the grids to sample LDB bits from.
-  cv::Mat descriptorBits_;
+  Mat descriptorSamples_;  // List of positions in the grids to sample LDB bits from.
+  Mat descriptorBits_;
 };
 
-class MLDB_Full_Descriptor_Invoker : public cv::ParallelLoopBody
+class MLDB_Full_Descriptor_Invoker : public ParallelLoopBody
 {
 public:
-  MLDB_Full_Descriptor_Invoker(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc, std::vector<TEvolution>& evolution, AKAZEOptions& options)
+  MLDB_Full_Descriptor_Invoker(std::vector<KeyPoint>& kpts, Mat& desc, std::vector<TEvolution>& evolution, AKAZEOptions& options)
     : keypoints_(&kpts)
     , descriptors_(&desc)
     , evolution_(&evolution)
@@ -648,28 +648,28 @@ public:
     }
   }
 
-  void Get_MLDB_Full_Descriptor(const cv::KeyPoint& kpt, unsigned char* desc) const;
+  void Get_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char* desc) const;
   void MLDB_Fill_Values(float* values, int sample_step, int level,
                         float xf, float yf, float co, float si, float scale) const;
   void MLDB_Binary_Comparisons(float* values, unsigned char* desc,
                                int count, int& dpos) const;
 
 private:
-  std::vector<cv::KeyPoint>* keypoints_;
-  cv::Mat*                   descriptors_;
+  std::vector<KeyPoint>* keypoints_;
+  Mat*                   descriptors_;
   std::vector<TEvolution>*   evolution_;
   AKAZEOptions*              options_;
 };
 
-class MLDB_Descriptor_Subset_Invoker : public cv::ParallelLoopBody
+class MLDB_Descriptor_Subset_Invoker : public ParallelLoopBody
 {
 public:
-  MLDB_Descriptor_Subset_Invoker(std::vector<cv::KeyPoint>& kpts,
-                                 cv::Mat& desc,
+  MLDB_Descriptor_Subset_Invoker(std::vector<KeyPoint>& kpts,
+                                 Mat& desc,
                                  std::vector<TEvolution>& evolution,
                                  AKAZEOptions& options,
-                                 cv::Mat descriptorSamples,
-                                 cv::Mat descriptorBits)
+                                 Mat descriptorSamples,
+                                 Mat descriptorBits)
     : keypoints_(&kpts)
     , descriptors_(&desc)
     , evolution_(&evolution)
@@ -688,16 +688,16 @@ public:
     }
   }
 
-  void Get_MLDB_Descriptor_Subset(const cv::KeyPoint& kpt, unsigned char* desc) const;
+  void Get_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char* desc) const;
 
 private:
-  std::vector<cv::KeyPoint>* keypoints_;
-  cv::Mat*                   descriptors_;
+  std::vector<KeyPoint>* keypoints_;
+  Mat*                   descriptors_;
   std::vector<TEvolution>*   evolution_;
   AKAZEOptions*              options_;
 
-  cv::Mat descriptorSamples_;  // List of positions in the grids to sample LDB bits from.
-  cv::Mat descriptorBits_;
+  Mat descriptorSamples_;  // List of positions in the grids to sample LDB bits from.
+  Mat descriptorBits_;
 };
 
 /**
@@ -705,7 +705,7 @@ private:
  * @param kpts Vector of detected keypoints
  * @param desc Matrix to store the descriptors
  */
-void AKAZEFeatures::Compute_Descriptors(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc)
+void AKAZEFeatures::Compute_Descriptors(std::vector<KeyPoint>& kpts, Mat& desc)
 {
   for(size_t i = 0; i < kpts.size(); i++)
   {
@@ -714,17 +714,17 @@ void AKAZEFeatures::Compute_Descriptors(std::vector<cv::KeyPoint>& kpts, cv::Mat
 
   // Allocate memory for the matrix with the descriptors
   if (options_.descriptor < AKAZE::DESCRIPTOR_MLDB_UPRIGHT) {
-    desc = cv::Mat::zeros((int)kpts.size(), 64, CV_32FC1);
+    desc = Mat::zeros((int)kpts.size(), 64, CV_32FC1);
   }
   else {
     // We use the full length binary descriptor -> 486 bits
     if (options_.descriptor_size == 0) {
       int t = (6 + 36 + 120)*options_.descriptor_channels;
-      desc = cv::Mat::zeros((int)kpts.size(), (int)ceil(t / 8.), CV_8UC1);
+      desc = Mat::zeros((int)kpts.size(), (int)ceil(t / 8.), CV_8UC1);
     }
     else {
       // We use the random bit selection length binary descriptor
-      desc = cv::Mat::zeros((int)kpts.size(), (int)ceil(options_.descriptor_size / 8.), CV_8UC1);
+      desc = Mat::zeros((int)kpts.size(), (int)ceil(options_.descriptor_size / 8.), CV_8UC1);
     }
   }
 
@@ -732,28 +732,28 @@ void AKAZEFeatures::Compute_Descriptors(std::vector<cv::KeyPoint>& kpts, cv::Mat
   {
     case AKAZE::DESCRIPTOR_KAZE_UPRIGHT: // Upright descriptors, not invariant to rotation
     {
-      cv::parallel_for_(cv::Range(0, (int)kpts.size()), MSURF_Upright_Descriptor_64_Invoker(kpts, desc, evolution_));
+      parallel_for_(Range(0, (int)kpts.size()), MSURF_Upright_Descriptor_64_Invoker(kpts, desc, evolution_));
     }
     break;
     case AKAZE::DESCRIPTOR_KAZE:
     {
-      cv::parallel_for_(cv::Range(0, (int)kpts.size()), MSURF_Descriptor_64_Invoker(kpts, desc, evolution_));
+      parallel_for_(Range(0, (int)kpts.size()), MSURF_Descriptor_64_Invoker(kpts, desc, evolution_));
     }
     break;
     case AKAZE::DESCRIPTOR_MLDB_UPRIGHT: // Upright descriptors, not invariant to rotation
     {
       if (options_.descriptor_size == 0)
-        cv::parallel_for_(cv::Range(0, (int)kpts.size()), Upright_MLDB_Full_Descriptor_Invoker(kpts, desc, evolution_, options_));
+        parallel_for_(Range(0, (int)kpts.size()), Upright_MLDB_Full_Descriptor_Invoker(kpts, desc, evolution_, options_));
       else
-        cv::parallel_for_(cv::Range(0, (int)kpts.size()), Upright_MLDB_Descriptor_Subset_Invoker(kpts, desc, evolution_, options_, descriptorSamples_, descriptorBits_));
+        parallel_for_(Range(0, (int)kpts.size()), Upright_MLDB_Descriptor_Subset_Invoker(kpts, desc, evolution_, options_, descriptorSamples_, descriptorBits_));
     }
     break;
     case AKAZE::DESCRIPTOR_MLDB:
     {
       if (options_.descriptor_size == 0)
-        cv::parallel_for_(cv::Range(0, (int)kpts.size()), MLDB_Full_Descriptor_Invoker(kpts, desc, evolution_, options_));
+        parallel_for_(Range(0, (int)kpts.size()), MLDB_Full_Descriptor_Invoker(kpts, desc, evolution_, options_));
       else
-        cv::parallel_for_(cv::Range(0, (int)kpts.size()), MLDB_Descriptor_Subset_Invoker(kpts, desc, evolution_, options_, descriptorSamples_, descriptorBits_));
+        parallel_for_(Range(0, (int)kpts.size()), MLDB_Descriptor_Subset_Invoker(kpts, desc, evolution_, options_, descriptorSamples_, descriptorBits_));
     }
     break;
   }
@@ -766,7 +766,7 @@ void AKAZEFeatures::Compute_Descriptors(std::vector<cv::KeyPoint>& kpts, cv::Mat
  * @note The orientation is computed using a similar approach as described in the
  * original SURF method. See Bay et al., Speeded Up Robust Features, ECCV 2006
  */
-void AKAZEFeatures::Compute_Main_Orientation(cv::KeyPoint& kpt, const std::vector<TEvolution>& evolution_)
+void AKAZEFeatures::Compute_Main_Orientation(KeyPoint& kpt, const std::vector<TEvolution>& evolution_)
 {
     /* ************************************************************************* */
     /// Lookup table for 2d gaussian (sigma = 2.5) where (0,0) is top left and (6,6) is bottom right
@@ -854,7 +854,7 @@ void AKAZEFeatures::Compute_Main_Orientation(cv::KeyPoint& kpt, const std::vecto
  * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
  * ECCV 2008
  */
-void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint& kpt, float *desc) const {
+void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const KeyPoint& kpt, float *desc) const {
 
   float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0;
   float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0;
@@ -977,7 +977,7 @@ void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const
  * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
  * ECCV 2008
  */
-void MSURF_Descriptor_64_Invoker::Get_MSURF_Descriptor_64(const cv::KeyPoint& kpt, float *desc) const {
+void MSURF_Descriptor_64_Invoker::Get_MSURF_Descriptor_64(const KeyPoint& kpt, float *desc) const {
 
   float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0;
   float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0;
@@ -1101,7 +1101,7 @@ void MSURF_Descriptor_64_Invoker::Get_MSURF_Descriptor_64(const cv::KeyPoint& kp
  * @param kpt Input keypoint
  * @param desc Descriptor vector
  */
-void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(const cv::KeyPoint& kpt, unsigned char *desc) const {
+void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char *desc) const {
 
   float di = 0.0, dx = 0.0, dy = 0.0;
   float ri = 0.0, rx = 0.0, ry = 0.0, xf = 0.0, yf = 0.0;
@@ -1114,9 +1114,9 @@ void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(cons
   const std::vector<TEvolution>& evolution = *evolution_;
 
   // Matrices for the M-LDB descriptor
-  cv::Mat values_1 = cv::Mat::zeros(4, options.descriptor_channels, CV_32FC1);
-  cv::Mat values_2 = cv::Mat::zeros(9, options.descriptor_channels, CV_32FC1);
-  cv::Mat values_3 = cv::Mat::zeros(16, options.descriptor_channels, CV_32FC1);
+  Mat values_1 = Mat::zeros(4, options.descriptor_channels, CV_32FC1);
+  Mat values_2 = Mat::zeros(9, options.descriptor_channels, CV_32FC1);
+  Mat values_3 = Mat::zeros(16, options.descriptor_channels, CV_32FC1);
 
   // Get the information from the keypoint
   ratio = (float)(1 << kpt.octave);
@@ -1395,7 +1395,7 @@ void MLDB_Full_Descriptor_Invoker::MLDB_Binary_Comparisons(float* values, unsign
  * @param kpt Input keypoint
  * @param desc Descriptor vector
  */
-void MLDB_Full_Descriptor_Invoker::Get_MLDB_Full_Descriptor(const cv::KeyPoint& kpt, unsigned char *desc) const {
+void MLDB_Full_Descriptor_Invoker::Get_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char *desc) const {
 
   const int max_channels = 3;
   CV_Assert(options_->descriptor_channels <= max_channels);
@@ -1428,7 +1428,7 @@ void MLDB_Full_Descriptor_Invoker::Get_MLDB_Full_Descriptor(const cv::KeyPoint&
  * @param kpt Input keypoint
  * @param desc Descriptor vector
  */
-void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const cv::KeyPoint& kpt, unsigned char *desc) const {
+void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char *desc) const {
 
   float di = 0.f, dx = 0.f, dy = 0.f;
   float rx = 0.f, ry = 0.f;
@@ -1449,7 +1449,7 @@ void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const cv::KeyPoi
   float si = sin(angle);
 
   // Allocate memory for the matrix of values
-  cv::Mat values = cv::Mat_<float>::zeros((4 + 9 + 16)*options.descriptor_channels, 1);
+  Mat values = Mat_<float>::zeros((4 + 9 + 16)*options.descriptor_channels, 1);
 
   // Sample everything, but only do the comparisons
   vector<int> steps(3);
@@ -1522,7 +1522,7 @@ void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const cv::KeyPoi
  * @param kpt Input keypoint
  * @param desc Descriptor vector
  */
-void Upright_MLDB_Descriptor_Subset_Invoker::Get_Upright_MLDB_Descriptor_Subset(const cv::KeyPoint& kpt, unsigned char *desc) const {
+void Upright_MLDB_Descriptor_Subset_Invoker::Get_Upright_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char *desc) const {
 
   float di = 0.0f, dx = 0.0f, dy = 0.0f;
   float rx = 0.0f, ry = 0.0f;
@@ -1540,7 +1540,7 @@ void Upright_MLDB_Descriptor_Subset_Invoker::Get_Upright_MLDB_Descriptor_Subset(
   float xf = kpt.pt.x / ratio;
 
   // Allocate memory for the matrix of values
-  Mat values = cv::Mat_<float>::zeros((4 + 9 + 16)*options.descriptor_channels, 1);
+  Mat values = Mat_<float>::zeros((4 + 9 + 16)*options.descriptor_channels, 1);
 
   vector<int> steps(3);
   steps.at(0) = options.descriptor_pattern_size;
@@ -1614,7 +1614,7 @@ void Upright_MLDB_Descriptor_Subset_Invoker::Get_Upright_MLDB_Descriptor_Subset(
  * @note The function keeps the 18 bits (3-channels by 6 comparisons) of the
  * coarser grid, since it provides the most robust estimations
  */
-void generateDescriptorSubsample(cv::Mat& sampleList, cv::Mat& comparisons, int nbits,
+void generateDescriptorSubsample(Mat& sampleList, Mat& comparisons, int nbits,
                                  int pattern_size, int nchannels) {
 
   int ssz = 0;
@@ -1718,4 +1718,3 @@ void generateDescriptorSubsample(cv::Mat& sampleList, cv::Mat& comparisons, int
 }
 
 }
-}
index 9119c97..14800bc 100644 (file)
 
 /* ************************************************************************* */
 // Includes
-#include "../precomp.hpp"
 #include "AKAZEConfig.h"
 #include "TEvolution.h"
 
+namespace cv
+{
+
 /* ************************************************************************* */
 // AKAZE Class Declaration
 class AKAZEFeatures {
@@ -22,7 +24,7 @@ class AKAZEFeatures {
 private:
 
   AKAZEOptions options_;                ///< Configuration options for AKAZE
-    std::vector<TEvolution> evolution_;        ///< Vector of nonlinear diffusion evolution
+  std::vector<TEvolution> evolution_;        ///< Vector of nonlinear diffusion evolution
 
   /// FED parameters
   int ncycles_;                  ///< Number of cycles
@@ -59,4 +61,6 @@ public:
 void generateDescriptorSubsample(cv::Mat& sampleList, cv::Mat& comparisons,
                                  int nbits, int pattern_size, int nchannels);
 
+}
+
 #endif
index 69e9a4b..702a8a0 100644 (file)
  * @date Jan 21, 2012
  * @author Pablo F. Alcantarilla
  */
-
+#include "../precomp.hpp"
 #include "KAZEFeatures.h"
 #include "utils.h"
 
+namespace cv
+{
+
 // Namespaces
 using namespace std;
-using namespace cv;
-using namespace cv::details::kaze;
 
 /* ************************************************************************* */
 /**
@@ -52,19 +53,20 @@ KAZEFeatures::KAZEFeatures(KAZEOptions& options)
 void KAZEFeatures::Allocate_Memory_Evolution(void) {
 
     // Allocate the dimension of the matrices for the evolution
-        for (int i = 0; i <= options_.omax - 1; i++) {
-                for (int j = 0; j <= options_.nsublevels - 1; j++) {
-
+    for (int i = 0; i <= options_.omax - 1; i++)
+    {
+        for (int j = 0; j <= options_.nsublevels - 1; j++)
+        {
             TEvolution aux;
-                        aux.Lx = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
-                        aux.Ly = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
-                        aux.Lxx = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
-                        aux.Lxy = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
-                        aux.Lyy = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
-                        aux.Lt = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
-                        aux.Lsmooth = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
-                        aux.Ldet = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
-                        aux.esigma = options_.soffset*pow((float)2.0f, (float)(j) / (float)(options_.nsublevels)+i);
+            aux.Lx = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
+            aux.Ly = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
+            aux.Lxx = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
+            aux.Lxy = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
+            aux.Lyy = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
+            aux.Lt = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
+            aux.Lsmooth = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
+            aux.Ldet = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
+            aux.esigma = options_.soffset*pow((float)2.0f, (float)(j) / (float)(options_.nsublevels)+i);
             aux.etime = 0.5f*(aux.esigma*aux.esigma);
             aux.sigma_size = fRound(aux.esigma);
             aux.octave = i;
@@ -74,7 +76,8 @@ void KAZEFeatures::Allocate_Memory_Evolution(void) {
     }
 
     // Allocate memory for the FED number of cycles and time steps
-    for (size_t i = 1; i < evolution_.size(); i++) {
+    for (size_t i = 1; i < evolution_.size(); i++)
+    {
         int naux = 0;
         vector<float> tau;
         float ttime = 0.0;
@@ -92,47 +95,43 @@ void KAZEFeatures::Allocate_Memory_Evolution(void) {
  * @param img Input image for which the nonlinear scale space needs to be created
  * @return 0 if the nonlinear scale space was created successfully. -1 otherwise
  */
-int KAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat &img)
+int KAZEFeatures::Create_Nonlinear_Scale_Space(const Mat &img)
 {
     CV_Assert(evolution_.size() > 0);
 
     // Copy the original image to the first level of the evolution
     img.copyTo(evolution_[0].Lt);
-        gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lt, 0, 0, options_.soffset);
-        gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lsmooth, 0, 0, options_.sderivatives);
+    gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lt, 0, 0, options_.soffset);
+    gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lsmooth, 0, 0, options_.sderivatives);
 
     // Firstly compute the kcontrast factor
         Compute_KContrast(evolution_[0].Lt, options_.kcontrast_percentille);
 
     // Allocate memory for the flow and step images
-    cv::Mat Lflow = cv::Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
-    cv::Mat Lstep = cv::Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
+    Mat Lflow = Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
+    Mat Lstep = Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
 
     // Now generate the rest of evolution levels
-    for (size_t i = 1; i < evolution_.size(); i++) {
-
+    for (size_t i = 1; i < evolution_.size(); i++)
+    {
         evolution_[i - 1].Lt.copyTo(evolution_[i].Lt);
-                gaussian_2D_convolution(evolution_[i - 1].Lt, evolution_[i].Lsmooth, 0, 0, options_.sderivatives);
+        gaussian_2D_convolution(evolution_[i - 1].Lt, evolution_[i].Lsmooth, 0, 0, options_.sderivatives);
 
         // Compute the Gaussian derivatives Lx and Ly
         Scharr(evolution_[i].Lsmooth, evolution_[i].Lx, CV_32F, 1, 0, 1, 0, BORDER_DEFAULT);
         Scharr(evolution_[i].Lsmooth, evolution_[i].Ly, CV_32F, 0, 1, 1, 0, BORDER_DEFAULT);
 
         // Compute the conductivity equation
-                if (options_.diffusivity == cv::DIFF_PM_G1) {
-                        pm_g1(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
-        }
-                else if (options_.diffusivity == cv::DIFF_PM_G2) {
-                        pm_g2(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
-        }
-                else if (options_.diffusivity == cv::DIFF_WEICKERT) {
-                        weickert_diffusivity(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
-        }
+        if (options_.diffusivity == KAZE::DIFF_PM_G1)
+            pm_g1(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
+        else if (options_.diffusivity == KAZE::DIFF_PM_G2)
+            pm_g2(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
+        else if (options_.diffusivity == KAZE::DIFF_WEICKERT)
+            weickert_diffusivity(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
 
         // Perform FED n inner steps
-        for (int j = 0; j < nsteps_[i - 1]; j++) {
+        for (int j = 0; j < nsteps_[i - 1]; j++)
             nld_step_scalar(evolution_[i].Lt, Lflow, Lstep, tsteps_[i - 1][j]);
-        }
     }
 
     return 0;
@@ -144,7 +143,7 @@ int KAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat &img)
  * @param img Input image
  * @param kpercentile Percentile of the gradient histogram
  */
-void KAZEFeatures::Compute_KContrast(const cv::Mat &img, const float &kpercentile)
+void KAZEFeatures::Compute_KContrast(const Mat &img, const float &kpercentile)
 {
         options_.kcontrast = compute_k_percentile(img, kpercentile, options_.sderivatives, options_.kcontrast_bins, 0, 0);
 }
@@ -181,7 +180,7 @@ void KAZEFeatures::Compute_Detector_Response(void)
  * @brief This method selects interesting keypoints through the nonlinear scale space
  * @param kpts Vector of keypoints
  */
-void KAZEFeatures::Feature_Detection(std::vector<cv::KeyPoint>& kpts)
+void KAZEFeatures::Feature_Detection(std::vector<KeyPoint>& kpts)
 {
     kpts.clear();
         Compute_Detector_Response();
@@ -190,14 +189,14 @@ void KAZEFeatures::Feature_Detection(std::vector<cv::KeyPoint>& kpts)
 }
 
 /* ************************************************************************* */
-class MultiscaleDerivativesKAZEInvoker : public cv::ParallelLoopBody
+class MultiscaleDerivativesKAZEInvoker : public ParallelLoopBody
 {
 public:
     explicit MultiscaleDerivativesKAZEInvoker(std::vector<TEvolution>& ev) : evolution_(&ev)
     {
     }
 
-    void operator()(const cv::Range& range) const
+    void operator()(const Range& range) const
     {
         std::vector<TEvolution>& evolution = *evolution_;
         for (int i = range.start; i < range.end; i++)
@@ -226,74 +225,79 @@ private:
  */
 void KAZEFeatures::Compute_Multiscale_Derivatives(void)
 {
-    cv::parallel_for_(cv::Range(0, (int)evolution_.size()),
+    parallel_for_(Range(0, (int)evolution_.size()),
                                         MultiscaleDerivativesKAZEInvoker(evolution_));
 }
 
 
 /* ************************************************************************* */
-class FindExtremumKAZEInvoker : public cv::ParallelLoopBody
+class FindExtremumKAZEInvoker : public ParallelLoopBody
 {
 public:
-    explicit FindExtremumKAZEInvoker(std::vector<TEvolution>& ev, std::vector<std::vector<cv::KeyPoint> >& kpts_par,
+    explicit FindExtremumKAZEInvoker(std::vector<TEvolution>& ev, std::vector<std::vector<KeyPoint> >& kpts_par,
                                                                      const KAZEOptions& options) : evolution_(&ev), kpts_par_(&kpts_par), options_(options)
     {
     }
 
-    void operator()(const cv::Range& range) const
+    void operator()(const Range& range) const
     {
         std::vector<TEvolution>& evolution = *evolution_;
-        std::vector<std::vector<cv::KeyPoint> >& kpts_par = *kpts_par_;
+        std::vector<std::vector<KeyPoint> >& kpts_par = *kpts_par_;
         for (int i = range.start; i < range.end; i++)
         {
             float value = 0.0;
             bool is_extremum = false;
 
-            for (int ix = 1; ix < options_.img_height - 1; ix++) {
-                    for (int jx = 1; jx < options_.img_width - 1; jx++) {
-
-                            is_extremum = false;
-                            value = *(evolution[i].Ldet.ptr<float>(ix)+jx);
-
-                            // Filter the points with the detector threshold
-                            if (value > options_.dthreshold) {
-                                    if (value >= *(evolution[i].Ldet.ptr<float>(ix)+jx - 1)) {
-                                            // First check on the same scale
-                                            if (check_maximum_neighbourhood(evolution[i].Ldet, 1, value, ix, jx, 1)) {
-                                                    // Now check on the lower scale
-                                                    if (check_maximum_neighbourhood(evolution[i - 1].Ldet, 1, value, ix, jx, 0)) {
-                                                            // Now check on the upper scale
-                                                            if (check_maximum_neighbourhood(evolution[i + 1].Ldet, 1, value, ix, jx, 0)) {
-                                                                    is_extremum = true;
-                                                            }
-                                                    }
-                                            }
-                                    }
+            for (int ix = 1; ix < options_.img_height - 1; ix++)
+            {
+                for (int jx = 1; jx < options_.img_width - 1; jx++)
+                {
+                    is_extremum = false;
+                    value = *(evolution[i].Ldet.ptr<float>(ix)+jx);
+
+                    // Filter the points with the detector threshold
+                    if (value > options_.dthreshold)
+                    {
+                        if (value >= *(evolution[i].Ldet.ptr<float>(ix)+jx - 1))
+                        {
+                            // First check on the same scale
+                            if (check_maximum_neighbourhood(evolution[i].Ldet, 1, value, ix, jx, 1))
+                            {
+                                // Now check on the lower scale
+                                if (check_maximum_neighbourhood(evolution[i - 1].Ldet, 1, value, ix, jx, 0))
+                                {
+                                    // Now check on the upper scale
+                                    if (check_maximum_neighbourhood(evolution[i + 1].Ldet, 1, value, ix, jx, 0))
+                                        is_extremum = true;
+                                }
                             }
+                        }
+                    }
 
-                            // Add the point of interest!!
-                            if (is_extremum == true) {
-                                    cv::KeyPoint point;
-                                    point.pt.x = (float)jx;
-                                    point.pt.y = (float)ix;
-                                    point.response = fabs(value);
-                                    point.size = evolution[i].esigma;
-                                    point.octave = (int)evolution[i].octave;
-                                    point.class_id = i;
-
-                                    // We use the angle field for the sublevel value
-                                    // Then, we will replace this angle field with the main orientation
-                                    point.angle = static_cast<float>(evolution[i].sublevel);
-                                    kpts_par[i - 1].push_back(point);
-                            }
+                    // Add the point of interest!!
+                    if (is_extremum)
+                    {
+                        KeyPoint point;
+                        point.pt.x = (float)jx;
+                        point.pt.y = (float)ix;
+                        point.response = fabs(value);
+                        point.size = evolution[i].esigma;
+                        point.octave = (int)evolution[i].octave;
+                        point.class_id = i;
+
+                        // We use the angle field for the sublevel value
+                        // Then, we will replace this angle field with the main orientation
+                        point.angle = static_cast<float>(evolution[i].sublevel);
+                        kpts_par[i - 1].push_back(point);
                     }
+                }
             }
         }
     }
 
 private:
     std::vector<TEvolution>*  evolution_;
-    std::vector<std::vector<cv::KeyPoint> >* kpts_par_;
+    std::vector<std::vector<KeyPoint> >* kpts_par_;
     KAZEOptions options_;
 };
 
@@ -304,7 +308,7 @@ private:
  * @param kpts Vector of keypoints
  * @note We compute features for each of the nonlinear scale space level in a different processing thread
  */
-void KAZEFeatures::Determinant_Hessian(std::vector<cv::KeyPoint>& kpts)
+void KAZEFeatures::Determinant_Hessian(std::vector<KeyPoint>& kpts)
 {
     int level = 0;
     float dist = 0.0, smax = 3.0;
@@ -325,12 +329,14 @@ void KAZEFeatures::Determinant_Hessian(std::vector<cv::KeyPoint>& kpts)
         kpts_par_.push_back(aux);
     }
 
-        cv::parallel_for_(cv::Range(1, (int)evolution_.size()-1),
-                                            FindExtremumKAZEInvoker(evolution_, kpts_par_, options_));
+    parallel_for_(Range(1, (int)evolution_.size()-1),
+                FindExtremumKAZEInvoker(evolution_, kpts_par_, options_));
 
     // Now fill the vector of keypoints!!!
-    for (int i = 0; i < (int)kpts_par_.size(); i++) {
-        for (int j = 0; j < (int)kpts_par_[i].size(); j++) {
+    for (int i = 0; i < (int)kpts_par_.size(); i++)
+    {
+        for (int j = 0; j < (int)kpts_par_[i].size(); j++)
+        {
             level = i + 1;
             is_extremum = true;
             is_repeated = false;
@@ -388,7 +394,7 @@ void KAZEFeatures::Determinant_Hessian(std::vector<cv::KeyPoint>& kpts)
  * @brief This method performs subpixel refinement of the detected keypoints
  * @param kpts Vector of detected keypoints
  */
-void KAZEFeatures::Do_Subpixel_Refinement(std::vector<cv::KeyPoint> &kpts) {
+void KAZEFeatures::Do_Subpixel_Refinement(std::vector<KeyPoint> &kpts) {
 
     int step = 1;
     int x = 0, y = 0;
@@ -482,10 +488,10 @@ void KAZEFeatures::Do_Subpixel_Refinement(std::vector<cv::KeyPoint> &kpts) {
 }
 
 /* ************************************************************************* */
-class KAZE_Descriptor_Invoker : public cv::ParallelLoopBody
+class KAZE_Descriptor_Invoker : public ParallelLoopBody
 {
 public:
-        KAZE_Descriptor_Invoker(std::vector<cv::KeyPoint> &kpts, cv::Mat &desc, std::vector<TEvolution>& evolution, const KAZEOptions& options)
+        KAZE_Descriptor_Invoker(std::vector<KeyPoint> &kpts, Mat &desc, std::vector<TEvolution>& evolution, const KAZEOptions& options)
                 : kpts_(&kpts)
                 , desc_(&desc)
                 , evolution_(&evolution)
@@ -497,10 +503,10 @@ public:
     {
     }
 
-    void operator() (const cv::Range& range) const
+    void operator() (const Range& range) const
     {
-                std::vector<cv::KeyPoint> &kpts      = *kpts_;
-                cv::Mat                   &desc      = *desc_;
+                std::vector<KeyPoint> &kpts      = *kpts_;
+                Mat                   &desc      = *desc_;
                 std::vector<TEvolution>   &evolution = *evolution_;
 
         for (int i = range.start; i < range.end; i++)
@@ -526,13 +532,13 @@ public:
         }
     }
 private:
-    void Get_KAZE_Upright_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const;
-    void Get_KAZE_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const;
-    void Get_KAZE_Upright_Descriptor_128(const cv::KeyPoint& kpt, float* desc) const;
-    void Get_KAZE_Descriptor_128(const cv::KeyPoint& kpt, float *desc) const;
+    void Get_KAZE_Upright_Descriptor_64(const KeyPoint& kpt, float* desc) const;
+    void Get_KAZE_Descriptor_64(const KeyPoint& kpt, float* desc) const;
+    void Get_KAZE_Upright_Descriptor_128(const KeyPoint& kpt, float* desc) const;
+    void Get_KAZE_Descriptor_128(const KeyPoint& kpt, float *desc) const;
 
-        std::vector<cv::KeyPoint> * kpts_;
-        cv::Mat                   * desc_;
+        std::vector<KeyPoint> * kpts_;
+        Mat                   * desc_;
         std::vector<TEvolution>   * evolution_;
         KAZEOptions                 options_;
 };
@@ -543,7 +549,7 @@ private:
  * @param kpts Vector of keypoints
  * @param desc Matrix with the feature descriptors
  */
-void KAZEFeatures::Feature_Description(std::vector<cv::KeyPoint> &kpts, cv::Mat &desc)
+void KAZEFeatures::Feature_Description(std::vector<KeyPoint> &kpts, Mat &desc)
 {
     for(size_t i = 0; i < kpts.size(); i++)
     {
@@ -558,7 +564,7 @@ void KAZEFeatures::Feature_Description(std::vector<cv::KeyPoint> &kpts, cv::Mat
         desc = Mat::zeros((int)kpts.size(), 64, CV_32FC1);
     }
 
-        cv::parallel_for_(cv::Range(0, (int)kpts.size()), KAZE_Descriptor_Invoker(kpts, desc, evolution_, options_));
+        parallel_for_(Range(0, (int)kpts.size()), KAZE_Descriptor_Invoker(kpts, desc, evolution_, options_));
 }
 
 /* ************************************************************************* */
@@ -568,7 +574,7 @@ void KAZEFeatures::Feature_Description(std::vector<cv::KeyPoint> &kpts, cv::Mat
  * @note The orientation is computed using a similar approach as described in the
  * original SURF method. See Bay et al., Speeded Up Robust Features, ECCV 2006
  */
-void KAZEFeatures::Compute_Main_Orientation(cv::KeyPoint &kpt, const std::vector<TEvolution>& evolution_, const KAZEOptions& options)
+void KAZEFeatures::Compute_Main_Orientation(KeyPoint &kpt, const std::vector<TEvolution>& evolution_, const KAZEOptions& options)
 {
     int ix = 0, iy = 0, idx = 0, s = 0, level = 0;
     float xf = 0.0, yf = 0.0, gweight = 0.0;
@@ -647,7 +653,7 @@ void KAZEFeatures::Compute_Main_Orientation(cv::KeyPoint &kpt, const std::vector
  * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
  * ECCV 2008
  */
-void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_64(const cv::KeyPoint &kpt, float *desc) const
+void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_64(const KeyPoint &kpt, float *desc) const
 {
     float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0;
     float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0;
@@ -775,7 +781,7 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_64(const cv::KeyPoint
  * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
  * ECCV 2008
  */
-void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const cv::KeyPoint &kpt, float *desc) const
+void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const KeyPoint &kpt, float *desc) const
 {
     float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0;
     float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0;
@@ -904,7 +910,7 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const cv::KeyPoint &kpt, fl
  * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
  * ECCV 2008
  */
-void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_128(const cv::KeyPoint &kpt, float *desc) const
+void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_128(const KeyPoint &kpt, float *desc) const
 {
     float gauss_s1 = 0.0, gauss_s2 = 0.0;
     float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0;
@@ -1056,7 +1062,7 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_128(const cv::KeyPoint
  * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
  * ECCV 2008
  */
-void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const cv::KeyPoint &kpt, float *desc) const
+void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const KeyPoint &kpt, float *desc) const
 {
     float gauss_s1 = 0.0, gauss_s2 = 0.0;
     float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0;
@@ -1202,3 +1208,5 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const cv::KeyPoint &kpt, f
         desc[i] /= len;
     }
 }
+
+}
index 98c8307..934dfff 100644 (file)
@@ -22,8 +22,8 @@ namespace cv
 
 /* ************************************************************************* */
 // KAZE Class Declaration
-class KAZEFeatures {
-
+class KAZEFeatures
+{
 private:
 
     /// Parameters of the Nonlinear diffusion class
index bc7654e..b033bce 100644 (file)
@@ -8,10 +8,13 @@
 #ifndef __OPENCV_FEATURES_2D_TEVOLUTION_H__
 #define __OPENCV_FEATURES_2D_TEVOLUTION_H__
 
+namespace cv
+{
+
 /* ************************************************************************* */
 /// KAZE/A-KAZE nonlinear diffusion filtering evolution
-struct TEvolution {
-
+struct TEvolution
+{
   TEvolution() {
     etime = 0.0f;
     esigma = 0.0f;
@@ -20,11 +23,11 @@ struct TEvolution {
     sigma_size = 0;
   }
 
-  cv::Mat Lx, Ly;           ///< First order spatial derivatives
-  cv::Mat Lxx, Lxy, Lyy;    ///< Second order spatial derivatives
-  cv::Mat Lt;               ///< Evolution image
-  cv::Mat Lsmooth;          ///< Smoothed image
-  cv::Mat Ldet;             ///< Detector response
+  Mat Lx, Ly;           ///< First order spatial derivatives
+  Mat Lxx, Lxy, Lyy;    ///< Second order spatial derivatives
+  Mat Lt;               ///< Evolution image
+  Mat Lsmooth;          ///< Smoothed image
+  Mat Ldet;             ///< Detector response
   float etime;              ///< Evolution time
   float esigma;             ///< Evolution sigma. For linear diffusion t = sigma^2 / 2
   int octave;               ///< Image octave
@@ -32,4 +35,6 @@ struct TEvolution {
   int sigma_size;           ///< Integer esigma. For computing the feature detector responses
 };
 
+}
+
 #endif
index 1c0d70a..85ed5de 100644 (file)
  * @author Pablo F. Alcantarilla
  */
 
+#include "../precomp.hpp"
 #include "nldiffusion_functions.h"
 #include <iostream>
 
 // Namespaces
+
+/* ************************************************************************* */
+
+namespace cv
+{
 using namespace std;
-using namespace cv;
 
 /* ************************************************************************* */
+/**
+ * @brief This function smoothes an image with a Gaussian kernel
+ * @param src Input image
+ * @param dst Output image
+ * @param ksize_x Kernel size in X-direction (horizontal)
+ * @param ksize_y Kernel size in Y-direction (vertical)
+ * @param sigma Kernel standard deviation
+ */
+void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int ksize_y, float sigma) {
 
-namespace cv {
-    namespace details {
-        namespace kaze {
-
-            /* ************************************************************************* */
-            /**
-             * @brief This function smoothes an image with a Gaussian kernel
-             * @param src Input image
-             * @param dst Output image
-             * @param ksize_x Kernel size in X-direction (horizontal)
-             * @param ksize_y Kernel size in Y-direction (vertical)
-             * @param sigma Kernel standard deviation
-             */
-            void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int ksize_y, float sigma) {
-
-                int ksize_x_ = 0, ksize_y_ = 0;
-
-                // Compute an appropriate kernel size according to the specified sigma
-                if (sigma > ksize_x || sigma > ksize_y || ksize_x == 0 || ksize_y == 0) {
-                    ksize_x_ = (int)ceil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f)));
-                    ksize_y_ = ksize_x_;
-                }
+    int ksize_x_ = 0, ksize_y_ = 0;
 
-                // The kernel size must be and odd number
-                if ((ksize_x_ % 2) == 0) {
-                    ksize_x_ += 1;
-                }
+    // Compute an appropriate kernel size according to the specified sigma
+    if (sigma > ksize_x || sigma > ksize_y || ksize_x == 0 || ksize_y == 0) {
+        ksize_x_ = (int)ceil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f)));
+        ksize_y_ = ksize_x_;
+    }
 
-                if ((ksize_y_ % 2) == 0) {
-                    ksize_y_ += 1;
-                }
+    // The kernel size must be and odd number
+    if ((ksize_x_ % 2) == 0) {
+        ksize_x_ += 1;
+    }
 
-                // Perform the Gaussian Smoothing with border replication
-                GaussianBlur(src, dst, Size(ksize_x_, ksize_y_), sigma, sigma, BORDER_REPLICATE);
-            }
+    if ((ksize_y_ % 2) == 0) {
+        ksize_y_ += 1;
+    }
 
-            /* ************************************************************************* */
-            /**
-             * @brief This function computes image derivatives with Scharr kernel
-             * @param src Input image
-             * @param dst Output image
-             * @param xorder Derivative order in X-direction (horizontal)
-             * @param yorder Derivative order in Y-direction (vertical)
-             * @note Scharr operator approximates better rotation invariance than
-             * other stencils such as Sobel. See Weickert and Scharr,
-             * A Scheme for Coherence-Enhancing Diffusion Filtering with Optimized Rotation Invariance,
-             * Journal of Visual Communication and Image Representation 2002
-             */
-            void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder) {
-                Scharr(src, dst, CV_32F, xorder, yorder, 1.0, 0, BORDER_DEFAULT);
-            }
+    // Perform the Gaussian Smoothing with border replication
+    GaussianBlur(src, dst, Size(ksize_x_, ksize_y_), sigma, sigma, BORDER_REPLICATE);
+}
 
-            /* ************************************************************************* */
-            /**
-             * @brief This function computes the Perona and Malik conductivity coefficient g1
-             * g1 = exp(-|dL|^2/k^2)
-             * @param Lx First order image derivative in X-direction (horizontal)
-             * @param Ly First order image derivative in Y-direction (vertical)
-             * @param dst Output image
-             * @param k Contrast factor parameter
-             */
-            void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k) {
-
-              Size sz = Lx.size();
-              float inv_k = 1.0f / (k*k);
-              for (int y = 0; y < sz.height; y++) {
-
-                const float* Lx_row = Lx.ptr<float>(y);
-                const float* Ly_row = Ly.ptr<float>(y);
-                float* dst_row = dst.ptr<float>(y);
-
-                for (int x = 0; x < sz.width; x++) {
-                  dst_row[x] = (-inv_k*(Lx_row[x]*Lx_row[x] + Ly_row[x]*Ly_row[x]));
-                }
-              }
+/* ************************************************************************* */
+/**
+ * @brief This function computes image derivatives with Scharr kernel
+ * @param src Input image
+ * @param dst Output image
+ * @param xorder Derivative order in X-direction (horizontal)
+ * @param yorder Derivative order in Y-direction (vertical)
+ * @note Scharr operator approximates better rotation invariance than
+ * other stencils such as Sobel. See Weickert and Scharr,
+ * A Scheme for Coherence-Enhancing Diffusion Filtering with Optimized Rotation Invariance,
+ * Journal of Visual Communication and Image Representation 2002
+ */
+void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder) {
+    Scharr(src, dst, CV_32F, xorder, yorder, 1.0, 0, BORDER_DEFAULT);
+}
 
-              exp(dst, dst);
-            }
+/* ************************************************************************* */
+/**
+ * @brief This function computes the Perona and Malik conductivity coefficient g1
+ * g1 = exp(-|dL|^2/k^2)
+ * @param Lx First order image derivative in X-direction (horizontal)
+ * @param Ly First order image derivative in Y-direction (vertical)
+ * @param dst Output image
+ * @param k Contrast factor parameter
+ */
+void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k) {
 
-            /* ************************************************************************* */
-            /**
-             * @brief This function computes the Perona and Malik conductivity coefficient g2
-             * g2 = 1 / (1 + dL^2 / k^2)
-             * @param Lx First order image derivative in X-direction (horizontal)
-             * @param Ly First order image derivative in Y-direction (vertical)
-             * @param dst Output image
-             * @param k Contrast factor parameter
-             */
-            void pm_g2(const cv::Mat &Lx, const cv::Mat& Ly, cv::Mat& dst, float k) {
-
-                Size sz = Lx.size();
-                dst.create(sz, Lx.type());
-                float k2inv = 1.0f / (k * k);
-
-                for(int y = 0; y < sz.height; y++) {
-                    const float *Lx_row = Lx.ptr<float>(y);
-                    const float *Ly_row = Ly.ptr<float>(y);
-                    float* dst_row = dst.ptr<float>(y);
-                    for(int x = 0; x < sz.width; x++) {
-                        dst_row[x] = 1.0f / (1.0f + ((Lx_row[x] * Lx_row[x] + Ly_row[x] * Ly_row[x]) * k2inv));
-                    }
-                }
-            }
-            /* ************************************************************************* */
-            /**
-             * @brief This function computes Weickert conductivity coefficient gw
-             * @param Lx First order image derivative in X-direction (horizontal)
-             * @param Ly First order image derivative in Y-direction (vertical)
-             * @param dst Output image
-             * @param k Contrast factor parameter
-             * @note For more information check the following paper: J. Weickert
-             * Applications of nonlinear diffusion in image processing and computer vision,
-             * Proceedings of Algorithmy 2000
-             */
-            void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k) {
-
-              Size sz = Lx.size();
-              float inv_k = 1.0f / (k*k);
-              for (int y = 0; y < sz.height; y++) {
-
-                const float* Lx_row = Lx.ptr<float>(y);
-                const float* Ly_row = Ly.ptr<float>(y);
-                float* dst_row = dst.ptr<float>(y);
-
-                for (int x = 0; x < sz.width; x++) {
-                  float dL = inv_k*(Lx_row[x]*Lx_row[x] + Ly_row[x]*Ly_row[x]);
-                  dst_row[x] = -3.315f/(dL*dL*dL*dL);
-                }
-              }
+  Size sz = Lx.size();
+  float inv_k = 1.0f / (k*k);
+  for (int y = 0; y < sz.height; y++) {
 
-              exp(dst, dst);
-              dst = 1.0 - dst;
-            }
+    const float* Lx_row = Lx.ptr<float>(y);
+    const float* Ly_row = Ly.ptr<float>(y);
+    float* dst_row = dst.ptr<float>(y);
 
+    for (int x = 0; x < sz.width; x++) {
+      dst_row[x] = (-inv_k*(Lx_row[x]*Lx_row[x] + Ly_row[x]*Ly_row[x]));
+    }
+  }
 
-            /* ************************************************************************* */
-            /**
-            * @brief This function computes Charbonnier conductivity coefficient gc
-            * gc = 1 / sqrt(1 + dL^2 / k^2)
-            * @param Lx First order image derivative in X-direction (horizontal)
-            * @param Ly First order image derivative in Y-direction (vertical)
-            * @param dst Output image
-            * @param k Contrast factor parameter
-            * @note For more information check the following paper: J. Weickert
-            * Applications of nonlinear diffusion in image processing and computer vision,
-            * Proceedings of Algorithmy 2000
-            */
-            void charbonnier_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k) {
-
-              Size sz = Lx.size();
-              float inv_k = 1.0f / (k*k);
-              for (int y = 0; y < sz.height; y++) {
-
-                const float* Lx_row = Lx.ptr<float>(y);
-                const float* Ly_row = Ly.ptr<float>(y);
-                float* dst_row = dst.ptr<float>(y);
-
-                for (int x = 0; x < sz.width; x++) {
-                  float den = sqrt(1.0f+inv_k*(Lx_row[x]*Lx_row[x] + Ly_row[x]*Ly_row[x]));
-                  dst_row[x] = 1.0f / den;
-                }
-              }
-            }
+  exp(dst, dst);
+}
 
+/* ************************************************************************* */
+/**
+ * @brief This function computes the Perona and Malik conductivity coefficient g2
+ * g2 = 1 / (1 + dL^2 / k^2)
+ * @param Lx First order image derivative in X-direction (horizontal)
+ * @param Ly First order image derivative in Y-direction (vertical)
+ * @param dst Output image
+ * @param k Contrast factor parameter
+ */
+void pm_g2(const cv::Mat &Lx, const cv::Mat& Ly, cv::Mat& dst, float k) {
+
+    Size sz = Lx.size();
+    dst.create(sz, Lx.type());
+    float k2inv = 1.0f / (k * k);
+
+    for(int y = 0; y < sz.height; y++) {
+        const float *Lx_row = Lx.ptr<float>(y);
+        const float *Ly_row = Ly.ptr<float>(y);
+        float* dst_row = dst.ptr<float>(y);
+        for(int x = 0; x < sz.width; x++) {
+            dst_row[x] = 1.0f / (1.0f + ((Lx_row[x] * Lx_row[x] + Ly_row[x] * Ly_row[x]) * k2inv));
+        }
+    }
+}
+/* ************************************************************************* */
+/**
+ * @brief This function computes Weickert conductivity coefficient gw
+ * @param Lx First order image derivative in X-direction (horizontal)
+ * @param Ly First order image derivative in Y-direction (vertical)
+ * @param dst Output image
+ * @param k Contrast factor parameter
+ * @note For more information check the following paper: J. Weickert
+ * Applications of nonlinear diffusion in image processing and computer vision,
+ * Proceedings of Algorithmy 2000
+ */
+void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k) {
 
-            /* ************************************************************************* */
-            /**
-             * @brief This function computes a good empirical value for the k contrast factor
-             * given an input image, the percentile (0-1), the gradient scale and the number of
-             * bins in the histogram
-             * @param img Input image
-             * @param perc Percentile of the image gradient histogram (0-1)
-             * @param gscale Scale for computing the image gradient histogram
-             * @param nbins Number of histogram bins
-             * @param ksize_x Kernel size in X-direction (horizontal) for the Gaussian smoothing kernel
-             * @param ksize_y Kernel size in Y-direction (vertical) for the Gaussian smoothing kernel
-             * @return k contrast factor
-             */
-            float compute_k_percentile(const cv::Mat& img, float perc, float gscale, int nbins, int ksize_x, int ksize_y) {
-
-                int nbin = 0, nelements = 0, nthreshold = 0, k = 0;
-                float kperc = 0.0, modg = 0.0;
-                float npoints = 0.0;
-                float hmax = 0.0;
-
-                // Create the array for the histogram
-                std::vector<int> hist(nbins, 0);
-
-                // Create the matrices
-                Mat gaussian = Mat::zeros(img.rows, img.cols, CV_32F);
-                Mat Lx = Mat::zeros(img.rows, img.cols, CV_32F);
-                Mat Ly = Mat::zeros(img.rows, img.cols, CV_32F);
-
-                // Perform the Gaussian convolution
-                gaussian_2D_convolution(img, gaussian, ksize_x, ksize_y, gscale);
-
-                // Compute the Gaussian derivatives Lx and Ly
-                Scharr(gaussian, Lx, CV_32F, 1, 0, 1, 0, cv::BORDER_DEFAULT);
-                Scharr(gaussian, Ly, CV_32F, 0, 1, 1, 0, cv::BORDER_DEFAULT);
-
-                // Skip the borders for computing the histogram
-                for (int i = 1; i < gaussian.rows - 1; i++) {
-                    const float *lx = Lx.ptr<float>(i);
-                    const float *ly = Ly.ptr<float>(i);
-                    for (int j = 1; j < gaussian.cols - 1; j++) {
-                        modg = lx[j]*lx[j] + ly[j]*ly[j];
-
-                        // Get the maximum
-                        if (modg > hmax) {
-                            hmax = modg;
-                        }
-                    }
-                }
-                hmax = sqrt(hmax);
-                // Skip the borders for computing the histogram
-                for (int i = 1; i < gaussian.rows - 1; i++) {
-                    const float *lx = Lx.ptr<float>(i);
-                    const float *ly = Ly.ptr<float>(i);
-                    for (int j = 1; j < gaussian.cols - 1; j++) {
-                        modg = lx[j]*lx[j] + ly[j]*ly[j];
-
-                        // Find the correspondent bin
-                        if (modg != 0.0) {
-                            nbin = (int)floor(nbins*(sqrt(modg) / hmax));
-
-                            if (nbin == nbins) {
-                                nbin--;
-                            }
-
-                            hist[nbin]++;
-                            npoints++;
-                        }
-                    }
-                }
+  Size sz = Lx.size();
+  float inv_k = 1.0f / (k*k);
+  for (int y = 0; y < sz.height; y++) {
 
-                // Now find the perc of the histogram percentile
-                nthreshold = (int)(npoints*perc);
+    const float* Lx_row = Lx.ptr<float>(y);
+    const float* Ly_row = Ly.ptr<float>(y);
+    float* dst_row = dst.ptr<float>(y);
 
-                for (k = 0; nelements < nthreshold && k < nbins; k++) {
-                    nelements = nelements + hist[k];
-                }
+    for (int x = 0; x < sz.width; x++) {
+      float dL = inv_k*(Lx_row[x]*Lx_row[x] + Ly_row[x]*Ly_row[x]);
+      dst_row[x] = -3.315f/(dL*dL*dL*dL);
+    }
+  }
 
-                if (nelements < nthreshold)  {
-                    kperc = 0.03f;
-                }
-                else {
-                    kperc = hmax*((float)(k) / (float)nbins);
-                }
+  exp(dst, dst);
+  dst = 1.0 - dst;
+}
+
+
+/* ************************************************************************* */
+/**
+* @brief This function computes Charbonnier conductivity coefficient gc
+* gc = 1 / sqrt(1 + dL^2 / k^2)
+* @param Lx First order image derivative in X-direction (horizontal)
+* @param Ly First order image derivative in Y-direction (vertical)
+* @param dst Output image
+* @param k Contrast factor parameter
+* @note For more information check the following paper: J. Weickert
+* Applications of nonlinear diffusion in image processing and computer vision,
+* Proceedings of Algorithmy 2000
+*/
+void charbonnier_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k) {
+
+  Size sz = Lx.size();
+  float inv_k = 1.0f / (k*k);
+  for (int y = 0; y < sz.height; y++) {
+
+    const float* Lx_row = Lx.ptr<float>(y);
+    const float* Ly_row = Ly.ptr<float>(y);
+    float* dst_row = dst.ptr<float>(y);
+
+    for (int x = 0; x < sz.width; x++) {
+      float den = sqrt(1.0f+inv_k*(Lx_row[x]*Lx_row[x] + Ly_row[x]*Ly_row[x]));
+      dst_row[x] = 1.0f / den;
+    }
+  }
+}
 
-                return kperc;
+
+/* ************************************************************************* */
+/**
+ * @brief This function computes a good empirical value for the k contrast factor
+ * given an input image, the percentile (0-1), the gradient scale and the number of
+ * bins in the histogram
+ * @param img Input image
+ * @param perc Percentile of the image gradient histogram (0-1)
+ * @param gscale Scale for computing the image gradient histogram
+ * @param nbins Number of histogram bins
+ * @param ksize_x Kernel size in X-direction (horizontal) for the Gaussian smoothing kernel
+ * @param ksize_y Kernel size in Y-direction (vertical) for the Gaussian smoothing kernel
+ * @return k contrast factor
+ */
+float compute_k_percentile(const cv::Mat& img, float perc, float gscale, int nbins, int ksize_x, int ksize_y) {
+
+    int nbin = 0, nelements = 0, nthreshold = 0, k = 0;
+    float kperc = 0.0, modg = 0.0;
+    float npoints = 0.0;
+    float hmax = 0.0;
+
+    // Create the array for the histogram
+    std::vector<int> hist(nbins, 0);
+
+    // Create the matrices
+    Mat gaussian = Mat::zeros(img.rows, img.cols, CV_32F);
+    Mat Lx = Mat::zeros(img.rows, img.cols, CV_32F);
+    Mat Ly = Mat::zeros(img.rows, img.cols, CV_32F);
+
+    // Perform the Gaussian convolution
+    gaussian_2D_convolution(img, gaussian, ksize_x, ksize_y, gscale);
+
+    // Compute the Gaussian derivatives Lx and Ly
+    Scharr(gaussian, Lx, CV_32F, 1, 0, 1, 0, cv::BORDER_DEFAULT);
+    Scharr(gaussian, Ly, CV_32F, 0, 1, 1, 0, cv::BORDER_DEFAULT);
+
+    // Skip the borders for computing the histogram
+    for (int i = 1; i < gaussian.rows - 1; i++) {
+        const float *lx = Lx.ptr<float>(i);
+        const float *ly = Ly.ptr<float>(i);
+        for (int j = 1; j < gaussian.cols - 1; j++) {
+            modg = lx[j]*lx[j] + ly[j]*ly[j];
+
+            // Get the maximum
+            if (modg > hmax) {
+                hmax = modg;
             }
+        }
+    }
+    hmax = sqrt(hmax);
+    // Skip the borders for computing the histogram
+    for (int i = 1; i < gaussian.rows - 1; i++) {
+        const float *lx = Lx.ptr<float>(i);
+        const float *ly = Ly.ptr<float>(i);
+        for (int j = 1; j < gaussian.cols - 1; j++) {
+            modg = lx[j]*lx[j] + ly[j]*ly[j];
+
+            // Find the correspondent bin
+            if (modg != 0.0) {
+                nbin = (int)floor(nbins*(sqrt(modg) / hmax));
+
+                if (nbin == nbins) {
+                    nbin--;
+                }
 
-            /* ************************************************************************* */
-            /**
-             * @brief This function computes Scharr image derivatives
-             * @param src Input image
-             * @param dst Output image
-             * @param xorder Derivative order in X-direction (horizontal)
-             * @param yorder Derivative order in Y-direction (vertical)
-             * @param scale Scale factor for the derivative size
-             */
-            void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder, int scale) {
-                Mat kx, ky;
-                compute_derivative_kernels(kx, ky, xorder, yorder, scale);
-                sepFilter2D(src, dst, CV_32F, kx, ky);
+                hist[nbin]++;
+                npoints++;
             }
+        }
+    }
 
-            /* ************************************************************************* */
-            /**
-             * @brief Compute derivative kernels for sizes different than 3
-             * @param _kx Horizontal kernel ues
-             * @param _ky Vertical kernel values
-             * @param dx Derivative order in X-direction (horizontal)
-             * @param dy Derivative order in Y-direction (vertical)
-             * @param scale_ Scale factor or derivative size
-             */
-            void compute_derivative_kernels(cv::OutputArray _kx, cv::OutputArray _ky, int dx, int dy, int scale) {
-
-                int ksize = 3 + 2 * (scale - 1);
-
-                // The standard Scharr kernel
-                if (scale == 1) {
-                    getDerivKernels(_kx, _ky, dx, dy, 0, true, CV_32F);
-                    return;
-                }
+    // Now find the perc of the histogram percentile
+    nthreshold = (int)(npoints*perc);
 
-                _kx.create(ksize, 1, CV_32F, -1, true);
-                _ky.create(ksize, 1, CV_32F, -1, true);
-                Mat kx = _kx.getMat();
-                Mat ky = _ky.getMat();
+    for (k = 0; nelements < nthreshold && k < nbins; k++) {
+        nelements = nelements + hist[k];
+    }
 
-                float w = 10.0f / 3.0f;
-                float norm = 1.0f / (2.0f*scale*(w + 2.0f));
+    if (nelements < nthreshold)  {
+        kperc = 0.03f;
+    }
+    else {
+        kperc = hmax*((float)(k) / (float)nbins);
+    }
 
-                for (int k = 0; k < 2; k++) {
-                    Mat* kernel = k == 0 ? &kx : &ky;
-                    int order = k == 0 ? dx : dy;
-                    std::vector<float> kerI(ksize, 0.0f);
+    return kperc;
+}
 
-                    if (order == 0) {
-                        kerI[0] = norm, kerI[ksize / 2] = w*norm, kerI[ksize - 1] = norm;
-                    }
-                    else if (order == 1) {
-                        kerI[0] = -1, kerI[ksize / 2] = 0, kerI[ksize - 1] = 1;
-                    }
+/* ************************************************************************* */
+/**
+ * @brief This function computes Scharr image derivatives
+ * @param src Input image
+ * @param dst Output image
+ * @param xorder Derivative order in X-direction (horizontal)
+ * @param yorder Derivative order in Y-direction (vertical)
+ * @param scale Scale factor for the derivative size
+ */
+void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder, int scale) {
+    Mat kx, ky;
+    compute_derivative_kernels(kx, ky, xorder, yorder, scale);
+    sepFilter2D(src, dst, CV_32F, kx, ky);
+}
 
-                    Mat temp(kernel->rows, kernel->cols, CV_32F, &kerI[0]);
-                    temp.copyTo(*kernel);
-                }
-            }
+/* ************************************************************************* */
+/**
+ * @brief Compute derivative kernels for sizes different than 3
+ * @param _kx Horizontal kernel ues
+ * @param _ky Vertical kernel values
+ * @param dx Derivative order in X-direction (horizontal)
+ * @param dy Derivative order in Y-direction (vertical)
+ * @param scale_ Scale factor or derivative size
+ */
+void compute_derivative_kernels(cv::OutputArray _kx, cv::OutputArray _ky, int dx, int dy, int scale) {
 
-            class Nld_Step_Scalar_Invoker : public cv::ParallelLoopBody
-            {
-            public:
-                Nld_Step_Scalar_Invoker(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float _stepsize)
-                    : _Ld(&Ld)
-                    , _c(&c)
-                    , _Lstep(&Lstep)
-                    , stepsize(_stepsize)
-                {
-                }
+    int ksize = 3 + 2 * (scale - 1);
 
-                virtual ~Nld_Step_Scalar_Invoker()
-                {
+    // The standard Scharr kernel
+    if (scale == 1) {
+        getDerivKernels(_kx, _ky, dx, dy, 0, true, CV_32F);
+        return;
+    }
 
-                }
+    _kx.create(ksize, 1, CV_32F, -1, true);
+    _ky.create(ksize, 1, CV_32F, -1, true);
+    Mat kx = _kx.getMat();
+    Mat ky = _ky.getMat();
 
-                void operator()(const cv::Range& range) const
-                {
-                    cv::Mat& Ld = *_Ld;
-                    const cv::Mat& c = *_c;
-                    cv::Mat& Lstep = *_Lstep;
-
-                    for (int i = range.start; i < range.end; i++)
-                    {
-                        const float *c_prev  = c.ptr<float>(i - 1);
-                        const float *c_curr  = c.ptr<float>(i);
-                        const float *c_next  = c.ptr<float>(i + 1);
-                        const float *ld_prev = Ld.ptr<float>(i - 1);
-                        const float *ld_curr = Ld.ptr<float>(i);
-                        const float *ld_next = Ld.ptr<float>(i + 1);
-
-                        float *dst  = Lstep.ptr<float>(i);
-
-                        for (int j = 1; j < Lstep.cols - 1; j++)
-                        {
-                            float xpos = (c_curr[j]   + c_curr[j+1])*(ld_curr[j+1] - ld_curr[j]);
-                            float xneg = (c_curr[j-1] + c_curr[j])  *(ld_curr[j]   - ld_curr[j-1]);
-                            float ypos = (c_curr[j]   + c_next[j])  *(ld_next[j]   - ld_curr[j]);
-                            float yneg = (c_prev[j]   + c_curr[j])  *(ld_curr[j]   - ld_prev[j]);
-                            dst[j] = 0.5f*stepsize*(xpos - xneg + ypos - yneg);
-                        }
-                    }
-                }
-            private:
-                cv::Mat * _Ld;
-                const cv::Mat * _c;
-                cv::Mat * _Lstep;
-                float stepsize;
-            };
-
-            /* ************************************************************************* */
-            /**
-            * @brief This function performs a scalar non-linear diffusion step
-            * @param Ld2 Output image in the evolution
-            * @param c Conductivity image
-            * @param Lstep Previous image in the evolution
-            * @param stepsize The step size in time units
-            * @note Forward Euler Scheme 3x3 stencil
-            * The function c is a scalar value that depends on the gradient norm
-            * dL_by_ds = d(c dL_by_dx)_by_dx + d(c dL_by_dy)_by_dy
-            */
-            void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float stepsize) {
-
-                cv::parallel_for_(cv::Range(1, Lstep.rows - 1), Nld_Step_Scalar_Invoker(Ld, c, Lstep, stepsize), (double)Ld.total()/(1 << 16));
-
-                float xneg, xpos, yneg, ypos;
-                float* dst = Lstep.ptr<float>(0);
-                const float* cprv = NULL;
-                const float* ccur  = c.ptr<float>(0);
-                const float* cnxt  = c.ptr<float>(1);
-                const float* ldprv = NULL;
-                const float* ldcur = Ld.ptr<float>(0);
-                const float* ldnxt = Ld.ptr<float>(1);
-                for (int j = 1; j < Lstep.cols - 1; j++) {
-                    xpos = (ccur[j]   + ccur[j+1]) * (ldcur[j+1] - ldcur[j]);
-                    xneg = (ccur[j-1] + ccur[j])   * (ldcur[j]   - ldcur[j-1]);
-                    ypos = (ccur[j]   + cnxt[j])   * (ldnxt[j]   - ldcur[j]);
-                    dst[j] = 0.5f*stepsize*(xpos - xneg + ypos);
-                }
+    float w = 10.0f / 3.0f;
+    float norm = 1.0f / (2.0f*scale*(w + 2.0f));
 
-                dst = Lstep.ptr<float>(Lstep.rows - 1);
-                ccur = c.ptr<float>(Lstep.rows - 1);
-                cprv = c.ptr<float>(Lstep.rows - 2);
-                ldcur = Ld.ptr<float>(Lstep.rows - 1);
-                ldprv = Ld.ptr<float>(Lstep.rows - 2);
-
-                for (int j = 1; j < Lstep.cols - 1; j++) {
-                    xpos = (ccur[j] + ccur[j+1]) * (ldcur[j+1] - ldcur[j]);
-                    xneg = (ccur[j-1] + ccur[j]) * (ldcur[j] - ldcur[j-1]);
-                    yneg = (cprv[j] + ccur[j])   * (ldcur[j] - ldprv[j]);
-                    dst[j] = 0.5f*stepsize*(xpos - xneg - yneg);
-                }
+    for (int k = 0; k < 2; k++) {
+        Mat* kernel = k == 0 ? &kx : &ky;
+        int order = k == 0 ? dx : dy;
+        std::vector<float> kerI(ksize, 0.0f);
 
-                ccur = c.ptr<float>(1);
-                ldcur = Ld.ptr<float>(1);
-                cprv = c.ptr<float>(0);
-                ldprv = Ld.ptr<float>(0);
-
-                int r0 = Lstep.cols - 1;
-                int r1 = Lstep.cols - 2;
-
-                for (int i = 1; i < Lstep.rows - 1; i++) {
-                    cnxt = c.ptr<float>(i + 1);
-                    ldnxt = Ld.ptr<float>(i + 1);
-                    dst = Lstep.ptr<float>(i);
-
-                    xpos = (ccur[0] + ccur[1]) * (ldcur[1] - ldcur[0]);
-                    ypos = (ccur[0] + cnxt[0]) * (ldnxt[0] - ldcur[0]);
-                    yneg = (cprv[0] + ccur[0]) * (ldcur[0] - ldprv[0]);
-                    dst[0] = 0.5f*stepsize*(xpos + ypos - yneg);
-
-                    xneg = (ccur[r1] + ccur[r0]) * (ldcur[r0] - ldcur[r1]);
-                    ypos = (ccur[r0] + cnxt[r0]) * (ldnxt[r0] - ldcur[r0]);
-                    yneg = (cprv[r0] + ccur[r0]) * (ldcur[r0] - ldprv[r0]);
-                    dst[r0] = 0.5f*stepsize*(-xneg + ypos - yneg);
-
-                    cprv = ccur;
-                    ccur = cnxt;
-                    ldprv = ldcur;
-                    ldcur = ldnxt;
-                }
-                Ld += Lstep;
-            }
+        if (order == 0) {
+            kerI[0] = norm, kerI[ksize / 2] = w*norm, kerI[ksize - 1] = norm;
+        }
+        else if (order == 1) {
+            kerI[0] = -1, kerI[ksize / 2] = 0, kerI[ksize - 1] = 1;
+        }
 
-            /* ************************************************************************* */
-            /**
-            * @brief This function downsamples the input image using OpenCV resize
-            * @param img Input image to be downsampled
-            * @param dst Output image with half of the resolution of the input image
-            */
-            void halfsample_image(const cv::Mat& src, cv::Mat& dst) {
-
-                // Make sure the destination image is of the right size
-                CV_Assert(src.cols / 2 == dst.cols);
-                CV_Assert(src.rows / 2 == dst.rows);
-                resize(src, dst, dst.size(), 0, 0, cv::INTER_AREA);
+        Mat temp(kernel->rows, kernel->cols, CV_32F, &kerI[0]);
+        temp.copyTo(*kernel);
+    }
+}
+
+class Nld_Step_Scalar_Invoker : public cv::ParallelLoopBody
+{
+public:
+    Nld_Step_Scalar_Invoker(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float _stepsize)
+        : _Ld(&Ld)
+        , _c(&c)
+        , _Lstep(&Lstep)
+        , stepsize(_stepsize)
+    {
+    }
+
+    virtual ~Nld_Step_Scalar_Invoker()
+    {
+
+    }
+
+    void operator()(const cv::Range& range) const
+    {
+        cv::Mat& Ld = *_Ld;
+        const cv::Mat& c = *_c;
+        cv::Mat& Lstep = *_Lstep;
+
+        for (int i = range.start; i < range.end; i++)
+        {
+            const float *c_prev  = c.ptr<float>(i - 1);
+            const float *c_curr  = c.ptr<float>(i);
+            const float *c_next  = c.ptr<float>(i + 1);
+            const float *ld_prev = Ld.ptr<float>(i - 1);
+            const float *ld_curr = Ld.ptr<float>(i);
+            const float *ld_next = Ld.ptr<float>(i + 1);
+
+            float *dst  = Lstep.ptr<float>(i);
+
+            for (int j = 1; j < Lstep.cols - 1; j++)
+            {
+                float xpos = (c_curr[j]   + c_curr[j+1])*(ld_curr[j+1] - ld_curr[j]);
+                float xneg = (c_curr[j-1] + c_curr[j])  *(ld_curr[j]   - ld_curr[j-1]);
+                float ypos = (c_curr[j]   + c_next[j])  *(ld_next[j]   - ld_curr[j]);
+                float yneg = (c_prev[j]   + c_curr[j])  *(ld_curr[j]   - ld_prev[j]);
+                dst[j] = 0.5f*stepsize*(xpos - xneg + ypos - yneg);
             }
+        }
+    }
+private:
+    cv::Mat * _Ld;
+    const cv::Mat * _c;
+    cv::Mat * _Lstep;
+    float stepsize;
+};
+
+/* ************************************************************************* */
+/**
+* @brief This function performs a scalar non-linear diffusion step
+* @param Ld2 Output image in the evolution
+* @param c Conductivity image
+* @param Lstep Previous image in the evolution
+* @param stepsize The step size in time units
+* @note Forward Euler Scheme 3x3 stencil
+* The function c is a scalar value that depends on the gradient norm
+* dL_by_ds = d(c dL_by_dx)_by_dx + d(c dL_by_dy)_by_dy
+*/
+void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float stepsize) {
+
+    cv::parallel_for_(cv::Range(1, Lstep.rows - 1), Nld_Step_Scalar_Invoker(Ld, c, Lstep, stepsize), (double)Ld.total()/(1 << 16));
+
+    float xneg, xpos, yneg, ypos;
+    float* dst = Lstep.ptr<float>(0);
+    const float* cprv = NULL;
+    const float* ccur  = c.ptr<float>(0);
+    const float* cnxt  = c.ptr<float>(1);
+    const float* ldprv = NULL;
+    const float* ldcur = Ld.ptr<float>(0);
+    const float* ldnxt = Ld.ptr<float>(1);
+    for (int j = 1; j < Lstep.cols - 1; j++) {
+        xpos = (ccur[j]   + ccur[j+1]) * (ldcur[j+1] - ldcur[j]);
+        xneg = (ccur[j-1] + ccur[j])   * (ldcur[j]   - ldcur[j-1]);
+        ypos = (ccur[j]   + cnxt[j])   * (ldnxt[j]   - ldcur[j]);
+        dst[j] = 0.5f*stepsize*(xpos - xneg + ypos);
+    }
+
+    dst = Lstep.ptr<float>(Lstep.rows - 1);
+    ccur = c.ptr<float>(Lstep.rows - 1);
+    cprv = c.ptr<float>(Lstep.rows - 2);
+    ldcur = Ld.ptr<float>(Lstep.rows - 1);
+    ldprv = Ld.ptr<float>(Lstep.rows - 2);
+
+    for (int j = 1; j < Lstep.cols - 1; j++) {
+        xpos = (ccur[j] + ccur[j+1]) * (ldcur[j+1] - ldcur[j]);
+        xneg = (ccur[j-1] + ccur[j]) * (ldcur[j] - ldcur[j-1]);
+        yneg = (cprv[j] + ccur[j])   * (ldcur[j] - ldprv[j]);
+        dst[j] = 0.5f*stepsize*(xpos - xneg - yneg);
+    }
 
-            /* ************************************************************************* */
-            /**
-             * @brief This function checks if a given pixel is a maximum in a local neighbourhood
-             * @param img Input image where we will perform the maximum search
-             * @param dsize Half size of the neighbourhood
-             * @param value Response value at (x,y) position
-             * @param row Image row coordinate
-             * @param col Image column coordinate
-             * @param same_img Flag to indicate if the image value at (x,y) is in the input image
-             * @return 1->is maximum, 0->otherwise
-             */
-            bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, int row, int col, bool same_img) {
-
-                bool response = true;
-
-                for (int i = row - dsize; i <= row + dsize; i++) {
-                    for (int j = col - dsize; j <= col + dsize; j++) {
-                        if (i >= 0 && i < img.rows && j >= 0 && j < img.cols) {
-                            if (same_img == true) {
-                                if (i != row || j != col) {
-                                    if ((*(img.ptr<float>(i)+j)) > value) {
-                                        response = false;
-                                        return response;
-                                    }
-                                }
-                            }
-                            else {
-                                if ((*(img.ptr<float>(i)+j)) > value) {
-                                    response = false;
-                                    return response;
-                                }
-                            }
+    ccur = c.ptr<float>(1);
+    ldcur = Ld.ptr<float>(1);
+    cprv = c.ptr<float>(0);
+    ldprv = Ld.ptr<float>(0);
+
+    int r0 = Lstep.cols - 1;
+    int r1 = Lstep.cols - 2;
+
+    for (int i = 1; i < Lstep.rows - 1; i++) {
+        cnxt = c.ptr<float>(i + 1);
+        ldnxt = Ld.ptr<float>(i + 1);
+        dst = Lstep.ptr<float>(i);
+
+        xpos = (ccur[0] + ccur[1]) * (ldcur[1] - ldcur[0]);
+        ypos = (ccur[0] + cnxt[0]) * (ldnxt[0] - ldcur[0]);
+        yneg = (cprv[0] + ccur[0]) * (ldcur[0] - ldprv[0]);
+        dst[0] = 0.5f*stepsize*(xpos + ypos - yneg);
+
+        xneg = (ccur[r1] + ccur[r0]) * (ldcur[r0] - ldcur[r1]);
+        ypos = (ccur[r0] + cnxt[r0]) * (ldnxt[r0] - ldcur[r0]);
+        yneg = (cprv[r0] + ccur[r0]) * (ldcur[r0] - ldprv[r0]);
+        dst[r0] = 0.5f*stepsize*(-xneg + ypos - yneg);
+
+        cprv = ccur;
+        ccur = cnxt;
+        ldprv = ldcur;
+        ldcur = ldnxt;
+    }
+    Ld += Lstep;
+}
+
+/* ************************************************************************* */
+/**
+* @brief This function downsamples the input image using OpenCV resize
+* @param img Input image to be downsampled
+* @param dst Output image with half of the resolution of the input image
+*/
+void halfsample_image(const cv::Mat& src, cv::Mat& dst) {
+
+    // Make sure the destination image is of the right size
+    CV_Assert(src.cols / 2 == dst.cols);
+    CV_Assert(src.rows / 2 == dst.rows);
+    resize(src, dst, dst.size(), 0, 0, cv::INTER_AREA);
+}
+
+/* ************************************************************************* */
+/**
+ * @brief This function checks if a given pixel is a maximum in a local neighbourhood
+ * @param img Input image where we will perform the maximum search
+ * @param dsize Half size of the neighbourhood
+ * @param value Response value at (x,y) position
+ * @param row Image row coordinate
+ * @param col Image column coordinate
+ * @param same_img Flag to indicate if the image value at (x,y) is in the input image
+ * @return 1->is maximum, 0->otherwise
+ */
+bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, int row, int col, bool same_img) {
+
+    bool response = true;
+
+    for (int i = row - dsize; i <= row + dsize; i++) {
+        for (int j = col - dsize; j <= col + dsize; j++) {
+            if (i >= 0 && i < img.rows && j >= 0 && j < img.cols) {
+                if (same_img == true) {
+                    if (i != row || j != col) {
+                        if ((*(img.ptr<float>(i)+j)) > value) {
+                            response = false;
+                            return response;
                         }
                     }
                 }
-
-                return response;
+                else {
+                    if ((*(img.ptr<float>(i)+j)) > value) {
+                        response = false;
+                        return response;
+                    }
+                }
             }
         }
     }
+
+    return response;
+}
+
 }
index 6665e54..9dc9fed 100644 (file)
 #define __OPENCV_FEATURES_2D_NLDIFFUSION_FUNCTIONS_H__
 
 /* ************************************************************************* */
-// Includes
-#include "../precomp.hpp"
-
-/* ************************************************************************* */
 // Declaration of functions
 
-namespace cv {
-    namespace details {
-        namespace kaze {
+namespace cv
+{
+
+// Gaussian 2D convolution
+void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int ksize_y, float sigma);
 
-            // Gaussian 2D convolution
-            void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int ksize_y, float sigma);
+// Diffusivity functions
+void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k);
+void pm_g2(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k);
+void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k);
+void charbonnier_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k);
 
-            // Diffusivity functions
-            void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k);
-            void pm_g2(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k);
-            void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k);
-            void charbonnier_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k);
+float compute_k_percentile(const cv::Mat& img, float perc, float gscale, int nbins, int ksize_x, int ksize_y);
 
-            float compute_k_percentile(const cv::Mat& img, float perc, float gscale, int nbins, int ksize_x, int ksize_y);
+// Image derivatives
+void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder, int scale);
+void compute_derivative_kernels(cv::OutputArray _kx, cv::OutputArray _ky, int dx, int dy, int scale);
+void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder);
 
-            // Image derivatives
-            void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder, int scale);
-            void compute_derivative_kernels(cv::OutputArray _kx, cv::OutputArray _ky, int dx, int dy, int scale);
-            void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder);
+// Nonlinear diffusion filtering scalar step
+void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float stepsize);
 
-            // Nonlinear diffusion filtering scalar step
-            void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float stepsize);
+// For non-maxima suppresion
+bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, int row, int col, bool same_img);
 
-            // For non-maxima suppresion
-            bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, int row, int col, bool same_img);
+// Image downsampling
+void halfsample_image(const cv::Mat& src, cv::Mat& dst);
 
-            // Image downsampling
-            void halfsample_image(const cv::Mat& src, cv::Mat& dst);
-        }
-    }
 }
 
 #endif
index 40c32d0..0deaa26 100644 (file)
 namespace cv
 {
 
-const int TABLE_SIZE = 400;
-
-static double chitab3[]={0,  0.0150057,  0.0239478,  0.0315227,
-                  0.0383427,  0.0446605,  0.0506115,  0.0562786,
-                  0.0617174,  0.0669672,  0.0720573,  0.0770099,
-                  0.081843,  0.0865705,  0.0912043,  0.0957541,
-                  0.100228,  0.104633,  0.108976,  0.113261,
-                  0.117493,  0.121676,  0.125814,  0.12991,
-                  0.133967,  0.137987,  0.141974,  0.145929,
-                  0.149853,  0.15375,  0.15762,  0.161466,
-                  0.165287,  0.169087,  0.172866,  0.176625,
-                  0.180365,  0.184088,  0.187794,  0.191483,
-                  0.195158,  0.198819,  0.202466,  0.2061,
-                  0.209722,  0.213332,  0.216932,  0.220521,
-                  0.2241,  0.22767,  0.231231,  0.234783,
-                  0.238328,  0.241865,  0.245395,  0.248918,
-                  0.252435,  0.255947,  0.259452,  0.262952,
-                  0.266448,  0.269939,  0.273425,  0.276908,
-                  0.280386,  0.283862,  0.287334,  0.290803,
-                  0.29427,  0.297734,  0.301197,  0.304657,
-                  0.308115,  0.311573,  0.315028,  0.318483,
-                  0.321937,  0.32539,  0.328843,  0.332296,
-                  0.335749,  0.339201,  0.342654,  0.346108,
-                  0.349562,  0.353017,  0.356473,  0.35993,
-                  0.363389,  0.366849,  0.37031,  0.373774,
-                  0.377239,  0.380706,  0.384176,  0.387648,
-                  0.391123,  0.3946,  0.39808,  0.401563,
-                  0.405049,  0.408539,  0.412032,  0.415528,
-                  0.419028,  0.422531,  0.426039,  0.429551,
-                  0.433066,  0.436586,  0.440111,  0.44364,
-                  0.447173,  0.450712,  0.454255,  0.457803,
-                  0.461356,  0.464915,  0.468479,  0.472049,
-                  0.475624,  0.479205,  0.482792,  0.486384,
-                  0.489983,  0.493588,  0.4972,  0.500818,
-                  0.504442,  0.508073,  0.511711,  0.515356,
-                  0.519008,  0.522667,  0.526334,  0.530008,
-                  0.533689,  0.537378,  0.541075,  0.54478,
-                  0.548492,  0.552213,  0.555942,  0.55968,
-                  0.563425,  0.56718,  0.570943,  0.574715,
-                  0.578497,  0.582287,  0.586086,  0.589895,
-                  0.593713,  0.597541,  0.601379,  0.605227,
-                  0.609084,  0.612952,  0.61683,  0.620718,
-                  0.624617,  0.628526,  0.632447,  0.636378,
-                  0.64032,  0.644274,  0.648239,  0.652215,
-                  0.656203,  0.660203,  0.664215,  0.668238,
-                  0.672274,  0.676323,  0.680384,  0.684457,
-                  0.688543,  0.692643,  0.696755,  0.700881,
-                  0.70502,  0.709172,  0.713339,  0.717519,
-                  0.721714,  0.725922,  0.730145,  0.734383,
-                  0.738636,  0.742903,  0.747185,  0.751483,
-                  0.755796,  0.760125,  0.76447,  0.768831,
-                  0.773208,  0.777601,  0.782011,  0.786438,
-                  0.790882,  0.795343,  0.799821,  0.804318,
-                  0.808831,  0.813363,  0.817913,  0.822482,
-                  0.827069,  0.831676,  0.836301,  0.840946,
-                  0.84561,  0.850295,  0.854999,  0.859724,
-                  0.864469,  0.869235,  0.874022,  0.878831,
-                  0.883661,  0.888513,  0.893387,  0.898284,
-                  0.903204,  0.908146,  0.913112,  0.918101,
-                  0.923114,  0.928152,  0.933214,  0.938301,
-                  0.943413,  0.94855,  0.953713,  0.958903,
-                  0.964119,  0.969361,  0.974631,  0.979929,
-                  0.985254,  0.990608,  0.99599,  1.0014,
-                  1.00684,  1.01231,  1.01781,  1.02335,
-                  1.02891,  1.0345,  1.04013,  1.04579,
-                  1.05148,  1.05721,  1.06296,  1.06876,
-                  1.07459,  1.08045,  1.08635,  1.09228,
-                  1.09826,  1.10427,  1.11032,  1.1164,
-                  1.12253,  1.1287,  1.1349,  1.14115,
-                  1.14744,  1.15377,  1.16015,  1.16656,
-                  1.17303,  1.17954,  1.18609,  1.19269,
-                  1.19934,  1.20603,  1.21278,  1.21958,
-                  1.22642,  1.23332,  1.24027,  1.24727,
-                  1.25433,  1.26144,  1.26861,  1.27584,
-                  1.28312,  1.29047,  1.29787,  1.30534,
-                  1.31287,  1.32046,  1.32812,  1.33585,
-                  1.34364,  1.3515,  1.35943,  1.36744,
-                  1.37551,  1.38367,  1.39189,  1.4002,
-                  1.40859,  1.41705,  1.42561,  1.43424,
-                  1.44296,  1.45177,  1.46068,  1.46967,
-                  1.47876,  1.48795,  1.49723,  1.50662,
-                  1.51611,  1.52571,  1.53541,  1.54523,
-                  1.55517,  1.56522,  1.57539,  1.58568,
-                  1.59611,  1.60666,  1.61735,  1.62817,
-                  1.63914,  1.65025,  1.66152,  1.67293,
-                  1.68451,  1.69625,  1.70815,  1.72023,
-                  1.73249,  1.74494,  1.75757,  1.77041,
-                  1.78344,  1.79669,  1.81016,  1.82385,
-                  1.83777,  1.85194,  1.86635,  1.88103,
-                  1.89598,  1.91121,  1.92674,  1.94257,
-                  1.95871,  1.97519,  1.99201,  2.0092,
-                  2.02676,  2.04471,  2.06309,  2.08189,
-                  2.10115,  2.12089,  2.14114,  2.16192,
-                  2.18326,  2.2052,  2.22777,  2.25101,
-                  2.27496,  2.29966,  2.32518,  2.35156,
-                  2.37886,  2.40717,  2.43655,  2.46709,
-                  2.49889,  2.53206,  2.56673,  2.60305,
-                  2.64117,  2.6813,  2.72367,  2.76854,
-                  2.81623,  2.86714,  2.92173,  2.98059,
-                  3.04446,  3.1143,  3.19135,  3.27731,
-                  3.37455,  3.48653,  3.61862,  3.77982,
-                  3.98692,  4.2776,  4.77167,  133.333 };
-
-typedef struct LinkedPoint
-{
-    struct LinkedPoint* prev;
-    struct LinkedPoint* next;
-    Point pt;
-}
-LinkedPoint;
+using std::vector;
 
-// the history of region grown
-typedef struct MSERGrowHistory
+class MSER_Impl : public MSER
 {
-    struct MSERGrowHistory* shortcut;
-    struct MSERGrowHistory* child;
-    int stable; // when it ever stabled before, record the size
-    int val;
-    int size;
-}
-MSERGrowHistory;
+public:
+    struct Params
+    {
+        explicit Params( int _delta=5, double _maxVariation=0.25,
+                        int _minArea=60, int _maxArea=14400,
+                        double _minDiversity=.2, int _maxEvolution=200,
+                        double _areaThreshold=1.01,
+                        double _minMargin=0.003, int _edgeBlurSize=5 )
+        {
+            delta = _delta;
+            minArea = _minArea;
+            maxArea = _maxArea;
+            maxVariation = _maxVariation;
+            minDiversity = _minDiversity;
+            pass2Only = false;
+            maxEvolution = _maxEvolution;
+            areaThreshold = _areaThreshold;
+            minMargin = _minMargin;
+            edgeBlurSize = _edgeBlurSize;
+        }
+        int delta;
+        int minArea;
+        int maxArea;
+        double maxVariation;
+        double minDiversity;
+        bool pass2Only;
 
-typedef struct MSERConnectedComp
-{
-    LinkedPoint* head;
-    LinkedPoint* tail;
-    MSERGrowHistory* history;
-    unsigned long grey_level;
-    int size;
-    int dvar; // the derivative of last var
-    float var; // the current variation (most time is the variation of one-step back)
-}
-MSERConnectedComp;
+        int maxEvolution;
+        double areaThreshold;
+        double minMargin;
+        int edgeBlurSize;
+    };
 
-// Linear Time MSER claims by using bsf can get performance gain, here is the implementation
-// however it seems that will not do any good in real world test
-inline void _bitset(unsigned long * a, unsigned long b)
-{
-    *a |= 1<<b;
-}
-inline void _bitreset(unsigned long * a, unsigned long b)
-{
-    *a &= ~(1<<b);
-}
+    explicit MSER_Impl(const Params& _params) : params(_params) {}
 
-struct MSERParams
-{
-    MSERParams( int _delta, int _minArea, int _maxArea, double _maxVariation,
-                double _minDiversity, int _maxEvolution, double _areaThreshold,
-                double _minMargin, int _edgeBlurSize )
-        : delta(_delta), minArea(_minArea), maxArea(_maxArea), maxVariation(_maxVariation),
-        minDiversity(_minDiversity), maxEvolution(_maxEvolution), areaThreshold(_areaThreshold),
-        minMargin(_minMargin), edgeBlurSize(_edgeBlurSize)
-    {}
-    int delta;
-    int minArea;
-    int maxArea;
-    double maxVariation;
-    double minDiversity;
-    int maxEvolution;
-    double areaThreshold;
-    double minMargin;
-    int edgeBlurSize;
-};
+    virtual ~MSER_Impl() {}
 
-// clear the connected component in stack
-static void
-initMSERComp( MSERConnectedComp* comp )
-{
-    comp->size = 0;
-    comp->var = 0;
-    comp->dvar = 1;
-    comp->history = NULL;
-}
+    void set(int propId, double value)
+    {
+        if( propId == DELTA )
+            params.delta = cvRound(value);
+        else if( propId == MIN_AREA )
+            params.minArea = cvRound(value);
+        else if( propId == MAX_AREA )
+            params.maxArea = cvRound(value);
+        else if( propId == PASS2_ONLY )
+            params.pass2Only = value != 0;
+        else
+            CV_Error(CV_StsBadArg, "Unknown parameter id");
+    }
 
-// add history of size to a connected component
-static void
-MSERNewHistory( MSERConnectedComp* comp, MSERGrowHistory* history )
-{
-    history->child = history;
-    if ( NULL == comp->history )
+    double get(int propId) const
     {
-        history->shortcut = history;
-        history->stable = 0;
-    } else {
-        comp->history->child = history;
-        history->shortcut = comp->history->shortcut;
-        history->stable = comp->history->stable;
+        double value = 0;
+        if( propId == DELTA )
+            value = params.delta;
+        else if( propId == MIN_AREA )
+            value = params.minArea;
+        else if( propId == MAX_AREA )
+            value = params.maxArea;
+        else if( propId == PASS2_ONLY )
+            value = params.pass2Only;
+        else
+            CV_Error(CV_StsBadArg, "Unknown parameter id");
+        return value;
     }
-    history->val = comp->grey_level;
-    history->size = comp->size;
-    comp->history = history;
-}
 
-// merging two connected component
-static void
-MSERMergeComp( MSERConnectedComp* comp1,
-          MSERConnectedComp* comp2,
-          MSERConnectedComp* comp,
-          MSERGrowHistory* history )
-{
-    LinkedPoint* head;
-    LinkedPoint* tail;
-    comp->grey_level = comp2->grey_level;
-    history->child = history;
-    // select the winner by size
-    if ( comp1->size >= comp2->size )
+    enum { DIR_SHIFT = 29, NEXT_MASK = ((1<<DIR_SHIFT)-1)  };
+
+    struct Pixel
     {
-        if ( NULL == comp1->history )
+        Pixel() : val(0) {}
+        Pixel(int _val) : val(_val) {}
+
+        int getGray(const Pixel* ptr0, const uchar* imgptr0, int mask) const
         {
-            history->shortcut = history;
-            history->stable = 0;
-        } else {
-            comp1->history->child = history;
-            history->shortcut = comp1->history->shortcut;
-            history->stable = comp1->history->stable;
+            return imgptr0[this - ptr0] ^ mask;
         }
-        if ( NULL != comp2->history && comp2->history->stable > history->stable )
-            history->stable = comp2->history->stable;
-        history->val = comp1->grey_level;
-        history->size = comp1->size;
-        // put comp1 to history
-        comp->var = comp1->var;
-        comp->dvar = comp1->dvar;
-        if ( comp1->size > 0 && comp2->size > 0 )
+        int getNext() const { return (val & NEXT_MASK); }
+        void setNext(int next) { val = (val & ~NEXT_MASK) | next; }
+
+        int getDir() const { return (int)((unsigned)val >> DIR_SHIFT); }
+        void setDir(int dir) { val = (val & NEXT_MASK) | (dir << DIR_SHIFT); }
+        bool isVisited() const { return (val & ~NEXT_MASK) != 0; }
+
+        int val;
+    };
+    typedef int PPixel;
+
+    // the history of region grown
+    struct CompHistory
+    {
+        CompHistory() { shortcut = child = 0; stable = val = size = 0; }
+        CompHistory* shortcut;
+        CompHistory* child;
+        int stable; // when it ever stabled before, record the size
+        int val;
+        int size;
+    };
+
+    struct ConnectedComp
+    {
+        ConnectedComp()
         {
-            comp1->tail->next = comp2->head;
-            comp2->head->prev = comp1->tail;
+            init(0);
         }
-        head = ( comp1->size > 0 ) ? comp1->head : comp2->head;
-        tail = ( comp2->size > 0 ) ? comp2->tail : comp1->tail;
-        // always made the newly added in the last of the pixel list (comp1 ... comp2)
-    } else {
-        if ( NULL == comp2->history )
+
+        void init(int gray)
         {
-            history->shortcut = history;
-            history->stable = 0;
-        } else {
-            comp2->history->child = history;
-            history->shortcut = comp2->history->shortcut;
-            history->stable = comp2->history->stable;
+            head = tail = 0;
+            history = 0;
+            size = 0;
+            grey_level = gray;
+            dvar = false;
+            var = 0;
         }
-        if ( NULL != comp1->history && comp1->history->stable > history->stable )
-            history->stable = comp1->history->stable;
-        history->val = comp2->grey_level;
-        history->size = comp2->size;
-        // put comp2 to history
-        comp->var = comp2->var;
-        comp->dvar = comp2->dvar;
-        if ( comp1->size > 0 && comp2->size > 0 )
+
+        // add history chunk to a connected component
+        void growHistory( CompHistory* h )
         {
-            comp2->tail->next = comp1->head;
-            comp1->head->prev = comp2->tail;
+            h->child = h;
+            if( !history )
+            {
+                h->shortcut = h;
+                h->stable = 0;
+            }
+            else
+            {
+                history->child = h;
+                h->shortcut = history->shortcut;
+                h->stable = history->stable;
+            }
+            h->val = grey_level;
+            h->size = size;
+            history = h;
         }
-        head = ( comp2->size > 0 ) ? comp2->head : comp1->head;
-        tail = ( comp1->size > 0 ) ? comp1->tail : comp2->tail;
-        // always made the newly added in the last of the pixel list (comp2 ... comp1)
-    }
-    comp->head = head;
-    comp->tail = tail;
-    comp->history = history;
-    comp->size = comp1->size + comp2->size;
-}
 
-static float
-MSERVariationCalc( MSERConnectedComp* comp, int delta )
-{
-    MSERGrowHistory* history = comp->history;
-    int val = comp->grey_level;
-    if ( NULL != history )
-    {
-        MSERGrowHistory* shortcut = history->shortcut;
-        while ( shortcut != shortcut->shortcut && shortcut->val + delta > val )
-            shortcut = shortcut->shortcut;
-        MSERGrowHistory* child = shortcut->child;
-        while ( child != child->child && child->val + delta <= val )
+        // merging two connected components
+        static void
+        merge( const ConnectedComp* comp1,
+              const ConnectedComp* comp2,
+              ConnectedComp* comp,
+              CompHistory* h,
+              Pixel* pix0 )
         {
-            shortcut = child;
-            child = child->child;
+            comp->grey_level = comp2->grey_level;
+            h->child = h;
+            // select the winner by size
+            if ( comp1->size < comp2->size )
+                std::swap(comp1, comp2);
+
+            if( !comp1->history )
+            {
+                h->shortcut = h;
+                h->stable = 0;
+            }
+            else
+            {
+                comp1->history->child = h;
+                h->shortcut = comp1->history->shortcut;
+                h->stable = comp1->history->stable;
+            }
+            if( comp2->history && comp2->history->stable > h->stable )
+                h->stable = comp2->history->stable;
+            h->val = comp1->grey_level;
+            h->size = comp1->size;
+            // put comp1 to history
+            comp->var = comp1->var;
+            comp->dvar = comp1->dvar;
+            if( comp1->size > 0 && comp2->size > 0 )
+                pix0[comp1->tail].setNext(comp2->head);
+            PPixel head = comp1->size > 0 ? comp1->head : comp2->head;
+            PPixel tail = comp2->size > 0 ? comp2->tail : comp1->tail;
+            // always made the newly added in the last of the pixel list (comp1 ... comp2)
+            comp->head = head;
+            comp->tail = tail;
+            comp->history = h;
+            comp->size = comp1->size + comp2->size;
         }
-        // get the position of history where the shortcut->val <= delta+val and shortcut->child->val >= delta+val
-        history->shortcut = shortcut;
-        return (float)(comp->size-shortcut->size)/(float)shortcut->size;
-        // here is a small modification of MSER where cal ||R_{i}-R_{i-delta}||/||R_{i-delta}||
-        // in standard MSER, cal ||R_{i+delta}-R_{i-delta}||/||R_{i}||
-        // my calculation is simpler and much easier to implement
-    }
-    return 1.;
-}
 
-static bool MSERStableCheck( MSERConnectedComp* comp, MSERParams params )
-{
-    // tricky part: it actually check the stablity of one-step back
-    if ( comp->history == NULL || comp->history->size <= params.minArea || comp->history->size >= params.maxArea )
-        return 0;
-    float div = (float)(comp->history->size-comp->history->stable)/(float)comp->history->size;
-    float var = MSERVariationCalc( comp, params.delta );
-    int dvar = ( comp->var < var || (unsigned long)(comp->history->val + 1) < comp->grey_level );
-    int stable = ( dvar && !comp->dvar && comp->var < params.maxVariation && div > params.minDiversity );
-    comp->var = var;
-    comp->dvar = dvar;
-    if ( stable )
-        comp->history->stable = comp->history->size;
-    return stable != 0;
-}
+        float calcVariation( int delta ) const
+        {
+            if( !history )
+                return 1.f;
+            int val = grey_level;
+            CompHistory* shortcut = history->shortcut;
+            while( shortcut != shortcut->shortcut && shortcut->val + delta > val )
+                shortcut = shortcut->shortcut;
+            CompHistory* child = shortcut->child;
+            while( child != child->child && child->val + delta <= val )
+            {
+                shortcut = child;
+                child = child->child;
+            }
+            // get the position of history where the shortcut->val <= delta+val and shortcut->child->val >= delta+val
+            history->shortcut = shortcut;
+            return (float)(size - shortcut->size)/(float)shortcut->size;
+            // here is a small modification of MSER where cal ||R_{i}-R_{i-delta}||/||R_{i-delta}||
+            // in standard MSER, cal ||R_{i+delta}-R_{i-delta}||/||R_{i}||
+            // my calculation is simpler and much easier to implement
+        }
 
-// add a pixel to the pixel list
-static void accumulateMSERComp( MSERConnectedComp* comp, LinkedPoint* point )
-{
-    if ( comp->size > 0 )
-    {
-        point->prev = comp->tail;
-        comp->tail->next = point;
-        point->next = NULL;
-    } else {
-        point->prev = NULL;
-        point->next = NULL;
-        comp->head = point;
-    }
-    comp->tail = point;
-    comp->size++;
-}
+        bool isStable(const Params& p)
+        {
+            // tricky part: it actually check the stablity of one-step back
+            if( !history || history->size <= p.minArea || history->size >= p.maxArea )
+                return false;
+            float div = (float)(history->size - history->stable)/(float)history->size;
+            float _var = calcVariation( p.delta );
+            bool _dvar = (var < _var) || (history->val + 1 < grey_level);
+            bool stable = _dvar && !dvar && _var < p.maxVariation && div > p.minDiversity;
+            var = _var;
+            dvar = _dvar;
+            if( stable )
+                history->stable = history->size;
+            return stable;
+        }
 
-// convert the point set to CvSeq
-static CvContour* MSERToContour( MSERConnectedComp* comp, CvMemStorage* storage )
-{
-    CvSeq* _contour = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage );
-    CvContour* contour = (CvContour*)_contour;
-    cvSeqPushMulti( _contour, 0, comp->history->size );
-    LinkedPoint* lpt = comp->head;
-    for ( int i = 0; i < comp->history->size; i++ )
-    {
-        CvPoint* pt = CV_GET_SEQ_ELEM( CvPoint, _contour, i );
-        pt->x = lpt->pt.x;
-        pt->y = lpt->pt.y;
-        lpt = lpt->next;
-    }
-    cvBoundingRect( contour );
-    return contour;
-}
+        // convert the point set to CvSeq
+        Rect label( Mat& labels, int lval, const Pixel* pix0, int step ) const
+        {
+            int* lptr = labels.ptr<int>();
+            int lstep = labels.step/sizeof(lptr[0]);
+            int xmin = INT_MAX, ymin = INT_MAX, xmax = INT_MIN, ymax = INT_MIN;
 
-// to preprocess src image to following format
-// 32-bit image
-// > 0 is available, < 0 is visited
-// 17~19 bits is the direction
-// 8~11 bits is the bucket it falls to (for BitScanForward)
-// 0~8 bits is the color
-static int* preprocessMSER_8UC1( CvMat* img,
-            int*** heap_cur,
-            CvMat* src,
-            CvMat* mask )
-{
-    int srccpt = src->step-src->cols;
-    int cpt_1 = img->cols-src->cols-1;
-    int* imgptr = img->data.i;
-    int* startptr;
+            for( PPixel pix = head; pix != 0; pix = pix0[pix].getNext() )
+            {
+                int y = pix/step;
+                int x = pix - y*step;
 
-    int level_size[256];
-    for ( int i = 0; i < 256; i++ )
-        level_size[i] = 0;
+                xmin = std::min(xmin, x);
+                xmax = std::max(xmax, x);
+                ymin = std::min(ymin, y);
+                ymax = std::max(ymax, y);
 
-    for ( int i = 0; i < src->cols+2; i++ )
-    {
-        *imgptr = -1;
-        imgptr++;
-    }
-    imgptr += cpt_1-1;
-    uchar* srcptr = src->data.ptr;
-    if ( mask )
+                lptr[lstep*y + x] = lval;
+            }
+
+            return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
+        }
+
+        PPixel head;
+        PPixel tail;
+        CompHistory* history;
+        int grey_level;
+        int size;
+        float var; // the current variation (most time is the variation of one-step back)
+        bool dvar; // the derivative of last var
+    };
+
+    int detectAndLabel( InputArray _src, OutputArray _labels, OutputArray _bboxes );
+    void detect( InputArray _src, vector<KeyPoint>& keypoints, InputArray _mask );
+
+    void preprocess1( const Mat& img, int* level_size )
     {
-        startptr = 0;
-        uchar* maskptr = mask->data.ptr;
-        for ( int i = 0; i < src->rows; i++ )
+        memset(level_size, 0, 256*sizeof(level_size[0]));
+
+        int i, j, cols = img.cols, rows = img.rows;
+        int step = cols;
+        pixbuf.resize(step*rows);
+        heapbuf.resize(cols*rows + 256);
+        histbuf.resize(cols*rows);
+        Pixel borderpix;
+        borderpix.setDir(4);
+
+        for( j = 0; j < step; j++ )
         {
-            *imgptr = -1;
-            imgptr++;
-            for ( int j = 0; j < src->cols; j++ )
-            {
-                if ( *maskptr )
-                {
-                    if ( !startptr )
-                        startptr = imgptr;
-                    *srcptr = 0xff-*srcptr;
-                    level_size[*srcptr]++;
-                    *imgptr = ((*srcptr>>5)<<8)|(*srcptr);
-                } else {
-                    *imgptr = -1;
-                }
-                imgptr++;
-                srcptr++;
-                maskptr++;
-            }
-            *imgptr = -1;
-            imgptr += cpt_1;
-            srcptr += srccpt;
-            maskptr += srccpt;
+            pixbuf[j] = pixbuf[j + (rows-1)*step] = borderpix;
         }
-    } else {
-        startptr = imgptr+img->cols+1;
-        for ( int i = 0; i < src->rows; i++ )
+
+        for( i = 1; i < rows-1; i++ )
         {
-            *imgptr = -1;
-            imgptr++;
-            for ( int j = 0; j < src->cols; j++ )
+            const uchar* imgptr = img.ptr(i);
+            Pixel* pptr = &pixbuf[i*step];
+            pptr[0] = pptr[cols-1] = borderpix;
+            for( j = 1; j < cols-1; j++ )
             {
-                *srcptr = 0xff-*srcptr;
-                level_size[*srcptr]++;
-                *imgptr = ((*srcptr>>5)<<8)|(*srcptr);
-                imgptr++;
-                srcptr++;
+                int val = imgptr[j];
+                level_size[val]++;
+                pptr[j].val = 0;
             }
-            *imgptr = -1;
-            imgptr += cpt_1;
-            srcptr += srccpt;
         }
     }
-    for ( int i = 0; i < src->cols+2; i++ )
-    {
-        *imgptr = -1;
-        imgptr++;
-    }
 
-    heap_cur[0][0] = 0;
-    for ( int i = 1; i < 256; i++ )
+    void preprocess2( const Mat& img, int* level_size )
     {
-        heap_cur[i] = heap_cur[i-1]+level_size[i-1]+1;
-        heap_cur[i][0] = 0;
-    }
-    return startptr;
-}
+        int i;
 
-static void extractMSER_8UC1_Pass( int* ioptr,
-              int* imgptr,
-              int*** heap_cur,
-              LinkedPoint* ptsptr,
-              MSERGrowHistory* histptr,
-              MSERConnectedComp* comptr,
-              int step,
-              int stepmask,
-              int stepgap,
-              MSERParams params,
-              int color,
-              CvSeq* contours,
-              CvMemStorage* storage )
-{
-    comptr->grey_level = 256;
-    comptr++;
-    comptr->grey_level = (*imgptr)&0xff;
-    initMSERComp( comptr );
-    *imgptr |= 0x80000000;
-    heap_cur += (*imgptr)&0xff;
-    int dir[] = { 1, step, -1, -step };
-#ifdef __INTRIN_ENABLED__
-    unsigned long heapbit[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-    unsigned long* bit_cur = heapbit+(((*imgptr)&0x700)>>8);
-#endif
-    for ( ; ; )
-    {
-        // take tour of all the 4 directions
-        while ( ((*imgptr)&0x70000) < 0x40000 )
+        for( i = 0; i < 128; i++ )
+            std::swap(level_size[i], level_size[255-i]);
+
+        if( !params.pass2Only )
         {
-            // get the neighbor
-            int* imgptr_nbr = imgptr+dir[((*imgptr)&0x70000)>>16];
-            if ( *imgptr_nbr >= 0 ) // if the neighbor is not visited yet
+            int j, cols = img.cols, rows = img.rows;
+            int step = cols;
+            for( i = 1; i < rows-1; i++ )
             {
-                *imgptr_nbr |= 0x80000000; // mark it as visited
-                if ( ((*imgptr_nbr)&0xff) < ((*imgptr)&0xff) )
+                Pixel* pptr = &pixbuf[i*step + 1];
+                for( j = 1; j < cols-1; j++ )
                 {
-                    // when the value of neighbor smaller than current
-                    // push current to boundary heap and make the neighbor to be the current one
-                    // create an empty comp
-                    (*heap_cur)++;
-                    **heap_cur = imgptr;
-                    *imgptr += 0x10000;
-                    heap_cur += ((*imgptr_nbr)&0xff)-((*imgptr)&0xff);
-#ifdef __INTRIN_ENABLED__
-                    _bitset( bit_cur, (*imgptr)&0x1f );
-                    bit_cur += (((*imgptr_nbr)&0x700)-((*imgptr)&0x700))>>8;
-#endif
-                    imgptr = imgptr_nbr;
-                    comptr++;
-                    initMSERComp( comptr );
-                    comptr->grey_level = (*imgptr)&0xff;
-                    continue;
-                } else {
-                    // otherwise, push the neighbor to boundary heap
-                    heap_cur[((*imgptr_nbr)&0xff)-((*imgptr)&0xff)]++;
-                    *heap_cur[((*imgptr_nbr)&0xff)-((*imgptr)&0xff)] = imgptr_nbr;
-#ifdef __INTRIN_ENABLED__
-                    _bitset( bit_cur+((((*imgptr_nbr)&0x700)-((*imgptr)&0x700))>>8), (*imgptr_nbr)&0x1f );
-#endif
+                    pptr[j].val = 0;
                 }
             }
-            *imgptr += 0x10000;
         }
-        int imsk = (int)(imgptr-ioptr);
-        ptsptr->pt = cvPoint( imsk&stepmask, imsk>>stepgap );
-        // get the current location
-        accumulateMSERComp( comptr, ptsptr );
-        ptsptr++;
-        // get the next pixel from boundary heap
-        if ( **heap_cur )
+    }
+
+    void pass( const Mat& img, Mat& labels, int& lval, vector<Rect>& bboxvec,
+              Size size, const int* level_size, int mask )
+    {
+        CompHistory* histptr = &histbuf[0];
+        int step = size.width;
+        Pixel *ptr0 = &pixbuf[0], *ptr = &ptr0[step+1];
+        const uchar* imgptr0 = img.ptr();
+        Pixel** heap[256];
+        ConnectedComp comp[257];
+        ConnectedComp* comptr = &comp[0];
+
+        heap[0] = &heapbuf[0];
+        heap[0][0] = 0;
+
+        for( int i = 1; i < 256; i++ )
+        {
+            heap[i] = heap[i-1] + level_size[i-1] + 1;
+            heap[i][0] = 0;
+        }
+
+        comptr->grey_level = 256;
+        comptr++;
+        comptr->grey_level = ptr->getGray(ptr0, imgptr0, mask);
+        ptr->setDir(1);
+        int dir[] = { 0, 1, step, -1, -step };
+        for( ;; )
         {
-            imgptr = **heap_cur;
-            (*heap_cur)--;
-#ifdef __INTRIN_ENABLED__
-            if ( !**heap_cur )
-                _bitreset( bit_cur, (*imgptr)&0x1f );
-#endif
-        } else {
-#ifdef __INTRIN_ENABLED__
-            bool found_pixel = 0;
-            unsigned long pixel_val;
-            for ( int i = ((*imgptr)&0x700)>>8; i < 8; i++ )
+            int curr_gray = ptr->getGray(ptr0, imgptr0, mask);
+            int nbr_idx = ptr->getDir();
+            // take tour of all the 4 directions
+            for( ; nbr_idx <= 4; nbr_idx++ )
             {
-                if ( _BitScanForward( &pixel_val, *bit_cur ) )
+                // get the neighbor
+                Pixel* ptr_nbr = ptr + dir[nbr_idx];
+                if( !ptr_nbr->isVisited() )
                 {
-                    found_pixel = 1;
-                    pixel_val += i<<5;
-                    heap_cur += pixel_val-((*imgptr)&0xff);
-                    break;
+                    // set dir=1, next=0
+                    ptr_nbr->val = 1 << DIR_SHIFT;
+                    int nbr_gray = ptr_nbr->getGray(ptr0, imgptr0, mask);
+                    if( nbr_gray < curr_gray )
+                    {
+                        // when the value of neighbor smaller than current
+                        // push current to boundary heap and make the neighbor to be the current one
+                        // create an empty comp
+                        *(++heap[curr_gray]) = ptr;
+                        ptr->val = (nbr_idx+1) << DIR_SHIFT;
+                        ptr = ptr_nbr;
+                        comptr++;
+                        comptr->init(nbr_gray);
+                        curr_gray = nbr_gray;
+                        nbr_idx = 0;
+                        continue;
+                    }
+                    // otherwise, push the neighbor to boundary heap
+                    *(++heap[nbr_gray]) = ptr_nbr;
                 }
-                bit_cur++;
             }
-            if ( found_pixel )
-#else
-            heap_cur++;
-            unsigned long pixel_val = 0;
-            for ( unsigned long i = ((*imgptr)&0xff)+1; i < 256; i++ )
+
+            // set dir = nbr_idx, next = 0
+            ptr->val = nbr_idx << DIR_SHIFT;
+            int ptrofs = (int)(ptr - ptr0);
+            CV_Assert(ptrofs != 0);
+
+            // add a pixel to the pixel list
+            if( comptr->tail )
+                ptr0[comptr->tail].setNext(ptrofs);
+            else
+                comptr->head = ptrofs;
+            comptr->tail = ptrofs;
+            comptr->size++;
+            // get the next pixel from boundary heap
+            if( *heap[curr_gray] )
             {
-                if ( **heap_cur )
-                {
-                    pixel_val = i;
-                    break;
-                }
-                heap_cur++;
+                ptr = *heap[curr_gray];
+                heap[curr_gray]--;
             }
-            if ( pixel_val )
-#endif
+            else
             {
-                imgptr = **heap_cur;
-                (*heap_cur)--;
-#ifdef __INTRIN_ENABLED__
-                if ( !**heap_cur )
-                    _bitreset( bit_cur, pixel_val&0x1f );
-#endif
-                if ( pixel_val < comptr[-1].grey_level )
+                for( curr_gray++; curr_gray < 256; curr_gray++ )
+                {
+                    if( *heap[curr_gray] )
+                        break;
+                }
+                if( curr_gray >= 256 )
+                    break;
+
+                ptr = *heap[curr_gray];
+                heap[curr_gray]--;
+                if( curr_gray < comptr[-1].grey_level )
                 {
                     // check the stablity and push a new history, increase the grey level
-                    if ( MSERStableCheck( comptr, params ) )
+                    if( comptr->isStable(params) )
                     {
-                        CvContour* contour = MSERToContour( comptr, storage );
-                        contour->color = color;
-                        cvSeqPush( contours, &contour );
+                        Rect box = comptr->label( labels, lval++, ptr0, step );
+                        bboxvec.push_back(box);
                     }
-                    MSERNewHistory( comptr, histptr );
-                    comptr[0].grey_level = pixel_val;
-                    histptr++;
-                } else {
+                    comptr->growHistory( histptr++ );
+                    comptr[0].grey_level = curr_gray;
+                }
+                else
+                {
                     // keep merging top two comp in stack until the grey level >= pixel_val
-                    for ( ; ; )
+                    for(;;)
                     {
                         comptr--;
-                        MSERMergeComp( comptr+1, comptr, comptr, histptr );
-                        histptr++;
-                        if ( pixel_val <= comptr[0].grey_level )
+                        ConnectedComp::merge(comptr+1, comptr, comptr, histptr++, ptr0);
+                        if( curr_gray <= comptr[0].grey_level )
                             break;
-                        if ( pixel_val < comptr[-1].grey_level )
+                        if( curr_gray < comptr[-1].grey_level )
                         {
                             // check the stablity here otherwise it wouldn't be an ER
-                            if ( MSERStableCheck( comptr, params ) )
+                            if( comptr->isStable(params) )
                             {
-                                CvContour* contour = MSERToContour( comptr, storage );
-                                contour->color = color;
-                                cvSeqPush( contours, &contour );
+                                Rect box = comptr->label( labels, lval++, ptr0, step );
+                                bboxvec.push_back(box);
                             }
-                            MSERNewHistory( comptr, histptr );
-                            comptr[0].grey_level = pixel_val;
-                            histptr++;
+                            comptr->growHistory( histptr++ );
+                            comptr[0].grey_level = curr_gray;
                             break;
                         }
                     }
                 }
-            } else
-                break;
+            }
         }
     }
-}
 
-static void extractMSER_8UC1( CvMat* src,
-             CvMat* mask,
-             CvSeq* contours,
-             CvMemStorage* storage,
-             MSERParams params )
+    Mat tempsrc;
+    vector<Pixel> pixbuf;
+    vector<Pixel*> heapbuf;
+    vector<CompHistory> histbuf;
+
+    Params params;
+};
+
+/*
+
+TODO:
+the color MSER has not been completely refactored yet. We leave it mostly as-is,
+with just enough changes to convert C structures to C++ ones and
+add support for color images into MSER_Impl::detectAndLabel.
+*/
+
+const int TABLE_SIZE = 400;
+
+static const float chitab3[]=
 {
-    int step = 8;
-    int stepgap = 3;
-    while ( step < src->step+2 )
-    {
-        step <<= 1;
-        stepgap++;
-    }
-    int stepmask = step-1;
-
-    // to speedup the process, make the width to be 2^N
-    CvMat* img = cvCreateMat( src->rows+2, step, CV_32SC1 );
-    int* ioptr = img->data.i+step+1;
-    int* imgptr;
-
-    // pre-allocate boundary heap
-    int** heap = (int**)cvAlloc( (src->rows*src->cols+256)*sizeof(heap[0]) );
-    int** heap_start[256];
-    heap_start[0] = heap;
-
-    // pre-allocate linked point and grow history
-    LinkedPoint* pts = (LinkedPoint*)cvAlloc( src->rows*src->cols*sizeof(pts[0]) );
-    MSERGrowHistory* history = (MSERGrowHistory*)cvAlloc( src->rows*src->cols*sizeof(history[0]) );
-    MSERConnectedComp comp[257];
-
-    // darker to brighter (MSER-)
-    imgptr = preprocessMSER_8UC1( img, heap_start, src, mask );
-    extractMSER_8UC1_Pass( ioptr, imgptr, heap_start, pts, history, comp, step, stepmask, stepgap, params, -1, contours, storage );
-    // brighter to darker (MSER+)
-    imgptr = preprocessMSER_8UC1( img, heap_start, src, mask );
-    extractMSER_8UC1_Pass( ioptr, imgptr, heap_start, pts, history, comp, step, stepmask, stepgap, params, 1, contours, storage );
-
-    // clean up
-    cvFree( &history );
-    cvFree( &heap );
-    cvFree( &pts );
-    cvReleaseMat( &img );
-}
+    0.f,  0.0150057f,  0.0239478f,  0.0315227f,
+    0.0383427f,  0.0446605f,  0.0506115f,  0.0562786f,
+    0.0617174f,  0.0669672f,  0.0720573f,  0.0770099f,
+    0.081843f,  0.0865705f,  0.0912043f,  0.0957541f,
+    0.100228f,  0.104633f,  0.108976f,  0.113261f,
+    0.117493f,  0.121676f,  0.125814f,  0.12991f,
+    0.133967f,  0.137987f,  0.141974f,  0.145929f,
+    0.149853f,  0.15375f,  0.15762f,  0.161466f,
+    0.165287f,  0.169087f,  0.172866f,  0.176625f,
+    0.180365f,  0.184088f,  0.187794f,  0.191483f,
+    0.195158f,  0.198819f,  0.202466f,  0.2061f,
+    0.209722f,  0.213332f,  0.216932f,  0.220521f,
+    0.2241f,  0.22767f,  0.231231f,  0.234783f,
+    0.238328f,  0.241865f,  0.245395f,  0.248918f,
+    0.252435f,  0.255947f,  0.259452f,  0.262952f,
+    0.266448f,  0.269939f,  0.273425f,  0.276908f,
+    0.280386f,  0.283862f,  0.287334f,  0.290803f,
+    0.29427f,  0.297734f,  0.301197f,  0.304657f,
+    0.308115f,  0.311573f,  0.315028f,  0.318483f,
+    0.321937f,  0.32539f,  0.328843f,  0.332296f,
+    0.335749f,  0.339201f,  0.342654f,  0.346108f,
+    0.349562f,  0.353017f,  0.356473f,  0.35993f,
+    0.363389f,  0.366849f,  0.37031f,  0.373774f,
+    0.377239f,  0.380706f,  0.384176f,  0.387648f,
+    0.391123f,  0.3946f,  0.39808f,  0.401563f,
+    0.405049f,  0.408539f,  0.412032f,  0.415528f,
+    0.419028f,  0.422531f,  0.426039f,  0.429551f,
+    0.433066f,  0.436586f,  0.440111f,  0.44364f,
+    0.447173f,  0.450712f,  0.454255f,  0.457803f,
+    0.461356f,  0.464915f,  0.468479f,  0.472049f,
+    0.475624f,  0.479205f,  0.482792f,  0.486384f,
+    0.489983f,  0.493588f,  0.4972f,  0.500818f,
+    0.504442f,  0.508073f,  0.511711f,  0.515356f,
+    0.519008f,  0.522667f,  0.526334f,  0.530008f,
+    0.533689f,  0.537378f,  0.541075f,  0.54478f,
+    0.548492f,  0.552213f,  0.555942f,  0.55968f,
+    0.563425f,  0.56718f,  0.570943f,  0.574715f,
+    0.578497f,  0.582287f,  0.586086f,  0.589895f,
+    0.593713f,  0.597541f,  0.601379f,  0.605227f,
+    0.609084f,  0.612952f,  0.61683f,  0.620718f,
+    0.624617f,  0.628526f,  0.632447f,  0.636378f,
+    0.64032f,  0.644274f,  0.648239f,  0.652215f,
+    0.656203f,  0.660203f,  0.664215f,  0.668238f,
+    0.672274f,  0.676323f,  0.680384f,  0.684457f,
+    0.688543f,  0.692643f,  0.696755f,  0.700881f,
+    0.70502f,  0.709172f,  0.713339f,  0.717519f,
+    0.721714f,  0.725922f,  0.730145f,  0.734383f,
+    0.738636f,  0.742903f,  0.747185f,  0.751483f,
+    0.755796f,  0.760125f,  0.76447f,  0.768831f,
+    0.773208f,  0.777601f,  0.782011f,  0.786438f,
+    0.790882f,  0.795343f,  0.799821f,  0.804318f,
+    0.808831f,  0.813363f,  0.817913f,  0.822482f,
+    0.827069f,  0.831676f,  0.836301f,  0.840946f,
+    0.84561f,  0.850295f,  0.854999f,  0.859724f,
+    0.864469f,  0.869235f,  0.874022f,  0.878831f,
+    0.883661f,  0.888513f,  0.893387f,  0.898284f,
+    0.903204f,  0.908146f,  0.913112f,  0.918101f,
+    0.923114f,  0.928152f,  0.933214f,  0.938301f,
+    0.943413f,  0.94855f,  0.953713f,  0.958903f,
+    0.964119f,  0.969361f,  0.974631f,  0.979929f,
+    0.985254f,  0.990608f,  0.99599f,  1.0014f,
+    1.00684f,  1.01231f,  1.01781f,  1.02335f,
+    1.02891f,  1.0345f,  1.04013f,  1.04579f,
+    1.05148f,  1.05721f,  1.06296f,  1.06876f,
+    1.07459f,  1.08045f,  1.08635f,  1.09228f,
+    1.09826f,  1.10427f,  1.11032f,  1.1164f,
+    1.12253f,  1.1287f,  1.1349f,  1.14115f,
+    1.14744f,  1.15377f,  1.16015f,  1.16656f,
+    1.17303f,  1.17954f,  1.18609f,  1.19269f,
+    1.19934f,  1.20603f,  1.21278f,  1.21958f,
+    1.22642f,  1.23332f,  1.24027f,  1.24727f,
+    1.25433f,  1.26144f,  1.26861f,  1.27584f,
+    1.28312f,  1.29047f,  1.29787f,  1.30534f,
+    1.31287f,  1.32046f,  1.32812f,  1.33585f,
+    1.34364f,  1.3515f,  1.35943f,  1.36744f,
+    1.37551f,  1.38367f,  1.39189f,  1.4002f,
+    1.40859f,  1.41705f,  1.42561f,  1.43424f,
+    1.44296f,  1.45177f,  1.46068f,  1.46967f,
+    1.47876f,  1.48795f,  1.49723f,  1.50662f,
+    1.51611f,  1.52571f,  1.53541f,  1.54523f,
+    1.55517f,  1.56522f,  1.57539f,  1.58568f,
+    1.59611f,  1.60666f,  1.61735f,  1.62817f,
+    1.63914f,  1.65025f,  1.66152f,  1.67293f,
+    1.68451f,  1.69625f,  1.70815f,  1.72023f,
+    1.73249f,  1.74494f,  1.75757f,  1.77041f,
+    1.78344f,  1.79669f,  1.81016f,  1.82385f,
+    1.83777f,  1.85194f,  1.86635f,  1.88103f,
+    1.89598f,  1.91121f,  1.92674f,  1.94257f,
+    1.95871f,  1.97519f,  1.99201f,  2.0092f,
+    2.02676f,  2.04471f,  2.06309f,  2.08189f,
+    2.10115f,  2.12089f,  2.14114f,  2.16192f,
+    2.18326f,  2.2052f,  2.22777f,  2.25101f,
+    2.27496f,  2.29966f,  2.32518f,  2.35156f,
+    2.37886f,  2.40717f,  2.43655f,  2.46709f,
+    2.49889f,  2.53206f,  2.56673f,  2.60305f,
+    2.64117f,  2.6813f,  2.72367f,  2.76854f,
+    2.81623f,  2.86714f,  2.92173f,  2.98059f,
+    3.04446f,  3.1143f,  3.19135f,  3.27731f,
+    3.37455f,  3.48653f,  3.61862f,  3.77982f,
+    3.98692f,  4.2776f,  4.77167f,  133.333f
+};
+
 
 struct MSCRNode;
 
@@ -691,6 +617,56 @@ struct TempMSCR
 
 struct MSCRNode
 {
+    // the stable mscr should be:
+    // bigger than minArea and smaller than maxArea
+    // differ from its ancestor more than minDiversity
+    bool isStable( const MSER_Impl::Params& params ) const
+    {
+        if( size <= params.minArea || size >= params.maxArea )
+            return 0;
+        if( gmsr == NULL )
+            return 1;
+        double div = (double)(size - gmsr->size)/(double)size;
+        return div > params.minDiversity;
+    }
+
+    void init( int _index )
+    {
+        gmsr = tmsr = NULL;
+        reinit = 0xffff;
+        rank = 0;
+        sizei = size = 1;
+        prev = next = shortcut = this;
+        index = _index;
+    }
+
+    // to find the root of one region
+    MSCRNode* findRoot()
+    {
+        MSCRNode* x = this;
+        MSCRNode* _prev = x;
+        MSCRNode* _next;
+        for(;;)
+        {
+            _next = x->shortcut;
+            x->shortcut = _prev;
+            if( _next == x )
+                break;
+            _prev = x;
+            x = _next;
+        }
+        MSCRNode* root = x;
+        for(;;)
+        {
+            _prev = x->shortcut;
+            x->shortcut = root;
+            if( _prev == x )
+                break;
+            x = _prev;
+        }
+        return root;
+    }
+
     MSCRNode* shortcut;
     // to make the finding of root less painful
     MSCRNode* prev;
@@ -711,348 +687,86 @@ struct MSCRNode
 
 struct MSCREdge
 {
-    double chi;
+    double init(float _chi, MSCRNode* _left, MSCRNode* _right)
+    {
+        chi = _chi;
+        left = _left;
+        right = _right;
+        return chi;
+    }
+    float chi;
     MSCRNode* left;
     MSCRNode* right;
 };
 
-static double ChiSquaredDistance( uchar* x, uchar* y )
+static float ChiSquaredDistance( const uchar* x, const uchar* y )
 {
-    return (double)((x[0]-y[0])*(x[0]-y[0]))/(double)(x[0]+y[0]+1e-10)+
-           (double)((x[1]-y[1])*(x[1]-y[1]))/(double)(x[1]+y[1]+1e-10)+
-           (double)((x[2]-y[2])*(x[2]-y[2]))/(double)(x[2]+y[2]+1e-10);
+    return (float)((x[0]-y[0])*(x[0]-y[0]))/(float)(x[0]+y[0]+FLT_EPSILON)+
+           (float)((x[1]-y[1])*(x[1]-y[1]))/(float)(x[1]+y[1]+FLT_EPSILON)+
+           (float)((x[2]-y[2])*(x[2]-y[2]))/(float)(x[2]+y[2]+FLT_EPSILON);
 }
 
-static void initMSCRNode( MSCRNode* node )
-{
-    node->gmsr = node->tmsr = NULL;
-    node->reinit = 0xffff;
-    node->rank = 0;
-    node->sizei = node->size = 1;
-    node->prev = node->next = node->shortcut = node;
-}
 
 // the preprocess to get the edge list with proper gaussian blur
-static int preprocessMSER_8UC3( MSCRNode* node,
-            MSCREdge* edge,
-            double* total,
-            CvMat* src,
-            CvMat* mask,
-            CvMat* dx,
-            CvMat* dy,
-            int Ne,
-            int edgeBlurSize )
+static int preprocessMSER_8UC3( MSCRNode* node, MSCREdge* edge,
+                                double& total, const Mat& src,
+                                Mat& dx, Mat& dy, int Ne, int edgeBlurSize )
 {
-    int srccpt = src->step-src->cols*3;
-    uchar* srcptr = src->data.ptr;
-    uchar* lastptr = src->data.ptr+3;
-    double* dxptr = dx->data.db;
-    for ( int i = 0; i < src->rows; i++ )
-    {
-        for ( int j = 0; j < src->cols-1; j++ )
-        {
-            *dxptr = ChiSquaredDistance( srcptr, lastptr );
-            dxptr++;
-            srcptr += 3;
-            lastptr += 3;
-        }
-        srcptr += srccpt+3;
-        lastptr += srccpt+3;
-    }
-    srcptr = src->data.ptr;
-    lastptr = src->data.ptr+src->step;
-    double* dyptr = dy->data.db;
-    for ( int i = 0; i < src->rows-1; i++ )
+    int nch = src.channels();
+    int i, j, nrows = src.rows, ncols = src.cols;
+    float* dxptr = 0;
+    float* dyptr = 0;
+    for( i = 0; i < nrows; i++ )
     {
-        for ( int j = 0; j < src->cols; j++ )
+        const uchar* srcptr = src.ptr(i);
+        const uchar* nextsrc = src.ptr(std::min(i+1, nrows-1));
+        dxptr = dx.ptr<float>(i);
+        dyptr = dy.ptr<float>(i);
+
+        for( j = 0; j < ncols-1; j++ )
         {
-            *dyptr = ChiSquaredDistance( srcptr, lastptr );
-            dyptr++;
-            srcptr += 3;
-            lastptr += 3;
+            dxptr[j] = ChiSquaredDistance( srcptr + j*nch, srcptr + (j+1)*nch );
+            dyptr[j] = ChiSquaredDistance( srcptr + j*nch, nextsrc + j*nch );
         }
-        srcptr += srccpt;
-        lastptr += srccpt;
+        dyptr[ncols-1] = ChiSquaredDistance( srcptr + (ncols-1)*nch, nextsrc + (ncols-1)*nch );
     }
+
     // get dx and dy and blur it
-    if ( edgeBlurSize >= 1 )
+    if( edgeBlurSize >= 1 )
     {
-        cvSmooth( dx, dx, CV_GAUSSIAN, edgeBlurSize, edgeBlurSize );
-        cvSmooth( dy, dy, CV_GAUSSIAN, edgeBlurSize, edgeBlurSize );
+        GaussianBlur(dx, dx, Size(edgeBlurSize, edgeBlurSize), 0);
+        GaussianBlur(dy, dy, Size(edgeBlurSize, edgeBlurSize), 0);
     }
-    dxptr = dx->data.db;
-    dyptr = dy->data.db;
+    dxptr = dx.ptr<float>();
+    dyptr = dy.ptr<float>();
     // assian dx, dy to proper edge list and initialize mscr node
     // the nasty code here intended to avoid extra loops
-    if ( mask )
+    MSCRNode* nodeptr = node;
+    for( j = 0; j < ncols-1; j++ )
     {
-        Ne = 0;
-        int maskcpt = mask->step-mask->cols+1;
-        uchar* maskptr = mask->data.ptr;
-        MSCRNode* nodeptr = node;
-        initMSCRNode( nodeptr );
-        nodeptr->index = 0;
-        *total += edge->chi = *dxptr;
-        if ( maskptr[0] && maskptr[1] )
-        {
-            edge->left = nodeptr;
-            edge->right = nodeptr+1;
-            edge++;
-            Ne++;
-        }
-        dxptr++;
-        nodeptr++;
-        maskptr++;
-        for ( int i = 1; i < src->cols-1; i++ )
-        {
-            initMSCRNode( nodeptr );
-            nodeptr->index = i;
-            if ( maskptr[0] && maskptr[1] )
-            {
-                *total += edge->chi = *dxptr;
-                edge->left = nodeptr;
-                edge->right = nodeptr+1;
-                edge++;
-                Ne++;
-            }
-            dxptr++;
-            nodeptr++;
-            maskptr++;
-        }
-        initMSCRNode( nodeptr );
-        nodeptr->index = src->cols-1;
-        nodeptr++;
-        maskptr += maskcpt;
-        for ( int i = 1; i < src->rows-1; i++ )
-        {
-            initMSCRNode( nodeptr );
-            nodeptr->index = i<<16;
-            if ( maskptr[0] )
-            {
-                if ( maskptr[-mask->step] )
-                {
-                    *total += edge->chi = *dyptr;
-                    edge->left = nodeptr-src->cols;
-                    edge->right = nodeptr;
-                    edge++;
-                    Ne++;
-                }
-                if ( maskptr[1] )
-                {
-                    *total += edge->chi = *dxptr;
-                    edge->left = nodeptr;
-                    edge->right = nodeptr+1;
-                    edge++;
-                    Ne++;
-                }
-            }
-            dyptr++;
-            dxptr++;
-            nodeptr++;
-            maskptr++;
-            for ( int j = 1; j < src->cols-1; j++ )
-            {
-                initMSCRNode( nodeptr );
-                nodeptr->index = (i<<16)|j;
-                if ( maskptr[0] )
-                {
-                    if ( maskptr[-mask->step] )
-                    {
-                        *total += edge->chi = *dyptr;
-                        edge->left = nodeptr-src->cols;
-                        edge->right = nodeptr;
-                        edge++;
-                        Ne++;
-                    }
-                    if ( maskptr[1] )
-                    {
-                        *total += edge->chi = *dxptr;
-                        edge->left = nodeptr;
-                        edge->right = nodeptr+1;
-                        edge++;
-                        Ne++;
-                    }
-                }
-                dyptr++;
-                dxptr++;
-                nodeptr++;
-                maskptr++;
-            }
-            initMSCRNode( nodeptr );
-            nodeptr->index = (i<<16)|(src->cols-1);
-            if ( maskptr[0] && maskptr[-mask->step] )
-            {
-                *total += edge->chi = *dyptr;
-                edge->left = nodeptr-src->cols;
-                edge->right = nodeptr;
-                edge++;
-                Ne++;
-            }
-            dyptr++;
-            nodeptr++;
-            maskptr += maskcpt;
-        }
-        initMSCRNode( nodeptr );
-        nodeptr->index = (src->rows-1)<<16;
-        if ( maskptr[0] )
-        {
-            if ( maskptr[1] )
-            {
-                *total += edge->chi = *dxptr;
-                edge->left = nodeptr;
-                edge->right = nodeptr+1;
-                edge++;
-                Ne++;
-            }
-            if ( maskptr[-mask->step] )
-            {
-                *total += edge->chi = *dyptr;
-                edge->left = nodeptr-src->cols;
-                edge->right = nodeptr;
-                edge++;
-                Ne++;
-            }
-        }
-        dxptr++;
-        dyptr++;
-        nodeptr++;
-        maskptr++;
-        for ( int i = 1; i < src->cols-1; i++ )
-        {
-            initMSCRNode( nodeptr );
-            nodeptr->index = ((src->rows-1)<<16)|i;
-            if ( maskptr[0] )
-            {
-                if ( maskptr[1] )
-                {
-                    *total += edge->chi = *dxptr;
-                    edge->left = nodeptr;
-                    edge->right = nodeptr+1;
-                    edge++;
-                    Ne++;
-                }
-                if ( maskptr[-mask->step] )
-                {
-                    *total += edge->chi = *dyptr;
-                    edge->left = nodeptr-src->cols;
-                    edge->right = nodeptr;
-                    edge++;
-                    Ne++;
-                }
-            }
-            dxptr++;
-            dyptr++;
-            nodeptr++;
-            maskptr++;
-        }
-        initMSCRNode( nodeptr );
-        nodeptr->index = ((src->rows-1)<<16)|(src->cols-1);
-        if ( maskptr[0] && maskptr[-mask->step] )
-        {
-            *total += edge->chi = *dyptr;
-            edge->left = nodeptr-src->cols;
-            edge->right = nodeptr;
-            Ne++;
-        }
-    } else {
-        MSCRNode* nodeptr = node;
-        initMSCRNode( nodeptr );
-        nodeptr->index = 0;
-        *total += edge->chi = *dxptr;
-        dxptr++;
-        edge->left = nodeptr;
-        edge->right = nodeptr+1;
-        edge++;
-        nodeptr++;
-        for ( int i = 1; i < src->cols-1; i++ )
-        {
-            initMSCRNode( nodeptr );
-            nodeptr->index = i;
-            *total += edge->chi = *dxptr;
-            dxptr++;
-            edge->left = nodeptr;
-            edge->right = nodeptr+1;
-            edge++;
-            nodeptr++;
-        }
-        initMSCRNode( nodeptr );
-        nodeptr->index = src->cols-1;
-        nodeptr++;
-        for ( int i = 1; i < src->rows-1; i++ )
-        {
-            initMSCRNode( nodeptr );
-            nodeptr->index = i<<16;
-            *total += edge->chi = *dyptr;
-            dyptr++;
-            edge->left = nodeptr-src->cols;
-            edge->right = nodeptr;
-            edge++;
-            *total += edge->chi = *dxptr;
-            dxptr++;
-            edge->left = nodeptr;
-            edge->right = nodeptr+1;
-            edge++;
-            nodeptr++;
-            for ( int j = 1; j < src->cols-1; j++ )
-            {
-                initMSCRNode( nodeptr );
-                nodeptr->index = (i<<16)|j;
-                *total += edge->chi = *dyptr;
-                dyptr++;
-                edge->left = nodeptr-src->cols;
-                edge->right = nodeptr;
-                edge++;
-                *total += edge->chi = *dxptr;
-                dxptr++;
-                edge->left = nodeptr;
-                edge->right = nodeptr+1;
-                edge++;
-                nodeptr++;
-            }
-            initMSCRNode( nodeptr );
-            nodeptr->index = (i<<16)|(src->cols-1);
-            *total += edge->chi = *dyptr;
-            dyptr++;
-            edge->left = nodeptr-src->cols;
-            edge->right = nodeptr;
-            edge++;
-            nodeptr++;
-        }
-        initMSCRNode( nodeptr );
-        nodeptr->index = (src->rows-1)<<16;
-        *total += edge->chi = *dxptr;
-        dxptr++;
-        edge->left = nodeptr;
-        edge->right = nodeptr+1;
-        edge++;
-        *total += edge->chi = *dyptr;
-        dyptr++;
-        edge->left = nodeptr-src->cols;
-        edge->right = nodeptr;
-        edge++;
-        nodeptr++;
-        for ( int i = 1; i < src->cols-1; i++ )
+        nodeptr[j].init(j);
+        total += edge[j].init(dxptr[j], nodeptr+j, nodeptr+j+1);
+    }
+    dxptr += ncols - 1;
+    edge += ncols - 1;
+    nodeptr[ncols-1].init(ncols - 1);
+    nodeptr += ncols;
+    for( i = 1; i < nrows; i++ )
+    {
+        for( j = 0; j < ncols-1; j++ )
         {
-            initMSCRNode( nodeptr );
-            nodeptr->index = ((src->rows-1)<<16)|i;
-            *total += edge->chi = *dxptr;
-            dxptr++;
-            edge->left = nodeptr;
-            edge->right = nodeptr+1;
-            edge++;
-            *total += edge->chi = *dyptr;
-            dyptr++;
-            edge->left = nodeptr-src->cols;
-            edge->right = nodeptr;
-            edge++;
-            nodeptr++;
+            nodeptr[j].init( (i<<16)|j );
+            total += edge[j*2].init(dyptr[j], nodeptr + j - ncols, nodeptr + j);
+            total += edge[j*2+1].init(dxptr[j], nodeptr + j, nodeptr + j + 1);
         }
-        initMSCRNode( nodeptr );
-        nodeptr->index = ((src->rows-1)<<16)|(src->cols-1);
-        *total += edge->chi = *dyptr;
-        edge->left = nodeptr-src->cols;
-        edge->right = nodeptr;
+        nodeptr[ncols-1].init((i<<16)|(ncols - 1));
+        total += edge[(ncols-1)*2].init(dyptr[ncols-1], nodeptr - 1, nodeptr + ncols-1);
+        dxptr += ncols-1;
+        dyptr += ncols;
+        edge += 2*ncols - 1;
+        nodeptr += ncols;
     }
+
     return Ne;
 }
 
@@ -1062,63 +776,34 @@ public:
     bool operator()(const MSCREdge& a, const MSCREdge& b) const { return a.chi < b.chi; }
 };
 
-// to find the root of one region
-static MSCRNode* findMSCR( MSCRNode* x )
-{
-    MSCRNode* prev = x;
-    MSCRNode* next;
-    for ( ; ; )
-    {
-        next = x->shortcut;
-        x->shortcut = prev;
-        if ( next == x ) break;
-        prev= x;
-        x = next;
-    }
-    MSCRNode* root = x;
-    for ( ; ; )
-    {
-        prev = x->shortcut;
-        x->shortcut = root;
-        if ( prev == x ) break;
-        x = prev;
-    }
-    return root;
-}
-
-// the stable mscr should be:
-// bigger than minArea and smaller than maxArea
-// differ from its ancestor more than minDiversity
-static bool MSCRStableCheck( MSCRNode* x, MSERParams params )
-{
-    if ( x->size <= params.minArea || x->size >= params.maxArea )
-        return 0;
-    if ( x->gmsr == NULL )
-        return 1;
-    double div = (double)(x->size-x->gmsr->size)/(double)x->size;
-    return div > params.minDiversity;
-}
 
 static void
-extractMSER_8UC3( CvMat* src,
-             CvMat* mask,
-             CvSeq* contours,
-             CvMemStorage* storage,
-             MSERParams params )
+extractMSER_8uC3( const Mat& src, Mat& labels,
+                  vector<Rect>& bboxvec,
+                  const MSER_Impl::Params& params )
 {
-    MSCRNode* map = (MSCRNode*)cvAlloc( src->cols*src->rows*sizeof(map[0]) );
-    int Ne = src->cols*src->rows*2-src->cols-src->rows;
-    MSCREdge* edge = (MSCREdge*)cvAlloc( Ne*sizeof(edge[0]) );
-    TempMSCR* mscr = (TempMSCR*)cvAlloc( src->cols*src->rows*sizeof(mscr[0]) );
+    int npixels = src.cols*src.rows;
+    int currlabel = 0;
+    int* lptr = labels.ptr<int>();
+    int lstep = (int)(labels.step/sizeof(int));
+
+    vector<MSCRNode> mapvec(npixels);
+    MSCRNode* map = &mapvec[0];
+    int Ne = npixels*2 - src.cols - src.rows;
+    vector<MSCREdge> edgevec(Ne+1);
+    MSCREdge* edge = &edgevec[0];
+    vector<TempMSCR> mscrvec(npixels);
+    TempMSCR* mscr = &mscrvec[0];
     double emean = 0;
-    CvMat* dx = cvCreateMat( src->rows, src->cols-1, CV_64FC1 );
-    CvMat* dy = cvCreateMat( src->rows-1, src->cols, CV_64FC1 );
-    Ne = preprocessMSER_8UC3( map, edge, &emean, src, mask, dx, dy, Ne, params.edgeBlurSize );
+    Mat dx( src.rows, src.cols-1, CV_32FC1 );
+    Mat dy( src.rows, src.cols, CV_32FC1 );
+    Ne = preprocessMSER_8UC3( map, edge, emean, src, dx, dy, Ne, params.edgeBlurSize );
     emean = emean / (double)Ne;
     std::sort(edge, edge + Ne, LessThanEdge());
     MSCREdge* edge_ub = edge+Ne;
     MSCREdge* edgeptr = edge;
     TempMSCR* mscrptr = mscr;
+
     // the evolution process
     for ( int i = 0; i < params.maxEvolution; i++ )
     {
@@ -1127,23 +812,24 @@ extractMSER_8UC3( CvMat* src,
         double reminder = k-ti;
         double thres = emean*(chitab3[ti]*(1-reminder)+chitab3[ti+1]*reminder);
         // to process all the edges in the list that chi < thres
-        while ( edgeptr < edge_ub && edgeptr->chi < thres )
+        while( edgeptr < edge_ub && edgeptr->chi < thres )
         {
-            MSCRNode* lr = findMSCR( edgeptr->left );
-            MSCRNode* rr = findMSCR( edgeptr->right );
+            MSCRNode* lr = edgeptr->left->findRoot();
+            MSCRNode* rr = edgeptr->right->findRoot();
             // get the region root (who is responsible)
             if ( lr != rr )
             {
+                MSCRNode* tmp;
                 // rank idea take from: N-tree Disjoint-Set Forests for Maximally Stable Extremal Regions
                 if ( rr->rank > lr->rank )
                 {
-                    MSCRNode* tmp;
                     CV_SWAP( lr, rr, tmp );
-                } else if ( lr->rank == rr->rank ) {
+                }
+                else if ( lr->rank == rr->rank )
+                {
                     // at the same rank, we will compare the size
-                    if ( lr->size > rr->size )
+                    if( lr->size > rr->size )
                     {
-                        MSCRNode* tmp;
                         CV_SWAP( lr, rr, tmp );
                     }
                     lr->rank++;
@@ -1175,7 +861,7 @@ extractMSER_8UC3( CvMat* src,
                     if ( s < lr->s )
                     {
                         // skip the first one and check stablity
-                        if ( i > lr->reinit+1 && MSCRStableCheck( lr, params ) )
+                        if ( i > lr->reinit+1 && lr->isStable( params ) )
                         {
                             if ( lr->tmsr == NULL )
                             {
@@ -1196,113 +882,124 @@ extractMSER_8UC3( CvMat* src,
         if ( edgeptr >= edge_ub )
             break;
     }
-    for ( TempMSCR* ptr = mscr; ptr < mscrptr; ptr++ )
+
+    for( TempMSCR* ptr = mscr; ptr < mscrptr; ptr++ )
+    {
         // to prune area with margin less than minMargin
-        if ( ptr->m > params.minMargin )
+        if( ptr->m > params.minMargin )
         {
-            CvSeq* _contour = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage );
-            cvSeqPushMulti( _contour, 0, ptr->size );
+            int xmin = INT_MAX, ymin = INT_MAX, xmax = INT_MIN, ymax = INT_MIN;
+            currlabel++;
             MSCRNode* lpt = ptr->head;
-            for ( int i = 0; i < ptr->size; i++ )
+            for( int i = 0; i < ptr->size; i++ )
             {
-                CvPoint* pt = CV_GET_SEQ_ELEM( CvPoint, _contour, i );
-                pt->x = (lpt->index)&0xffff;
-                pt->y = (lpt->index)>>16;
+                int x = (lpt->index)&0xffff;
+                int y = (lpt->index)>>16;
                 lpt = lpt->next;
+
+                xmin = std::min(xmin, x);
+                xmax = std::max(xmax, x);
+                ymin = std::min(ymin, y);
+                ymax = std::max(ymax, y);
+
+                lptr[lstep*y + x] = currlabel;
             }
-            CvContour* contour = (CvContour*)_contour;
-            cvBoundingRect( contour );
-            contour->color = 0;
-            cvSeqPush( contours, &contour );
+            bboxvec.push_back(Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1));
         }
-    cvReleaseMat( &dx );
-    cvReleaseMat( &dy );
-    cvFree( &mscr );
-    cvFree( &edge );
-    cvFree( &map );
+    }
 }
 
-static void
-extractMSER( CvArr* _img,
-           CvArr* _mask,
-           CvSeq** _contours,
-           CvMemStorage* storage,
-           MSERParams params )
+int MSER_Impl::detectAndLabel( InputArray _src, OutputArray _labels, OutputArray _bboxes )
 {
-    CvMat srchdr, *src = cvGetMat( _img, &srchdr );
-    CvMat maskhdr, *mask = _mask ? cvGetMat( _mask, &maskhdr ) : 0;
-    CvSeq* contours = 0;
-
-    CV_Assert(src != 0);
-    CV_Assert(CV_MAT_TYPE(src->type) == CV_8UC1 || CV_MAT_TYPE(src->type) == CV_8UC3);
-    CV_Assert(mask == 0 || (CV_ARE_SIZES_EQ(src, mask) && CV_MAT_TYPE(mask->type) == CV_8UC1));
-    CV_Assert(storage != 0);
+    Mat src = _src.getMat();
+    size_t npix = src.total();
+    vector<Rect> bboxvec;
 
-    contours = *_contours = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSeq*), storage );
-
-    // choose different method for different image type
-    // for grey image, it is: Linear Time Maximally Stable Extremal Regions
-    // for color image, it is: Maximally Stable Colour Regions for Recognition and Matching
-    switch ( CV_MAT_TYPE(src->type) )
+    if( npix == 0 )
     {
-        case CV_8UC1:
-            extractMSER_8UC1( src, mask, contours, storage, params );
-            break;
-        case CV_8UC3:
-            extractMSER_8UC3( src, mask, contours, storage, params );
-            break;
+        _labels.release();
+        return 0;
     }
-}
 
+    Size size = src.size();
+    _labels.create( size, CV_32S );
+    Mat labels = _labels.getMat();
+    labels.setTo(Scalar::all(0));
 
-MSER::MSER( int _delta, int _min_area, int _max_area,
-      double _max_variation, double _min_diversity,
-      int _max_evolution, double _area_threshold,
-      double _min_margin, int _edge_blur_size )
-    : delta(_delta), minArea(_min_area), maxArea(_max_area),
-    maxVariation(_max_variation), minDiversity(_min_diversity),
-    maxEvolution(_max_evolution), areaThreshold(_area_threshold),
-    minMargin(_min_margin), edgeBlurSize(_edge_blur_size)
-{
-}
+    if( src.type() == CV_8U )
+    {
+        int level_size[256];
+        int lval = 1;
 
-void MSER::operator()( InputArray image, std::vector<std::vector<Point> >& dstcontours, InputArray mask ) const
-{
-    CvMat _image = image.getMat(), _mask, *pmask = 0;
-    if( !mask.empty() )
-        pmask = &(_mask = mask.getMat());
-    MemStorage storage(cvCreateMemStorage(0));
-    Seq<CvSeq*> contours;
-    extractMSER( &_image, pmask, &contours.seq, storage,
-                 MSERParams(delta, minArea, maxArea, maxVariation, minDiversity,
-                            maxEvolution, areaThreshold, minMargin, edgeBlurSize));
-    SeqIterator<CvSeq*> it = contours.begin();
-    size_t i, ncontours = contours.size();
-    dstcontours.resize(ncontours);
-    for( i = 0; i < ncontours; i++, ++it )
-        Seq<Point>(*it).copyTo(dstcontours[i]);
-}
+        if( !src.isContinuous() )
+        {
+            src.copyTo(tempsrc);
+            src = tempsrc;
+        }
 
+        // darker to brighter (MSER+)
+        preprocess1( src, level_size );
+        if( !params.pass2Only )
+            pass( src, labels, lval, bboxvec, size, level_size, 0 );
+        // brighter to darker (MSER-)
+        preprocess2( src, level_size );
+        pass( src, labels, lval, bboxvec, size, level_size, 255 );
+    }
+    else
+    {
+        CV_Assert( src.type() == CV_8UC3 || src.type() == CV_8UC4 );
+        extractMSER_8uC3( src, labels, bboxvec, params );
+    }
+    if( _bboxes.needed() )
+        Mat(bboxvec).copyTo(_bboxes);
+    return (int)bboxvec.size();
+}
 
-void MserFeatureDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) const
+void MSER_Impl::detect( InputArray _image, vector<KeyPoint>& keypoints, InputArray _mask )
 {
-    Mat image = _image.getMat(), mask = _mask.getMat();
-    std::vector<std::vector<Point> > msers;
+    vector<Rect> bboxes;
+    vector<Point> reg;
+    Mat labels, mask = _mask.getMat();
 
-    (*this)(image, msers, mask);
+    int i, x, y, ncomps = detectAndLabel(_image, labels, bboxes);
+    CV_Assert( ncomps == (int)bboxes.size() );
 
-    std::vector<std::vector<Point> >::const_iterator contour_it = msers.begin();
-    Rect r(0, 0, image.cols, image.rows);
-    for( ; contour_it != msers.end(); ++contour_it )
+    keypoints.clear();
+    for( i = 0; i < ncomps; i++ )
     {
+        Rect r = bboxes[i];
+        reg.reserve(r.area());
+        reg.clear();
+
+        for( y = r.y; y < r.y + r.height; y++ )
+        {
+            const int* lptr = labels.ptr<int>(y);
+            for( x = r.x; x < r.x + r.width; x++ )
+            {
+                if( lptr[x] == i+1 )
+                    reg.push_back(Point(x, y));
+            }
+        }
         // TODO check transformation from MSER region to KeyPoint
-        RotatedRect rect = fitEllipse(Mat(*contour_it));
+        RotatedRect rect = fitEllipse(Mat(reg));
         float diam = std::sqrt(rect.size.height*rect.size.width);
 
-        if( diam > std::numeric_limits<float>::epsilon() && r.contains(rect.center) )
+        if( diam > std::numeric_limits<float>::epsilon() && r.contains(rect.center) &&
+            (mask.empty() || mask.at<uchar>(cvRound(rect.center.y), cvRound(rect.center.x)) != 0) )
             keypoints.push_back( KeyPoint(rect.center, diam) );
     }
+}
 
+Ptr<MSER> MSER::create( int _delta, int _min_area, int _max_area,
+      double _max_variation, double _min_diversity,
+      int _max_evolution, double _area_threshold,
+      double _min_margin, int _edge_blur_size )
+{
+    return makePtr<MSER_Impl>(
+        MSER_Impl::Params(_delta, _min_area, _max_area,
+                          _max_variation, _min_diversity,
+                          _max_evolution, _area_threshold,
+                          _min_margin, _edge_blur_size));
 }
 
 }
index af91fb6..d7b8fce 100644 (file)
@@ -664,19 +664,11 @@ public:
     int defaultNorm() const;
 
     // Compute the ORB_Impl features and descriptors on an image
-    void operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const;
-
-    // Compute the ORB_Impl features and descriptors on an image
-    void operator()( InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints,
-                     OutputArray descriptors, bool useProvidedKeypoints=false ) const;
-
-    AlgorithmInfo* info() const;
+    void detectAndCompute( InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints,
+                     OutputArray descriptors, bool useProvidedKeypoints=false );
 
 protected:
 
-    void computeImpl( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const;
-    void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
-
     int nfeatures;
     double scaleFactor;
     int nlevels;
@@ -703,17 +695,6 @@ int ORB_Impl::defaultNorm() const
     return NORM_HAMMING;
 }
 
-/** Compute the ORB_Impl features and descriptors on an image
- * @param img the image to compute the features and descriptors on
- * @param mask the mask to apply
- * @param keypoints the resulting keypoints
- */
-void ORB_Impl::operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const
-{
-    (*this)(image, mask, keypoints, noArray(), false);
-}
-
-
 static void uploadORBKeypoints(const std::vector<KeyPoint>& src, std::vector<Vec3i>& buf, OutputArray dst)
 {
     size_t i, n = src.size();
@@ -813,8 +794,10 @@ static void computeKeyPoints(const Mat& imagePyramid,
         Mat mask = maskPyramid.empty() ? Mat() : maskPyramid(layerInfo[level]);
 
         // Detect FAST features, 20 is a good threshold
-        FastFeatureDetector fd(fastThreshold, true);
-        fd.detect(img, keypoints, mask);
+        {
+        Ptr<FastFeatureDetector> fd = FastFeatureDetector::create(fastThreshold, true);
+        fd->detect(img, keypoints, mask);
+        }
 
         // Remove keypoints very close to the border
         KeyPointsFilter::runByImageBorder(keypoints, img.size(), edgeThreshold);
@@ -926,8 +909,9 @@ static void computeKeyPoints(const Mat& imagePyramid,
  * @param do_keypoints if true, the keypoints are computed, otherwise used as an input
  * @param do_descriptors if true, also computes the descriptors
  */
-void ORB_Impl::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
-                      OutputArray _descriptors, bool useProvidedKeypoints ) const
+void ORB_Impl::detectAndCompute( InputArray _image, InputArray _mask,
+                                 std::vector<KeyPoint>& keypoints,
+                                 OutputArray _descriptors, bool useProvidedKeypoints )
 {
     CV_Assert(patchSize >= 2);
 
@@ -1153,15 +1137,11 @@ void ORB_Impl::operator()( InputArray _image, InputArray _mask, std::vector<KeyP
     }
 }
 
-void ORB_Impl::detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const
+Ptr<ORB> ORB::create(int nfeatures, float scaleFactor, int nlevels, int edgeThreshold,
+           int firstLevel, int WTA_K, int scoreType, int patchSize, int fastThreshold)
 {
-    (*this)(image.getMat(), mask.getMat(), keypoints, noArray(), false);
+    return makePtr<ORB_Impl>(nfeatures, scaleFactor, nlevels, edgeThreshold,
+                             firstLevel, WTA_K, scoreType, patchSize, fastThreshold);
 }
 
-void ORB_Impl::computeImpl( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const
-{
-    (*this)(image, Mat(), keypoints, descriptors, true);
-}
-
-
 }
index c09a466..baffeeb 100644 (file)
@@ -314,31 +314,34 @@ private:
 
 TEST( Features2d_DescriptorExtractor_BRISK, regression )
 {
-    CV_DescriptorExtractorTest<Hamming> test( "descriptor-brisk",  (CV_DescriptorExtractorTest<Hamming>::DistanceType)2.f,
-                                                 DescriptorExtractor::create("BRISK") );
+    CV_DescriptorExtractorTest<Hamming> test( "descriptor-brisk",
+                                             (CV_DescriptorExtractorTest<Hamming>::DistanceType)2.f,
+                                            BRISK::create() );
     test.safe_run();
 }
 
 TEST( Features2d_DescriptorExtractor_ORB, regression )
 {
     // TODO adjust the parameters below
-    CV_DescriptorExtractorTest<Hamming> test( "descriptor-orb",  (CV_DescriptorExtractorTest<Hamming>::DistanceType)12.f,
-                                                 DescriptorExtractor::create("ORB") );
+    CV_DescriptorExtractorTest<Hamming> test( "descriptor-orb",
+                                              (CV_DescriptorExtractorTest<Hamming>::DistanceType)12.f,
+                                             ORB::create() );
     test.safe_run();
 }
 
 TEST( Features2d_DescriptorExtractor_KAZE, regression )
 {
     CV_DescriptorExtractorTest< L2<float> > test( "descriptor-kaze",  0.03f,
-                                                 DescriptorExtractor::create("KAZE"),
-                                                 L2<float>(), FeatureDetector::create("KAZE"));
+                                                 KAZE::create(),
+                                                 L2<float>() );
     test.safe_run();
 }
 
 TEST( Features2d_DescriptorExtractor_AKAZE, regression )
 {
-    CV_DescriptorExtractorTest<Hamming> test( "descriptor-akaze",  (CV_DescriptorExtractorTest<Hamming>::DistanceType)12.f,
-                                              DescriptorExtractor::create("AKAZE"),
-                                              Hamming(), FeatureDetector::create("AKAZE"));
+    CV_DescriptorExtractorTest<Hamming> test( "descriptor-akaze",
+                                              (CV_DescriptorExtractorTest<Hamming>::DistanceType)12.f,
+                                              AKAZE::create(),
+                                              Hamming(), AKAZE::create());
     test.safe_run();
 }
index 1a7d09a..a3ca0a9 100644 (file)
@@ -249,48 +249,48 @@ void CV_FeatureDetectorTest::run( int /*start_from*/ )
 
 TEST( Features2d_Detector_BRISK, regression )
 {
-    CV_FeatureDetectorTest test( "detector-brisk", FeatureDetector::create("BRISK") );
+    CV_FeatureDetectorTest test( "detector-brisk", BRISK::create() );
     test.safe_run();
 }
 
 TEST( Features2d_Detector_FAST, regression )
 {
-    CV_FeatureDetectorTest test( "detector-fast", FeatureDetector::create("FAST") );
+    CV_FeatureDetectorTest test( "detector-fast", FastFeatureDetector::create() );
     test.safe_run();
 }
 
 TEST( Features2d_Detector_GFTT, regression )
 {
-    CV_FeatureDetectorTest test( "detector-gftt", FeatureDetector::create("GFTT") );
+    CV_FeatureDetectorTest test( "detector-gftt", GFTTDetector::create() );
     test.safe_run();
 }
 
 TEST( Features2d_Detector_Harris, regression )
 {
-    CV_FeatureDetectorTest test( "detector-harris", FeatureDetector::create("HARRIS") );
+    CV_FeatureDetectorTest test( "detector-harris", GFTTDetector::create(1000, 0.01, 1, 3, true, 0.04));
     test.safe_run();
 }
 
 TEST( Features2d_Detector_MSER, DISABLED_regression )
 {
-    CV_FeatureDetectorTest test( "detector-mser", FeatureDetector::create("MSER") );
+    CV_FeatureDetectorTest test( "detector-mser", MSER::create() );
     test.safe_run();
 }
 
 TEST( Features2d_Detector_ORB, regression )
 {
-    CV_FeatureDetectorTest test( "detector-orb", FeatureDetector::create("ORB") );
+    CV_FeatureDetectorTest test( "detector-orb", ORB::create() );
     test.safe_run();
 }
 
 TEST( Features2d_Detector_KAZE, regression )
 {
-    CV_FeatureDetectorTest test( "detector-kaze", FeatureDetector::create("KAZE") );
+    CV_FeatureDetectorTest test( "detector-kaze", KAZE::create() );
     test.safe_run();
 }
 
 TEST( Features2d_Detector_AKAZE, regression )
 {
-    CV_FeatureDetectorTest test( "detector-akaze", FeatureDetector::create("AKAZE") );
+    CV_FeatureDetectorTest test( "detector-akaze", AKAZE::create() );
     test.safe_run();
 }
index 349c03e..561c3cc 100644 (file)
@@ -61,7 +61,6 @@ public:
 protected:
     virtual void run(int)
     {
-        cv::initModule_features2d();
         CV_Assert(detector);
         string imgFilename = string(ts->get_data_path()) + FEATURES2D_DIR + "/" + IMAGE_FILENAME;
 
@@ -121,51 +120,51 @@ protected:
 
 TEST(Features2d_Detector_Keypoints_BRISK, validation)
 {
-    CV_FeatureDetectorKeypointsTest test(Algorithm::create<FeatureDetector>("Feature2D.BRISK"));
+    CV_FeatureDetectorKeypointsTest test(BRISK::create());
     test.safe_run();
 }
 
 TEST(Features2d_Detector_Keypoints_FAST, validation)
 {
-    CV_FeatureDetectorKeypointsTest test(Algorithm::create<FeatureDetector>("Feature2D.FAST"));
+    CV_FeatureDetectorKeypointsTest test(FastFeatureDetector::create());
     test.safe_run();
 }
 
 TEST(Features2d_Detector_Keypoints_HARRIS, validation)
 {
-    CV_FeatureDetectorKeypointsTest test(Algorithm::create<FeatureDetector>("Feature2D.HARRIS"));
+    CV_FeatureDetectorKeypointsTest test(GFTTDetector::create(1000, 0.01, 1, 3, true, 0.04));
     test.safe_run();
 }
 
 TEST(Features2d_Detector_Keypoints_GFTT, validation)
 {
-    CV_FeatureDetectorKeypointsTest test(Algorithm::create<FeatureDetector>("Feature2D.GFTT"));
+    CV_FeatureDetectorKeypointsTest test(GFTTDetector::create());
     test.safe_run();
 }
 
 TEST(Features2d_Detector_Keypoints_MSER, validation)
 {
-    CV_FeatureDetectorKeypointsTest test(Algorithm::create<FeatureDetector>("Feature2D.MSER"));
+    CV_FeatureDetectorKeypointsTest test(MSER::create());
     test.safe_run();
 }
 
 TEST(Features2d_Detector_Keypoints_ORB, validation)
 {
-    CV_FeatureDetectorKeypointsTest test(Algorithm::create<FeatureDetector>("Feature2D.ORB"));
+    CV_FeatureDetectorKeypointsTest test(ORB::create());
     test.safe_run();
 }
 
 TEST(Features2d_Detector_Keypoints_KAZE, validation)
 {
-    CV_FeatureDetectorKeypointsTest test(Algorithm::create<FeatureDetector>("Feature2D.KAZE"));
+    CV_FeatureDetectorKeypointsTest test(KAZE::create());
     test.safe_run();
 }
 
 TEST(Features2d_Detector_Keypoints_AKAZE, validation)
 {
-    CV_FeatureDetectorKeypointsTest test_kaze(cv::Ptr<FeatureDetector>(new cv::AKAZE(cv::DESCRIPTOR_KAZE)));
+    CV_FeatureDetectorKeypointsTest test_kaze(AKAZE::create(AKAZE::DESCRIPTOR_KAZE));
     test_kaze.safe_run();
 
-    CV_FeatureDetectorKeypointsTest test_mldb(cv::Ptr<FeatureDetector>(new cv::AKAZE(cv::DESCRIPTOR_MLDB)));
+    CV_FeatureDetectorKeypointsTest test_mldb(AKAZE::create(AKAZE::DESCRIPTOR_MLDB));
     test_mldb.safe_run();
 }
index 6b1b4ef..2957287 100644 (file)
@@ -43,6 +43,8 @@
 #include "test_precomp.hpp"
 #include "opencv2/imgproc/imgproc_c.h"
 
+#if 0
+
 #include <vector>
 #include <string>
 using namespace std;
@@ -205,3 +207,5 @@ void CV_MserTest::run(int)
 }
 
 TEST(Features2d_MSER, DISABLED_regression) { CV_MserTest test; test.safe_run(); }
+
+#endif
index 45e7690..47335b4 100644 (file)
@@ -47,10 +47,10 @@ using namespace cv;
 
 TEST(Features2D_ORB, _1996)
 {
-    Ptr<FeatureDetector> fd = FeatureDetector::create("ORB");
+    Ptr<FeatureDetector> fd = ORB::create();
     fd->set("nFeatures", 10000);//setting a higher maximum to make effect of threshold visible
     fd->set("fastThreshold", 20);//more features than the default
-    Ptr<DescriptorExtractor> de = DescriptorExtractor::create("ORB");
+    Ptr<DescriptorExtractor> de = fd;
 
     Mat image = imread(string(cvtest::TS::ptr()->get_data_path()) + "shared/lena.png");
     ASSERT_FALSE(image.empty());
index adb6fab..f1dec76 100644 (file)
@@ -367,7 +367,7 @@ void SurfFeaturesFinder::find(InputArray image, ImageFeatures &features)
     else
     {
         UMat descriptors;
-        (*surf)(gray_image, Mat(), features.keypoints, descriptors);
+        surf->detectAndCompute(gray_image, Mat(), features.keypoints, descriptors);
         features.descriptors = descriptors.reshape(1, (int)features.keypoints.size());
     }
 }
@@ -375,7 +375,7 @@ void SurfFeaturesFinder::find(InputArray image, ImageFeatures &features)
 OrbFeaturesFinder::OrbFeaturesFinder(Size _grid_size, int n_features, float scaleFactor, int nlevels)
 {
     grid_size = _grid_size;
-    orb = makePtr<ORB>(n_features * (99 + grid_size.area())/100/grid_size.area(), scaleFactor, nlevels);
+    orb = ORB::create(n_features * (99 + grid_size.area())/100/grid_size.area(), scaleFactor, nlevels);
 }
 
 void OrbFeaturesFinder::find(InputArray image, ImageFeatures &features)
@@ -395,7 +395,7 @@ void OrbFeaturesFinder::find(InputArray image, ImageFeatures &features)
     }
 
     if (grid_size.area() == 1)
-        (*orb)(gray_image, Mat(), features.keypoints, features.descriptors);
+        orb->detectAndCompute(gray_image, Mat(), features.keypoints, features.descriptors);
     else
     {
         features.keypoints.clear();
@@ -425,7 +425,7 @@ void OrbFeaturesFinder::find(InputArray image, ImageFeatures &features)
                 //     << " gray_image_part.dims=" << gray_image_part.dims << ", "
                 //     << " gray_image_part.data=" << ((size_t)gray_image_part.data) << "\n");
 
-                (*orb)(gray_image_part, UMat(), points, descriptors);
+                orb->detectAndCompute(gray_image_part, UMat(), points, descriptors);
 
                 features.keypoints.reserve(features.keypoints.size() + points.size());
                 for (std::vector<KeyPoint>::iterator kp = points.begin(); kp != points.end(); ++kp)
index 560d7b9..4875bef 100644 (file)
@@ -671,7 +671,7 @@ Mat ToFileMotionWriter::estimate(const Mat &frame0, const Mat &frame1, bool *ok)
 KeypointBasedMotionEstimator::KeypointBasedMotionEstimator(Ptr<MotionEstimatorBase> estimator)
     : ImageMotionEstimatorBase(estimator->motionModel()), motionEstimator_(estimator)
 {
-    setDetector(makePtr<GoodFeaturesToTrackDetector>());
+    setDetector(GFTTDetector::create());
     setOpticalFlowEstimator(makePtr<SparsePyrLkOptFlowEstimator>());
     setOutlierRejector(makePtr<NullOutlierRejector>());
 }