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.
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,
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>());
};
/*!
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,
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
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 );
};
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);
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 );
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,
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);
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);
}
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);
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);
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);
}
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);
#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)
, 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);
}
}
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> ¢ers) const;
Params params;
- AlgorithmInfo* info() const;
};
/*
fs << "maxConvexity" << maxConvexity;
}
-SimpleBlobDetector::SimpleBlobDetector(const SimpleBlobDetector::Params ¶meters) :
+SimpleBlobDetectorImpl::SimpleBlobDetectorImpl(const SimpleBlobDetector::Params ¶meters) :
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> ¢ers) const
+void SimpleBlobDetectorImpl::findBlobs(InputArray _image, InputArray _binaryImage, std::vector<Center> ¢ers) const
{
Mat image = _image.getMat(), binaryImage = _binaryImage.getMat();
(void)image;
#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();
keypoints.push_back(kpt);
}
}
+
+Ptr<SimpleBlobDetector> SimpleBlobDetector::create(const SimpleBlobDetector::Params& params)
+{
+ return makePtr<SimpleBlobDetectorImpl>(params);
+}
+
+}
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>
namespace cv
{
-
class BRISK_Impl : public BRISK
{
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,
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;
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;
}
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;
// 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
{
// 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)
}
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
{
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_;
}
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 )
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:
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);
}
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);
}
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);
+}
+
}
--- /dev/null
+/*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;
+}
+
+}
+++ /dev/null
-/*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
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);
+ }
}
, 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)
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);
* @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);
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);
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);
// 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:
// 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]);
}
}
* @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();
}
/* ************************************************************************* */
-class MultiscaleDerivativesAKAZEInvoker : public cv::ParallelLoopBody
+class MultiscaleDerivativesAKAZEInvoker : public ParallelLoopBody
{
public:
explicit MultiscaleDerivativesAKAZEInvoker(std::vector<TEvolution>& ev, const AKAZEOptions& opt)
{
}
- void operator()(const cv::Range& range) const
+ void operator()(const Range& range) const
{
std::vector<TEvolution>& evolution = *evolution_;
*/
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_));
}
* @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;
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) {
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
* @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;
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);
/* ************************************************************************* */
-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)
}
}
- 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)
}
}
- 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)
}
}
- 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)
}
}
- 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)
}
}
- 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)
}
}
- 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)
}
}
- 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)
}
}
- 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_;
};
/**
* @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++)
{
// 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);
}
}
{
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;
}
* @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
* 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;
* 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;
* @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;
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);
* @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);
* @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;
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);
* @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;
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;
* @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;
}
}
-}
/* ************************************************************************* */
// Includes
-#include "../precomp.hpp"
#include "AKAZEConfig.h"
#include "TEvolution.h"
+namespace cv
+{
+
/* ************************************************************************* */
// AKAZE Class Declaration
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
void generateDescriptorSubsample(cv::Mat& sampleList, cv::Mat& comparisons,
int nbits, int pattern_size, int nchannels);
+}
+
#endif
* @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;
/* ************************************************************************* */
/**
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;
}
// 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;
* @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;
* @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);
}
* @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();
}
/* ************************************************************************* */
-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++)
*/
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_;
};
* @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;
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;
* @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;
}
/* ************************************************************************* */
-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)
{
}
- 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++)
}
}
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_;
};
* @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++)
{
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_));
}
/* ************************************************************************* */
* @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;
* 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;
* 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;
* 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;
* 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;
desc[i] /= len;
}
}
+
+}
/* ************************************************************************* */
// KAZE Class Declaration
-class KAZEFeatures {
-
+class KAZEFeatures
+{
private:
/// Parameters of the Nonlinear diffusion class
#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;
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
int sigma_size; ///< Integer esigma. For computing the feature detector responses
};
+}
+
#endif
* @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;
+}
+
}
#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
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;
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;
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;
}
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++ )
{
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++;
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 )
{
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));
}
}
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;
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();
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);
* @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);
}
}
-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);
-}
-
-
}
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();
}
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();
}
protected:
virtual void run(int)
{
- cv::initModule_features2d();
CV_Assert(detector);
string imgFilename = string(ts->get_data_path()) + FEATURES2D_DIR + "/" + IMAGE_FILENAME;
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();
}
#include "test_precomp.hpp"
#include "opencv2/imgproc/imgproc_c.h"
+#if 0
+
#include <vector>
#include <string>
using namespace std;
}
TEST(Features2d_MSER, DISABLED_regression) { CV_MserTest test; test.safe_run(); }
+
+#endif
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());
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());
}
}
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)
}
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();
// << " 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)
KeypointBasedMotionEstimator::KeypointBasedMotionEstimator(Ptr<MotionEstimatorBase> estimator)
: ImageMotionEstimatorBase(estimator->motionModel()), motionEstimator_(estimator)
{
- setDetector(makePtr<GoodFeaturesToTrackDetector>());
+ setDetector(GFTTDetector::create());
setOpticalFlowEstimator(makePtr<SparsePyrLkOptFlowEstimator>());
setOutlierRejector(makePtr<NullOutlierRejector>());
}