all the tests now pass except for MSER
authorVadim Pisarevsky <vadim.pisarevsky@gmail.com>
Thu, 16 Oct 2014 16:58:29 +0000 (20:58 +0400)
committerVadim Pisarevsky <vadim.pisarevsky@gmail.com>
Thu, 16 Oct 2014 16:58:29 +0000 (20:58 +0400)
13 files changed:
modules/core/include/opencv2/core.hpp
modules/core/src/algorithm.cpp
modules/features2d/include/opencv2/features2d.hpp
modules/features2d/perf/opencl/perf_fast.cpp
modules/features2d/perf/perf_fast.cpp
modules/features2d/src/brisk.cpp
modules/features2d/src/fast.cpp
modules/features2d/src/mser.cpp
modules/features2d/test/test_descriptors_regression.cpp
modules/features2d/test/test_keypoints.cpp
modules/features2d/test/test_matchers_algorithmic.cpp
modules/features2d/test/test_rotation_and_scale_invariance.cpp
modules/stitching/src/matchers.cpp

index a258e8c..2fba9fc 100644 (file)
@@ -874,6 +874,9 @@ public:
     virtual ~Algorithm();
     String name() const;
 
+    virtual void set(int, double);
+    virtual double get(int) const;
+
     template<typename _Tp> typename ParamType<_Tp>::member_type get(const String& name) const;
     template<typename _Tp> typename ParamType<_Tp>::member_type get(const char* name) const;
 
index 9f9493e..bd28bdc 100644 (file)
@@ -179,6 +179,9 @@ String Algorithm::name() const
     return info()->name();
 }
 
