Skip to content

Tbmr features (purely topological adaptation on MSER) #2713

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Nov 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion modules/xfeatures2d/doc/xfeatures2d.bib
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,20 @@ @article{Mikolajczyk2004
publisher = {Springer}
}

@ARTICLE{Najman2014,
author={Y. {Xu} and P. {Monasse} and T. {Géraud} and L. {Najman}},
journal={IEEE Transactions on Image Processing},
title={Tree-Based Morse Regions: A Topological Approach to Local Feature Detection},
year={2014},
volume={23},
number={12},
pages={5612-5625},
abstract={This paper introduces a topological approach to local invariant feature detection motivated by Morse theory. We use the critical points of the graph of the intensity image, revealing directly the topology information as initial interest points. Critical points are selected from what we call a tree-based shape-space. In particular, they are selected from both the connected components of the upper level sets of the image (the Max-tree) and those of the lower level sets (the Min-tree). They correspond to specific nodes on those two trees: 1) to the leaves (extrema) and 2) to the nodes having bifurcation (saddle points). We then associate to each critical point the largest region that contains it and is topologically equivalent in its tree. We call such largest regions the tree-based Morse regions (TBMRs). The TBMR can be seen as a variant of maximally stable extremal region (MSER), which are contrasted regions. Contrarily to MSER, TBMR relies only on topological information and thus fully inherit the invariance properties of the space of shapes (e.g., invariance to affine contrast changes and covariance to continuous transformations). In particular, TBMR extracts the regions independently of the contrast, which makes it truly contrast invariant. Furthermore, it is quasi-parameter free. TBMR extraction is fast, having the same complexity as MSER. Experimentally, TBMR achieves a repeatability on par with state-of-the-art methods, but obtains a significantly higher number of features. Both the accuracy and robustness of TBMR are demonstrated by applications to image registration and 3D reconstruction.},
keywords={feature extraction;image reconstruction;image registration;trees (mathematics);tree-based Morse regions;topological approach;local invariant feature detection;Morse theory;intensity image;initial interest points;critical points;tree-based shape-space;upper level image sets;Max-tree;lower level sets;Min-tree;saddle points;bifurcation;maximally stable extremal region variant;MSER;topological information;TBMR extraction;3D reconstruction;image registration;Feature extraction;Detectors;Shape;Time complexity;Level set;Three-dimensional displays;Image registration;Min/Max tree;local features;affine region detectors;image registration;3D reconstruction;Min/Max tree;local features;affine region detectors;image registration;3D reconstruction},
doi={10.1109/TIP.2014.2364127},
ISSN={1941-0042},
month={Dec},}