+void Algorithm::set(int, double) {}
+double Algorithm::get(int) const { return 0.; }
+
 void Algorithm::set(const String& parameter, int value)
 {
     info()->set(this, parameter.c_str(), ParamType<int>::type, &value);
index ddf5d66..243d755 100644 (file)
@@ -213,9 +213,10 @@ CV_EXPORTS void FAST( InputArray image, CV_OUT std::vector<KeyPoint>& keypoints,
 class CV_EXPORTS_W FastFeatureDetector : public Feature2D
 {
 public:
-    enum Type
+    enum
     {
-        TYPE_5_8 = 0, TYPE_7_12 = 1, TYPE_9_16 = 2
+        TYPE_5_8 = 0, TYPE_7_12 = 1, TYPE_9_16 = 2,
+        THRESHOLD = 10000, NONMAX_SUPPRESSION=10001, FAST_N=10002,
     };
 
     CV_WRAP static Ptr<FastFeatureDetector> create( int threshold=10,
index c4a8e07..be310ba 100644 (file)
@@ -32,11 +32,8 @@ OCL_PERF_TEST_P(FASTFixture, FastDetect, testing::Combine(
     mframe.copyTo(frame);
     declare.in(frame);
 
-    Ptr<FeatureDetector> fd = Algorithm::create<FeatureDetector>("Feature2D.FAST");
+    Ptr<FeatureDetector> fd = FastFeatureDetector::create(20, true, type);
     ASSERT_FALSE( fd.empty() );
-    fd->set("threshold", 20);
-    fd->set("nonmaxSuppression", true);
-    fd->set("type", type);
     vector<KeyPoint> points;
 
     OCL_TEST_CYCLE() fd->detect(frame, points);
index 25b82bd..f706364 100644 (file)
@@ -30,11 +30,8 @@ PERF_TEST_P(fast, detect, testing::Combine(
 
     declare.in(frame);
 
-    Ptr<FeatureDetector> fd = Algorithm::create<FeatureDetector>("Feature2D.FAST");
+    Ptr<FeatureDetector> fd = FastFeatureDetector::create(20, true, type);
     ASSERT_FALSE( fd.empty() );
-    fd->set("threshold", 20);
-    fd->set("nonmaxSuppression", true);
-    fd->set("type", type);
     vector<KeyPoint> points;
 
     TEST_CYCLE() fd->detect(frame, points);
index d123a3a..0a14148 100644 (file)
@@ -2099,7 +2099,7 @@ BriskLayer::BriskLayer(const BriskLayer& layer, int mode)
 void
 BriskLayer::getAgastPoints(int threshold, std::vector<KeyPoint>& keypoints)
 {
-  fast_9_16_ = FastFeatureDetector::create(threshold);
+  fast_9_16_->set(FastFeatureDetector::THRESHOLD, threshold);
   fast_9_16_->detect(img_, keypoints);
 
   // also write scores
index 8acdbb1..d829e46 100644 (file)
@@ -380,6 +380,30 @@ public:
         KeyPointsFilter::runByPixelsMask( keypoints, mask );
     }
 
+    void set(int prop, double value)
+    {
+        if(prop == THRESHOLD)
+            threshold = cvRound(value);
+        else if(prop == NONMAX_SUPPRESSION)
+            nonmaxSuppression = value != 0;
+        else if(prop == FAST_N)
+            type = cvRound(value);
+        else
+            CV_Error(Error::StsBadArg, "");
+    }
+
+    double get(int prop) const
+    {
+        if(prop == THRESHOLD)
+            return threshold;
+        if(prop == NONMAX_SUPPRESSION)
+            return nonmaxSuppression;
+        if(prop == FAST_N)
+            return type;
+        CV_Error(Error::StsBadArg, "");
+        return 0;
+    }
+
     int threshold;
     bool nonmaxSuppression;
     int type;
index c9db567..49d173b 100644 (file)
@@ -800,9 +800,12 @@ extractMSER_8uC3( const Mat& src, Mat& labels,
     double emean = 0;
     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;
index baffeeb..c0956fd 100644 (file)
@@ -106,8 +106,6 @@ public:
 
     ~CV_DescriptorExtractorTest()
     {
-        if(!detector.empty())
-            detector.release();
     }
 protected:
     virtual void createDescriptorExtractor() {}
@@ -333,7 +331,7 @@ TEST( Features2d_DescriptorExtractor_KAZE, regression )
 {
     CV_DescriptorExtractorTest< L2<float> > test( "descriptor-kaze",  0.03f,
                                                  KAZE::create(),
-                                                 L2<float>() );
+                                                 L2<float>(), KAZE::create() );
     test.safe_run();
 }
 
index 561c3cc..c494f98 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "test_precomp.hpp"
 #include "opencv2/highgui.hpp"
+#include "opencv2/core/core_c.h"
 
 using namespace std;
 using namespace cv;
@@ -48,6 +49,683 @@ using namespace cv;
 const string FEATURES2D_DIR = "features2d";
 const string IMAGE_FILENAME = "tsukuba.png";
 
+const int TABLE_SIZE = 400;
+
+static const float chitab3[]=
+{
+    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;
+
+struct TempMSCR
+{
+    MSCRNode* head;
+    MSCRNode* tail;
+    double m; // the margin used to prune area later
+    int size;
+};
+
+struct MSCRNode
+{
+    MSCRNode* shortcut;
+    // to make the finding of root less painful
+    MSCRNode* prev;
+    MSCRNode* next;
+    // a point double-linked list
+    TempMSCR* tmsr;
+    // the temporary msr (set to NULL at every re-initialise)
+    TempMSCR* gmsr;
+    // the global msr (once set, never to NULL)
+    int index;
+    // the index of the node, at this point, it should be x at the first 16-bits, and y at the last 16-bits.
+    int rank;
+    int reinit;
+    int size, sizei;
+    double dt, di;
+    double s;
+};
+
+struct MSCREdge
+{
+    double chi;
+    MSCRNode* left;
+    MSCRNode* right;
+};
+
+static double ChiSquaredDistance( uchar* x, 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);
+}
+
+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 )
+{
+    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++ )
+    {
+        for ( int j = 0; j < src->cols; j++ )
+        {
+            *dyptr = ChiSquaredDistance( srcptr, lastptr );
+            dyptr++;
+            srcptr += 3;
+            lastptr += 3;
+        }
+        srcptr += srccpt;
+        lastptr += srccpt;
+    }
+    // get dx and dy and blur it
+    if ( edgeBlurSize >= 1 )
+    {
+        Mat _dx(dx->rows, dx->cols, dx->type, dx->data.ptr, dx->step);
+        Mat _dy(dy->rows, dy->cols, dy->type, dy->data.ptr, dy->step);
+        GaussianBlur( _dx, _dx, Size(edgeBlurSize, edgeBlurSize), 0 );
+        GaussianBlur( _dy, _dy, Size(edgeBlurSize, edgeBlurSize), 0 );
+    }
+    dxptr = dx->data.db;
+    dyptr = dy->data.db;
+    // assian dx, dy to proper edge list and initialize mscr node
+    // the nasty code here intended to avoid extra loops
+    if ( mask )
+    {
+        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++ )
+        {
+            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++;
+        }
+        initMSCRNode( nodeptr );
+        nodeptr->index = ((src->rows-1)<<16)|(src->cols-1);
+        *total += edge->chi = *dyptr;
+        edge->left = nodeptr-src->cols;
+        edge->right = nodeptr;
+    }
+    return Ne;
+}
+
+class LessThanEdge
+{
+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;
+}
+
+struct MSERParams
+{
+    MSERParams( int _delta=5, int _min_area=60, int _max_area=14400,
+                      double _max_variation=0.25, double _min_diversity=.2,
+                      int _max_evolution=200, double _area_threshold=1.01,
+                      double _min_margin=0.003, int _edge_blur_size=5 )
+    {
+        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;
+    }
+
+    int delta;
+    int minArea;
+    int maxArea;
+    double maxVariation;
+    double minDiversity;
+    int maxEvolution;
+    double areaThreshold;
+    double minMargin;
+    int edgeBlurSize;
+};
+
+// 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,
+                 vector<vector<Point> >& msers,
+                 MSERParams params )
+{
+    msers.clear();
+    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]) );
+    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 );
+    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++ )
+    {
+        double k = (double)i/(double)params.maxEvolution*(TABLE_SIZE-1);
+        int ti = cvFloor(k);
+        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 )
+        {
+            MSCRNode* lr = findMSCR( edgeptr->left );
+            MSCRNode* rr = findMSCR( edgeptr->right );
+            // get the region root (who is responsible)
+            if ( lr != rr )
+            {
+                // 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 ) {
+                    // at the same rank, we will compare the size
+                    if ( lr->size > rr->size )
+                    {
+                        MSCRNode* tmp;
+                        CV_SWAP( lr, rr, tmp );
+                    }
+                    lr->rank++;
+                }
+                rr->shortcut = lr;
+                lr->size += rr->size;
+                // join rr to the end of list lr (lr is a endless double-linked list)
+                lr->prev->next = rr;
+                lr->prev = rr->prev;
+                rr->prev->next = lr;
+                rr->prev = lr;
+                // area threshold force to reinitialize
+                if ( lr->size > (lr->size-rr->size)*params.areaThreshold )
+                {
+                    lr->sizei = lr->size;
+                    lr->reinit = i;
+                    if ( lr->tmsr != NULL )
+                    {
+                        lr->tmsr->m = lr->dt-lr->di;
+                        lr->tmsr = NULL;
+                    }
+                    lr->di = edgeptr->chi;
+                    lr->s = 1e10;
+                }
+                lr->dt = edgeptr->chi;
+                if ( i > lr->reinit )
+                {
+                    double s = (double)(lr->size-lr->sizei)/(lr->dt-lr->di);
+                    if ( s < lr->s )
+                    {
+                        // skip the first one and check stablity
+                        if ( i > lr->reinit+1 && MSCRStableCheck( lr, params ) )
+                        {
+                            if ( lr->tmsr == NULL )
+                            {
+                                lr->gmsr = lr->tmsr = mscrptr;
+                                mscrptr++;
+                            }
+                            lr->tmsr->size = lr->size;
+                            lr->tmsr->head = lr;
+                            lr->tmsr->tail = lr->prev;
+                            lr->tmsr->m = 0;
+                        }
+                        lr->s = s;
+                    }
+                }
+            }
+            edgeptr++;
+        }
+        if ( edgeptr >= edge_ub )
+            break;
+    }
+    for ( TempMSCR* ptr = mscr; ptr < mscrptr; ptr++ )
+        // to prune area with margin less than minMargin
+        if ( ptr->m > params.minMargin )
+        {
+            vector<Point> mser;
+            MSCRNode* lpt = ptr->head;
+            for ( int i = 0; i < ptr->size; i++ )
+            {
+                Point pt;
+                pt.x = (lpt->index)&0xffff;
+                pt.y = (lpt->index)>>16;
+                lpt = lpt->next;
+                mser.push_back(pt);
+            }
+            msers.push_back(mser);
+        }
+    cvReleaseMat( &dx );
+    cvReleaseMat( &dy );
+    cvFree( &mscr );
+    cvFree( &edge );
+    cvFree( &map );
+}
+
 /****************************************************************************************\
 *                                     Test for KeyPoint                                  *
 \****************************************************************************************/
@@ -74,6 +752,11 @@ protected:
         }
 
         vector<KeyPoint> keypoints;
+        vector<vector<Point> > msers;
+        CvMat src = image;
+
+        extractMSER_8UC3( &src, 0, msers, MSERParams());
+
         detector->detect(image, keypoints);
 
         if(keypoints.empty())
index 147ae55..ec71e5a 100644 (file)
@@ -533,13 +533,13 @@ void CV_DescriptorMatcherTest::run( int )
 TEST( Features2d_DescriptorMatcher_BruteForce, regression )
 {
     CV_DescriptorMatcherTest test( "descriptor-matcher-brute-force",
-                                  DescriptorMatcher::create("BFMatcher"), 0.01f );
+                                  DescriptorMatcher::create("BruteForce"), 0.01f );
     test.safe_run();
 }
 
 TEST( Features2d_DescriptorMatcher_FlannBased, regression )
 {
     CV_DescriptorMatcherTest test( "descriptor-matcher-flann-based",
-                                  DescriptorMatcher::create("FlannBasedMatcher"), 0.04f );
+                                  DescriptorMatcher::create("FlannBased"), 0.04f );
     test.safe_run();
 }
index 90fc2f8..f03fa14 100644 (file)
@@ -595,7 +595,7 @@ protected:
 
 TEST(Features2d_RotationInvariance_Detector_BRISK, regression)
 {
-    DetectorRotationInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.BRISK"),
+    DetectorRotationInvarianceTest test(BRISK::create(),
                                         0.32f,
                                         0.76f);
     test.safe_run();
@@ -603,7 +603,7 @@ TEST(Features2d_RotationInvariance_Detector_BRISK, regression)
 
 TEST(Features2d_RotationInvariance_Detector_ORB, regression)
 {
-    DetectorRotationInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.ORB"),
+    DetectorRotationInvarianceTest test(ORB::create(),
                                         0.47f,
                                         0.76f);
     test.safe_run();
index 9279df7..ad3f632 100644 (file)
@@ -321,7 +321,7 @@ SurfFeaturesFinder::SurfFeaturesFinder(double hess_thresh, int num_octaves, int
 {
     if (num_octaves_descr == num_octaves && num_layers_descr == num_layers)
     {
-        surf = Algorithm::create<Feature2D>("Feature2D.SURF");
+        surf = xfeatures2d::SURF::create();
         if( !surf )
             CV_Error( Error::StsNotImplemented, "OpenCV was built without SURF support" );
         surf->set("hessianThreshold", hess_thresh);
@@ -330,8 +330,8 @@ SurfFeaturesFinder::SurfFeaturesFinder(double hess_thresh, int num_octaves, int
     }
     else
     {
-        detector_ = Algorithm::create<FeatureDetector>("Feature2D.SURF");
-        extractor_ = Algorithm::create<DescriptorExtractor>("Feature2D.SURF");
+        detector_ = xfeatures2d::SURF::create();
+        extractor_ = xfeatures2d::SURF::create();
 
         if( !detector_ || !extractor_ )
             CV_Error( Error::StsNotImplemented, "OpenCV was built without SURF support" );