@article{Simonyan14,
author = {Simonyan, K. and Vedaldi, A. and Zisserman, A.},
title = {Learning Local Feature Descriptors Using Convex Optimisation},
Expand Down Expand Up @@ -126,4 +140,4 @@ @incollection{LUCID
pages = {1--9}
year = {2012}
publisher = {NIPS}
}
}
36 changes: 35 additions & 1 deletion modules/xfeatures2d/include/opencv2/xfeatures2d.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ class CV_EXPORTS_W HarrisLaplaceFeatureDetector : public Feature2D
* The interface is equivalent to @ref Feature2D, adding operations for
* @ref Elliptic_KeyPoint "Elliptic_KeyPoints" instead of @ref KeyPoint "KeyPoints".
*/
class CV_EXPORTS AffineFeature2D : public Feature2D
class CV_EXPORTS_W AffineFeature2D : public Feature2D
{
public:
/**
Expand Down Expand Up @@ -945,6 +945,40 @@ class CV_EXPORTS AffineFeature2D : public Feature2D
bool useProvidedKeypoints=false ) = 0;
};

/**
@brief Class implementing the Tree Based Morse Regions (TBMR) as described in
@cite Najman2014 extended with scaled extraction ability.

@param min_area prune areas smaller than minArea
@param max_area_relative prune areas bigger than maxArea = max_area_relative *
input_image_size
@param scale_factor scale factor for scaled extraction.
@param n_scales number of applications of the scale factor (octaves).

@note This algorithm is based on Component Tree (Min/Max) as well as MSER but
uses a Morse-theory approach to extract features.

Features are ellipses (similar to MSER, however a MSER feature can never be a
TBMR feature and vice versa).

*/
class CV_EXPORTS_W TBMR : public AffineFeature2D
{
public:
CV_WRAP static Ptr<TBMR> create(int min_area = 60,
float max_area_relative = 0.01f,
float scale_factor = 1.25f,
int n_scales = -1);

CV_WRAP virtual void setMinArea(int minArea) = 0;
CV_WRAP virtual int getMinArea() const = 0;
CV_WRAP virtual void setMaxAreaRelative(float maxArea) = 0;
CV_WRAP virtual float getMaxAreaRelative() const = 0;
CV_WRAP virtual void setScaleFactor(float scale_factor) = 0;
CV_WRAP virtual float getScaleFactor() const = 0;
CV_WRAP virtual void setNScales(int n_scales) = 0;
CV_WRAP virtual int getNScales() const = 0;
};

/** @brief Estimates cornerness for prespecified KeyPoints using the FAST algorithm

Expand Down
66 changes: 1 addition & 65 deletions modules/xfeatures2d/src/msd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,78 +55,14 @@ University of Bologna, Open Perception
*/

#include "precomp.hpp"
#include "msd_pyramid.hpp"
#include <limits>

namespace cv
{
namespace xfeatures2d
{
/*!
MSD Image Pyramid.
*/
class MSDImagePyramid
{
// Multi-threaded construction of the scale-space pyramid
struct MSDImagePyramidBuilder : ParallelLoopBody
{

MSDImagePyramidBuilder(const cv::Mat& _im, std::vector<cv::Mat>* _m_imPyr, float _scaleFactor)
{
im = &_im;
m_imPyr = _m_imPyr;
scaleFactor = _scaleFactor;

}

void operator()(const Range& range) const CV_OVERRIDE
{
for (int lvl = range.start; lvl < range.end; lvl++)
{
float scale = 1 / std::pow(scaleFactor, (float) lvl);
(*m_imPyr)[lvl] = cv::Mat(cv::Size(cvRound(im->cols * scale), cvRound(im->rows * scale)), im->type());
cv::resize(*im, (*m_imPyr)[lvl], cv::Size((*m_imPyr)[lvl].cols, (*m_imPyr)[lvl].rows), 0.0, 0.0, cv::INTER_AREA);
}
}
const cv::Mat* im;
std::vector<cv::Mat>* m_imPyr;
float scaleFactor;
};

public:

MSDImagePyramid(const cv::Mat &im, const int nLevels, const float scaleFactor = 1.6f);
~MSDImagePyramid();

const std::vector<cv::Mat> getImPyr() const
{
return m_imPyr;
};

private:

std::vector<cv::Mat> m_imPyr;
int m_nLevels;
float m_scaleFactor;
};

MSDImagePyramid::MSDImagePyramid(const cv::Mat & im, const int nLevels, const float scaleFactor)
{
m_nLevels = nLevels;
m_scaleFactor = scaleFactor;
m_imPyr.clear();
m_imPyr.resize(nLevels);

m_imPyr[0] = im.clone();

if (m_nLevels > 1)
{
parallel_for_(Range(1, nLevels), MSDImagePyramidBuilder(im, &m_imPyr, scaleFactor));
}
}

MSDImagePyramid::~MSDImagePyramid()
{
}

/*!
MSD Implementation.
Expand Down
77 changes: 77 additions & 0 deletions modules/xfeatures2d/src/msd_pyramid.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.

#ifndef __OPENCV_XFEATURES2D_MSD_PYRAMID_HPP__
#define __OPENCV_XFEATURES2D_MSD_PYRAMID_HPP__

#include "precomp.hpp"

namespace cv
{
namespace xfeatures2d
{
/*!
MSD Image Pyramid.
*/
class MSDImagePyramid
{
// Multi-threaded construction of the scale-space pyramid
struct MSDImagePyramidBuilder : ParallelLoopBody
{

MSDImagePyramidBuilder(const cv::Mat& _im, std::vector<cv::Mat>* _m_imPyr, float _scaleFactor)
{
im = &_im;
m_imPyr = _m_imPyr;
scaleFactor = _scaleFactor;

}

void operator()(const Range& range) const CV_OVERRIDE
{
for (int lvl = range.start; lvl < range.end; lvl++)
{
float scale = 1 / std::pow(scaleFactor, (float) lvl);
(*m_imPyr)[lvl] = cv::Mat(cv::Size(cvRound(im->cols * scale), cvRound(im->rows * scale)), im->type());
cv::resize(*im, (*m_imPyr)[lvl], cv::Size((*m_imPyr)[lvl].cols, (*m_imPyr)[lvl].rows), 0.0, 0.0, cv::INTER_AREA);
}
}
const cv::Mat* im;
std::vector<cv::Mat>* m_imPyr;
float scaleFactor;
};

public:

MSDImagePyramid(const cv::Mat &im, const int nLevels, const float scaleFactor = 1.6f)
{
m_nLevels = nLevels;
m_scaleFactor = scaleFactor;
m_imPyr.clear();
m_imPyr.resize(nLevels);

m_imPyr[0] = im.clone();

if (m_nLevels > 1)
{
parallel_for_(Range(1, nLevels), MSDImagePyramidBuilder(im, &m_imPyr, scaleFactor));
}
}
~MSDImagePyramid() {};

const std::vector<cv::Mat> getImPyr() const
{
return m_imPyr;
};

private:

std::vector<cv::Mat> m_imPyr;
int m_nLevels;
float m_scaleFactor;
};
}
}

#endif
Loading