mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 23:33:05 +04:00
Merge upstream branch
This commit is contained in:
@@ -1,2 +1,6 @@
|
||||
set(the_description "2D Features Framework")
|
||||
ocv_define_module(features2d opencv_imgproc opencv_flann OPTIONAL opencv_highgui)
|
||||
set(debug_modules "")
|
||||
if(DEBUG_opencv_features2d)
|
||||
list(APPEND debug_modules opencv_highgui)
|
||||
endif()
|
||||
ocv_define_module(features2d opencv_imgproc ${debug_modules} OPTIONAL opencv_flann WRAP java python js)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,121 +0,0 @@
|
||||
Common Interfaces of Descriptor Extractors
|
||||
==========================================
|
||||
|
||||
.. highlight:: cpp
|
||||
|
||||
Extractors of keypoint descriptors in OpenCV have wrappers with a common interface that enables you to easily switch
|
||||
between different algorithms solving the same problem. This section is devoted to computing descriptors
|
||||
represented as vectors in a multidimensional space. All objects that implement the ``vector``
|
||||
descriptor extractors inherit the
|
||||
:ocv:class:`DescriptorExtractor` interface.
|
||||
|
||||
.. note::
|
||||
|
||||
* An example explaining keypoint extraction can be found at opencv_source_code/samples/cpp/descriptor_extractor_matcher.cpp
|
||||
* An example on descriptor evaluation can be found at opencv_source_code/samples/cpp/detector_descriptor_evaluation.cpp
|
||||
|
||||
DescriptorExtractor
|
||||
-------------------
|
||||
.. ocv:class:: DescriptorExtractor : public Algorithm
|
||||
|
||||
Abstract base class for computing descriptors for image keypoints. ::
|
||||
|
||||
class CV_EXPORTS DescriptorExtractor
|
||||
{
|
||||
public:
|
||||
virtual ~DescriptorExtractor();
|
||||
|
||||
void compute( InputArray image, vector<KeyPoint>& keypoints,
|
||||
OutputArray descriptors ) const;
|
||||
void compute( InputArrayOfArrays images, vector<vector<KeyPoint> >& keypoints,
|
||||
OutputArrayOfArrays descriptors ) const;
|
||||
|
||||
virtual void read( const FileNode& );
|
||||
virtual void write( FileStorage& ) const;
|
||||
|
||||
virtual int descriptorSize() const = 0;
|
||||
virtual int descriptorType() const = 0;
|
||||
virtual int defaultNorm() const = 0;
|
||||
|
||||
static Ptr<DescriptorExtractor> create( const String& descriptorExtractorType );
|
||||
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
In this interface, a keypoint descriptor can be represented as a
|
||||
dense, fixed-dimension vector of a basic type. Most descriptors
|
||||
follow this pattern as it simplifies computing
|
||||
distances between descriptors. Therefore, a collection of
|
||||
descriptors is represented as
|
||||
:ocv:class:`Mat` , where each row is a keypoint descriptor.
|
||||
|
||||
|
||||
|
||||
DescriptorExtractor::compute
|
||||
--------------------------------
|
||||
Computes the descriptors for a set of keypoints detected in an image (first variant) or image set (second variant).
|
||||
|
||||
.. ocv:function:: void DescriptorExtractor::compute( InputArray image, vector<KeyPoint>& keypoints, OutputArray descriptors ) const
|
||||
|
||||
.. ocv:function:: void DescriptorExtractor::compute( InputArrayOfArrays images, vector<vector<KeyPoint> >& keypoints, OutputArrayOfArrays descriptors ) const
|
||||
|
||||
.. ocv:pyfunction:: cv2.DescriptorExtractor_create.compute(image, keypoints[, descriptors]) -> keypoints, descriptors
|
||||
|
||||
:param image: Image.
|
||||
|
||||
:param images: Image set.
|
||||
|
||||
:param keypoints: Input collection of keypoints. Keypoints for which a descriptor cannot be computed are removed. Sometimes new keypoints can be added, for example: ``SIFT`` duplicates keypoint with several dominant orientations (for each orientation).
|
||||
|
||||
:param descriptors: Computed descriptors. In the second variant of the method ``descriptors[i]`` are descriptors computed for a ``keypoints[i]``. Row ``j`` is the ``keypoints`` (or ``keypoints[i]``) is the descriptor for keypoint ``j``-th keypoint.
|
||||
|
||||
|
||||
DescriptorExtractor::create
|
||||
-------------------------------
|
||||
Creates a descriptor extractor by name.
|
||||
|
||||
.. ocv:function:: Ptr<DescriptorExtractor> DescriptorExtractor::create( const String& descriptorExtractorType )
|
||||
|
||||
.. ocv:pyfunction:: cv2.DescriptorExtractor_create(descriptorExtractorType) -> retval
|
||||
|
||||
:param descriptorExtractorType: Descriptor extractor type.
|
||||
|
||||
The current implementation supports the following types of a descriptor extractor:
|
||||
|
||||
* ``"SIFT"`` -- :ocv:class:`SIFT`
|
||||
* ``"SURF"`` -- :ocv:class:`SURF`
|
||||
* ``"BRIEF"`` -- :ocv:class:`BriefDescriptorExtractor`
|
||||
* ``"BRISK"`` -- :ocv:class:`BRISK`
|
||||
* ``"ORB"`` -- :ocv:class:`ORB`
|
||||
* ``"FREAK"`` -- :ocv:class:`FREAK`
|
||||
|
||||
A combined format is also supported: descriptor extractor adapter name ( ``"Opponent"`` --
|
||||
:ocv:class:`OpponentColorDescriptorExtractor` ) + descriptor extractor name (see above),
|
||||
for example: ``"OpponentSIFT"`` .
|
||||
|
||||
|
||||
OpponentColorDescriptorExtractor
|
||||
--------------------------------
|
||||
.. ocv:class:: OpponentColorDescriptorExtractor : public DescriptorExtractor
|
||||
|
||||
Class adapting a descriptor extractor to compute descriptors in the Opponent Color Space
|
||||
(refer to Van de Sande et al., CGIV 2008 *Color Descriptors for Object Category Recognition*).
|
||||
Input RGB image is transformed in the Opponent Color Space. Then, an unadapted descriptor extractor
|
||||
(set in the constructor) computes descriptors on each of three channels and concatenates
|
||||
them into a single color descriptor. ::
|
||||
|
||||
class OpponentColorDescriptorExtractor : public DescriptorExtractor
|
||||
{
|
||||
public:
|
||||
OpponentColorDescriptorExtractor( const Ptr<DescriptorExtractor>& dextractor );
|
||||
|
||||
virtual void read( const FileNode& );
|
||||
virtual void write( FileStorage& ) const;
|
||||
virtual int descriptorSize() const;
|
||||
virtual int descriptorType() const;
|
||||
virtual int defaultNorm() const;
|
||||
protected:
|
||||
...
|
||||
};
|
||||
@@ -1,279 +0,0 @@
|
||||
Common Interfaces of Descriptor Matchers
|
||||
========================================
|
||||
|
||||
.. highlight:: cpp
|
||||
|
||||
Matchers of keypoint descriptors in OpenCV have wrappers with a common interface that enables you to easily switch
|
||||
between different algorithms solving the same problem. This section is devoted to matching descriptors
|
||||
that are represented as vectors in a multidimensional space. All objects that implement ``vector``
|
||||
descriptor matchers inherit the
|
||||
:ocv:class:`DescriptorMatcher` interface.
|
||||
|
||||
.. note::
|
||||
|
||||
* An example explaining keypoint matching can be found at opencv_source_code/samples/cpp/descriptor_extractor_matcher.cpp
|
||||
* An example on descriptor matching evaluation can be found at opencv_source_code/samples/cpp/detector_descriptor_matcher_evaluation.cpp
|
||||
* An example on one to many image matching can be found at opencv_source_code/samples/cpp/matching_to_many_images.cpp
|
||||
|
||||
DescriptorMatcher
|
||||
-----------------
|
||||
.. ocv:class:: DescriptorMatcher : public Algorithm
|
||||
|
||||
Abstract base class for matching keypoint descriptors. It has two groups
|
||||
of match methods: for matching descriptors of an image with another image or
|
||||
with an image set. ::
|
||||
|
||||
class DescriptorMatcher
|
||||
{
|
||||
public:
|
||||
virtual ~DescriptorMatcher();
|
||||
|
||||
virtual void add( InputArrayOfArrays descriptors );
|
||||
|
||||
const vector<Mat>& getTrainDescriptors() const;
|
||||
virtual void clear();
|
||||
bool empty() const;
|
||||
virtual bool isMaskSupported() const = 0;
|
||||
|
||||
virtual void train();
|
||||
|
||||
/*
|
||||
* Group of methods to match descriptors from an image pair.
|
||||
*/
|
||||
void match( InputArray queryDescriptors, InputArray trainDescriptors,
|
||||
vector<DMatch>& matches, InputArray mask=noArray() ) const;
|
||||
void knnMatch( InputArray queryDescriptors, InputArray trainDescriptors,
|
||||
vector<vector<DMatch> >& matches, int k,
|
||||
InputArray mask=noArray(), bool compactResult=false ) const;
|
||||
void radiusMatch( InputArray queryDescriptors, InputArray trainDescriptors,
|
||||
vector<vector<DMatch> >& matches, float maxDistance,
|
||||
InputArray mask=noArray(), bool compactResult=false ) const;
|
||||
/*
|
||||
* Group of methods to match descriptors from one image to an image set.
|
||||
*/
|
||||
void match( InputArray queryDescriptors, vector<DMatch>& matches,
|
||||
InputArrayOfArrays masks=noArray() );
|
||||
void knnMatch( InputArray queryDescriptors, vector<vector<DMatch> >& matches,
|
||||
int k, InputArrayOfArrays masks=noArray(),
|
||||
bool compactResult=false );
|
||||
void radiusMatch( InputArray queryDescriptors, vector<vector<DMatch> >& matches,
|
||||
float maxDistance, InputArrayOfArrays masks=noArray(),
|
||||
bool compactResult=false );
|
||||
|
||||
virtual void read( const FileNode& );
|
||||
virtual void write( FileStorage& ) const;
|
||||
|
||||
virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const = 0;
|
||||
|
||||
static Ptr<DescriptorMatcher> create( const String& descriptorMatcherType );
|
||||
|
||||
protected:
|
||||
vector<Mat> trainDescCollection;
|
||||
vector<UMat> utrainDescCollection;
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
DescriptorMatcher::add
|
||||
--------------------------
|
||||
Adds descriptors to train a CPU(``trainDescCollectionis``) or GPU(``utrainDescCollectionis``) descriptor collection. If the collection is not empty, the new descriptors are added to existing train descriptors.
|
||||
|
||||
.. ocv:function:: void DescriptorMatcher::add( InputArrayOfArrays descriptors )
|
||||
|
||||
:param descriptors: Descriptors to add. Each ``descriptors[i]`` is a set of descriptors from the same train image.
|
||||
|
||||
|
||||
DescriptorMatcher::getTrainDescriptors
|
||||
------------------------------------------
|
||||
Returns a constant link to the train descriptor collection ``trainDescCollection`` .
|
||||
|
||||
.. ocv:function:: const vector<Mat>& DescriptorMatcher::getTrainDescriptors() const
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DescriptorMatcher::clear
|
||||
----------------------------
|
||||
Clears the train descriptor collections.
|
||||
|
||||
.. ocv:function:: void DescriptorMatcher::clear()
|
||||
|
||||
|
||||
|
||||
DescriptorMatcher::empty
|
||||
----------------------------
|
||||
Returns true if there are no train descriptors in the both collections.
|
||||
|
||||
.. ocv:function:: bool DescriptorMatcher::empty() const
|
||||
|
||||
|
||||
|
||||
DescriptorMatcher::isMaskSupported
|
||||
--------------------------------------
|
||||
Returns true if the descriptor matcher supports masking permissible matches.
|
||||
|
||||
.. ocv:function:: bool DescriptorMatcher::isMaskSupported()
|
||||
|
||||
|
||||
|
||||
DescriptorMatcher::train
|
||||
----------------------------
|
||||
Trains a descriptor matcher
|
||||
|
||||
.. ocv:function:: void DescriptorMatcher::train()
|
||||
|
||||
Trains a descriptor matcher (for example, the flann index). In all methods to match, the method ``train()`` is run every time before matching. Some descriptor matchers (for example, ``BruteForceMatcher``) have an empty implementation of this method. Other matchers really train their inner structures (for example, ``FlannBasedMatcher`` trains ``flann::Index`` ).
|
||||
|
||||
|
||||
|
||||
DescriptorMatcher::match
|
||||
----------------------------
|
||||
Finds the best match for each descriptor from a query set.
|
||||
|
||||
.. ocv:function:: void DescriptorMatcher::match( InputArray queryDescriptors, InputArray trainDescriptors, vector<DMatch>& matches, InputArray mask=noArray() ) const
|
||||
|
||||
.. ocv:function:: void DescriptorMatcher::match(InputArray queryDescriptors, vector<DMatch>& matches, InputArrayOfArrays masks=noArray() )
|
||||
|
||||
:param queryDescriptors: Query set of descriptors.
|
||||
|
||||
:param trainDescriptors: Train set of descriptors. This set is not added to the train descriptors collection stored in the class object.
|
||||
|
||||
:param matches: Matches. If a query descriptor is masked out in ``mask`` , no match is added for this descriptor. So, ``matches`` size may be smaller than the query descriptors count.
|
||||
|
||||
:param mask: Mask specifying permissible matches between an input query and train matrices of descriptors.
|
||||
|
||||
:param masks: Set of masks. Each ``masks[i]`` specifies permissible matches between the input query descriptors and stored train descriptors from the i-th image ``trainDescCollection[i]``.
|
||||
|
||||
In the first variant of this method, the train descriptors are passed as an input argument. In the second variant of the method, train descriptors collection that was set by ``DescriptorMatcher::add`` is used. Optional mask (or masks) can be passed to specify which query and training descriptors can be matched. Namely, ``queryDescriptors[i]`` can be matched with ``trainDescriptors[j]`` only if ``mask.at<uchar>(i,j)`` is non-zero.
|
||||
|
||||
|
||||
|
||||
DescriptorMatcher::knnMatch
|
||||
-------------------------------
|
||||
Finds the k best matches for each descriptor from a query set.
|
||||
|
||||
.. ocv:function:: void DescriptorMatcher::knnMatch(InputArray queryDescriptors, InputArray trainDescriptors, vector<vector<DMatch> >& matches, int k, InputArray mask=noArray(), bool compactResult=false ) const
|
||||
|
||||
.. ocv:function:: void DescriptorMatcher::knnMatch( InputArray queryDescriptors, vector<vector<DMatch> >& matches, int k, InputArrayOfArrays masks=noArray(), bool compactResult=false )
|
||||
|
||||
:param queryDescriptors: Query set of descriptors.
|
||||
|
||||
:param trainDescriptors: Train set of descriptors. This set is not added to the train descriptors collection stored in the class object.
|
||||
|
||||
:param mask: Mask specifying permissible matches between an input query and train matrices of descriptors.
|
||||
|
||||
:param masks: Set of masks. Each ``masks[i]`` specifies permissible matches between the input query descriptors and stored train descriptors from the i-th image ``trainDescCollection[i]``.
|
||||
|
||||
:param matches: Matches. Each ``matches[i]`` is k or less matches for the same query descriptor.
|
||||
|
||||
:param k: Count of best matches found per each query descriptor or less if a query descriptor has less than k possible matches in total.
|
||||
|
||||
:param compactResult: Parameter used when the mask (or masks) is not empty. If ``compactResult`` is false, the ``matches`` vector has the same size as ``queryDescriptors`` rows. If ``compactResult`` is true, the ``matches`` vector does not contain matches for fully masked-out query descriptors.
|
||||
|
||||
These extended variants of :ocv:func:`DescriptorMatcher::match` methods find several best matches for each query descriptor. The matches are returned in the distance increasing order. See :ocv:func:`DescriptorMatcher::match` for the details about query and train descriptors.
|
||||
|
||||
|
||||
|
||||
DescriptorMatcher::radiusMatch
|
||||
----------------------------------
|
||||
For each query descriptor, finds the training descriptors not farther than the specified distance.
|
||||
|
||||
.. ocv:function:: void DescriptorMatcher::radiusMatch( InputArray queryDescriptors, InputArray trainDescriptors, vector<vector<DMatch> >& matches, float maxDistance, InputArray mask=noArray(), bool compactResult=false ) const
|
||||
|
||||
.. ocv:function:: void DescriptorMatcher::radiusMatch( InputArray queryDescriptors, vector<vector<DMatch> >& matches, float maxDistance, InputArrayOfArrays masks=noArray(), bool compactResult=false )
|
||||
|
||||
:param queryDescriptors: Query set of descriptors.
|
||||
|
||||
:param trainDescriptors: Train set of descriptors. This set is not added to the train descriptors collection stored in the class object.
|
||||
|
||||
:param mask: Mask specifying permissible matches between an input query and train matrices of descriptors.
|
||||
|
||||
:param masks: Set of masks. Each ``masks[i]`` specifies permissible matches between the input query descriptors and stored train descriptors from the i-th image ``trainDescCollection[i]``.
|
||||
|
||||
:param matches: Found matches.
|
||||
|
||||
:param compactResult: Parameter used when the mask (or masks) is not empty. If ``compactResult`` is false, the ``matches`` vector has the same size as ``queryDescriptors`` rows. If ``compactResult`` is true, the ``matches`` vector does not contain matches for fully masked-out query descriptors.
|
||||
|
||||
:param maxDistance: Threshold for the distance between matched descriptors. Distance means here metric distance (e.g. Hamming distance), not the distance between coordinates (which is measured in Pixels)!
|
||||
|
||||
For each query descriptor, the methods find such training descriptors that the distance between the query descriptor and the training descriptor is equal or smaller than ``maxDistance``. Found matches are returned in the distance increasing order.
|
||||
|
||||
|
||||
|
||||
DescriptorMatcher::clone
|
||||
----------------------------
|
||||
Clones the matcher.
|
||||
|
||||
.. ocv:function:: Ptr<DescriptorMatcher> DescriptorMatcher::clone( bool emptyTrainData=false )
|
||||
|
||||
:param emptyTrainData: If ``emptyTrainData`` is false, the method creates a deep copy of the object, that is, copies both parameters and train data. If ``emptyTrainData`` is true, the method creates an object copy with the current parameters but with empty train data.
|
||||
|
||||
|
||||
|
||||
DescriptorMatcher::create
|
||||
-----------------------------
|
||||
Creates a descriptor matcher of a given type with the default parameters (using default constructor).
|
||||
|
||||
.. ocv:function:: Ptr<DescriptorMatcher> DescriptorMatcher::create( const String& descriptorMatcherType )
|
||||
|
||||
:param descriptorMatcherType: Descriptor matcher type. Now the following matcher types are supported:
|
||||
|
||||
*
|
||||
``BruteForce`` (it uses ``L2`` )
|
||||
*
|
||||
``BruteForce-L1``
|
||||
*
|
||||
``BruteForce-Hamming``
|
||||
*
|
||||
``BruteForce-Hamming(2)``
|
||||
*
|
||||
``FlannBased``
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BFMatcher
|
||||
-----------------
|
||||
.. ocv:class:: BFMatcher : public DescriptorMatcher
|
||||
|
||||
Brute-force descriptor matcher. For each descriptor in the first set, this matcher finds the closest descriptor in the second set by trying each one. This descriptor matcher supports masking permissible matches of descriptor sets.
|
||||
|
||||
|
||||
BFMatcher::BFMatcher
|
||||
--------------------
|
||||
Brute-force matcher constructor.
|
||||
|
||||
.. ocv:function:: BFMatcher::BFMatcher( int normType=NORM_L2, bool crossCheck=false )
|
||||
|
||||
:param normType: One of ``NORM_L1``, ``NORM_L2``, ``NORM_HAMMING``, ``NORM_HAMMING2``. ``L1`` and ``L2`` norms are preferable choices for SIFT and SURF descriptors, ``NORM_HAMMING`` should be used with ORB, BRISK and BRIEF, ``NORM_HAMMING2`` should be used with ORB when ``WTA_K==3`` or ``4`` (see ORB::ORB constructor description).
|
||||
|
||||
:param crossCheck: If it is false, this is will be default BFMatcher behaviour when it finds the k nearest neighbors for each query descriptor. If ``crossCheck==true``, then the ``knnMatch()`` method with ``k=1`` will only return pairs ``(i,j)`` such that for ``i-th`` query descriptor the ``j-th`` descriptor in the matcher's collection is the nearest and vice versa, i.e. the ``BFMatcher`` will only return consistent pairs. Such technique usually produces best results with minimal number of outliers when there are enough matches. This is alternative to the ratio test, used by D. Lowe in SIFT paper.
|
||||
|
||||
|
||||
FlannBasedMatcher
|
||||
-----------------
|
||||
.. ocv:class:: FlannBasedMatcher : public DescriptorMatcher
|
||||
|
||||
Flann-based descriptor matcher. This matcher trains :ocv:class:`flann::Index_` on a train descriptor collection and calls its nearest search methods to find the best matches. So, this matcher may be faster when matching a large train collection than the brute force matcher. ``FlannBasedMatcher`` does not support masking permissible matches of descriptor sets because ``flann::Index`` does not support this. ::
|
||||
|
||||
class FlannBasedMatcher : public DescriptorMatcher
|
||||
{
|
||||
public:
|
||||
FlannBasedMatcher(
|
||||
const Ptr<flann::IndexParams>& indexParams=new flann::KDTreeIndexParams(),
|
||||
const Ptr<flann::SearchParams>& searchParams=new flann::SearchParams() );
|
||||
|
||||
virtual void add( InputArrayOfArrays descriptors );
|
||||
virtual void clear();
|
||||
|
||||
virtual void train();
|
||||
virtual bool isMaskSupported() const;
|
||||
|
||||
virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const;
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
..
|
||||
@@ -1,502 +0,0 @@
|
||||
Common Interfaces of Feature Detectors
|
||||
======================================
|
||||
|
||||
.. highlight:: cpp
|
||||
|
||||
Feature detectors in OpenCV have wrappers with a common interface that enables you to easily switch
|
||||
between different algorithms solving the same problem. All objects that implement keypoint detectors
|
||||
inherit the
|
||||
:ocv:class:`FeatureDetector` interface.
|
||||
|
||||
.. note::
|
||||
|
||||
* An example explaining keypoint detection can be found at opencv_source_code/samples/cpp/descriptor_extractor_matcher.cpp
|
||||
|
||||
FeatureDetector
|
||||
---------------
|
||||
.. ocv:class:: FeatureDetector : public Algorithm
|
||||
|
||||
Abstract base class for 2D image feature detectors. ::
|
||||
|
||||
class CV_EXPORTS FeatureDetector
|
||||
{
|
||||
public:
|
||||
virtual ~FeatureDetector();
|
||||
|
||||
void detect( InputArray image, vector<KeyPoint>& keypoints,
|
||||
InputArray mask=noArray() ) const;
|
||||
|
||||
void detect( InputArrayOfArrays images,
|
||||
vector<vector<KeyPoint> >& keypoints,
|
||||
InputArrayOfArrays masks=noArray() ) const;
|
||||
|
||||
virtual void read(const FileNode&);
|
||||
virtual void write(FileStorage&) const;
|
||||
|
||||
static Ptr<FeatureDetector> create( const String& detectorType );
|
||||
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
FeatureDetector::detect
|
||||
---------------------------
|
||||
Detects keypoints in an image (first variant) or image set (second variant).
|
||||
|
||||
.. ocv:function:: void FeatureDetector::detect( InputArray image, vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const
|
||||
|
||||
.. ocv:function:: void FeatureDetector::detect( InputArrayOfArrays images, vector<vector<KeyPoint> >& keypoints, InputArrayOfArrays masks=noArray() ) const
|
||||
|
||||
.. ocv:pyfunction:: cv2.FeatureDetector_create.detect(image[, mask]) -> keypoints
|
||||
|
||||
:param image: Image.
|
||||
|
||||
:param images: Image set.
|
||||
|
||||
:param keypoints: The detected keypoints. In the second variant of the method ``keypoints[i]`` is a set of keypoints detected in ``images[i]`` .
|
||||
|
||||
:param mask: Mask specifying where to look for keypoints (optional). It must be a 8-bit integer matrix with non-zero values in the region of interest.
|
||||
|
||||
:param masks: Masks for each input image specifying where to look for keypoints (optional). ``masks[i]`` is a mask for ``images[i]``.
|
||||
|
||||
FeatureDetector::create
|
||||
-----------------------
|
||||
Creates a feature detector by its name.
|
||||
|
||||
.. ocv:function:: Ptr<FeatureDetector> FeatureDetector::create( const String& detectorType )
|
||||
|
||||
.. ocv:pyfunction:: cv2.FeatureDetector_create(detectorType) -> retval
|
||||
|
||||
:param detectorType: Feature detector type.
|
||||
|
||||
The following detector types are supported:
|
||||
|
||||
* ``"FAST"`` -- :ocv:class:`FastFeatureDetector`
|
||||
* ``"STAR"`` -- :ocv:class:`StarFeatureDetector`
|
||||
* ``"SIFT"`` -- :ocv:class:`SIFT` (nonfree module)
|
||||
* ``"SURF"`` -- :ocv:class:`SURF` (nonfree module)
|
||||
* ``"ORB"`` -- :ocv:class:`ORB`
|
||||
* ``"BRISK"`` -- :ocv:class:`BRISK`
|
||||
* ``"MSER"`` -- :ocv:class:`MSER`
|
||||
* ``"GFTT"`` -- :ocv:class:`GoodFeaturesToTrackDetector`
|
||||
* ``"HARRIS"`` -- :ocv:class:`GoodFeaturesToTrackDetector` with Harris detector enabled
|
||||
* ``"Dense"`` -- :ocv:class:`DenseFeatureDetector`
|
||||
* ``"SimpleBlob"`` -- :ocv:class:`SimpleBlobDetector`
|
||||
|
||||
Also a combined format is supported: feature detector adapter name ( ``"Grid"`` --
|
||||
:ocv:class:`GridAdaptedFeatureDetector`, ``"Pyramid"`` --
|
||||
:ocv:class:`PyramidAdaptedFeatureDetector` ) + feature detector name (see above),
|
||||
for example: ``"GridFAST"``, ``"PyramidSTAR"`` .
|
||||
|
||||
FastFeatureDetector
|
||||
-------------------
|
||||
.. ocv:class:: FastFeatureDetector : public FeatureDetector
|
||||
|
||||
Wrapping class for feature detection using the
|
||||
:ocv:func:`FAST` method. ::
|
||||
|
||||
class FastFeatureDetector : public FeatureDetector
|
||||
{
|
||||
public:
|
||||
FastFeatureDetector( int threshold=1, bool nonmaxSuppression=true, type=FastFeatureDetector::TYPE_9_16 );
|
||||
virtual void read( const FileNode& fn );
|
||||
virtual void write( FileStorage& fs ) const;
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
GoodFeaturesToTrackDetector
|
||||
---------------------------
|
||||
.. ocv:class:: GoodFeaturesToTrackDetector : public FeatureDetector
|
||||
|
||||
Wrapping class for feature detection using the
|
||||
:ocv:func:`goodFeaturesToTrack` function. ::
|
||||
|
||||
class GoodFeaturesToTrackDetector : public FeatureDetector
|
||||
{
|
||||
public:
|
||||
class Params
|
||||
{
|
||||
public:
|
||||
Params( int maxCorners=1000, double qualityLevel=0.01,
|
||||
double minDistance=1., int blockSize=3,
|
||||
bool useHarrisDetector=false, double k=0.04 );
|
||||
void read( const FileNode& fn );
|
||||
void write( FileStorage& fs ) const;
|
||||
|
||||
int maxCorners;
|
||||
double qualityLevel;
|
||||
double minDistance;
|
||||
int blockSize;
|
||||
bool useHarrisDetector;
|
||||
double k;
|
||||
};
|
||||
|
||||
GoodFeaturesToTrackDetector( const GoodFeaturesToTrackDetector::Params& params=
|
||||
GoodFeaturesToTrackDetector::Params() );
|
||||
GoodFeaturesToTrackDetector( int maxCorners, double qualityLevel,
|
||||
double minDistance, int blockSize=3,
|
||||
bool useHarrisDetector=false, double k=0.04 );
|
||||
virtual void read( const FileNode& fn );
|
||||
virtual void write( FileStorage& fs ) const;
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
MserFeatureDetector
|
||||
-------------------
|
||||
.. ocv:class:: MserFeatureDetector : public FeatureDetector
|
||||
|
||||
Wrapping class for feature detection using the
|
||||
:ocv:class:`MSER` class. ::
|
||||
|
||||
class MserFeatureDetector : public FeatureDetector
|
||||
{
|
||||
public:
|
||||
MserFeatureDetector( CvMSERParams params=cvMSERParams() );
|
||||
MserFeatureDetector( int delta, int minArea, int maxArea,
|
||||
double maxVariation, double minDiversity,
|
||||
int maxEvolution, double areaThreshold,
|
||||
double minMargin, int edgeBlurSize );
|
||||
virtual void read( const FileNode& fn );
|
||||
virtual void write( FileStorage& fs ) const;
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
StarFeatureDetector
|
||||
-------------------
|
||||
.. ocv:class:: StarFeatureDetector : public FeatureDetector
|
||||
|
||||
The class implements the keypoint detector introduced by [Agrawal08]_, synonym of ``StarDetector``. ::
|
||||
|
||||
class StarFeatureDetector : public FeatureDetector
|
||||
{
|
||||
public:
|
||||
StarFeatureDetector( int maxSize=16, int responseThreshold=30,
|
||||
int lineThresholdProjected = 10,
|
||||
int lineThresholdBinarized=8, int suppressNonmaxSize=5 );
|
||||
virtual void read( const FileNode& fn );
|
||||
virtual void write( FileStorage& fs ) const;
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
.. [Agrawal08] Agrawal, M., Konolige, K., & Blas, M. R. (2008). Censure: Center surround extremas for realtime feature detection and matching. In Computer Vision–ECCV 2008 (pp. 102-115). Springer Berlin Heidelberg.
|
||||
|
||||
|
||||
DenseFeatureDetector
|
||||
--------------------
|
||||
.. ocv:class:: DenseFeatureDetector : public FeatureDetector
|
||||
|
||||
Class for generation of image features which are distributed densely and regularly over the image. ::
|
||||
|
||||
class DenseFeatureDetector : public FeatureDetector
|
||||
{
|
||||
public:
|
||||
DenseFeatureDetector( float initFeatureScale=1.f, int featureScaleLevels=1,
|
||||
float featureScaleMul=0.1f,
|
||||
int initXyStep=6, int initImgBound=0,
|
||||
bool varyXyStepWithScale=true,
|
||||
bool varyImgBoundWithScale=false );
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
The detector generates several levels (in the amount of ``featureScaleLevels``) of features. Features of each level are located in the nodes of a regular grid over the image (excluding the image boundary of given size). The level parameters (a feature scale, a node size, a size of boundary) are multiplied by ``featureScaleMul`` with level index growing depending on input flags, viz.:
|
||||
|
||||
* Feature scale is multiplied always.
|
||||
|
||||
* The grid node size is multiplied if ``varyXyStepWithScale`` is ``true``.
|
||||
|
||||
* Size of image boundary is multiplied if ``varyImgBoundWithScale`` is ``true``.
|
||||
|
||||
|
||||
SimpleBlobDetector
|
||||
-------------------
|
||||
.. ocv:class:: SimpleBlobDetector : public FeatureDetector
|
||||
|
||||
Class for extracting blobs from an image. ::
|
||||
|
||||
class SimpleBlobDetector : public FeatureDetector
|
||||
{
|
||||
public:
|
||||
struct Params
|
||||
{
|
||||
Params();
|
||||
float thresholdStep;
|
||||
float minThreshold;
|
||||
float maxThreshold;
|
||||
size_t minRepeatability;
|
||||
float minDistBetweenBlobs;
|
||||
|
||||
bool filterByColor;
|
||||
uchar blobColor;
|
||||
|
||||
bool filterByArea;
|
||||
float minArea, maxArea;
|
||||
|
||||
bool filterByCircularity;
|
||||
float minCircularity, maxCircularity;
|
||||
|
||||
bool filterByInertia;
|
||||
float minInertiaRatio, maxInertiaRatio;
|
||||
|
||||
bool filterByConvexity;
|
||||
float minConvexity, maxConvexity;
|
||||
};
|
||||
|
||||
SimpleBlobDetector(const SimpleBlobDetector::Params ¶meters = SimpleBlobDetector::Params());
|
||||
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
The class implements a simple algorithm for extracting blobs from an image:
|
||||
|
||||
#. Convert the source image to binary images by applying thresholding with several thresholds from ``minThreshold`` (inclusive) to ``maxThreshold`` (exclusive) with distance ``thresholdStep`` between neighboring thresholds.
|
||||
|
||||
#. Extract connected components from every binary image by :ocv:func:`findContours` and calculate their centers.
|
||||
|
||||
#. Group centers from several binary images by their coordinates. Close centers form one group that corresponds to one blob, which is controlled by the ``minDistBetweenBlobs`` parameter.
|
||||
|
||||
#. From the groups, estimate final centers of blobs and their radiuses and return as locations and sizes of keypoints.
|
||||
|
||||
This class performs several filtrations of returned blobs. You should set ``filterBy*`` to true/false to turn on/off corresponding filtration. Available filtrations:
|
||||
|
||||
* **By color**. This filter compares the intensity of a binary image at the center of a blob to ``blobColor``. If they differ, the blob is filtered out. Use ``blobColor = 0`` to extract dark blobs and ``blobColor = 255`` to extract light blobs.
|
||||
|
||||
* **By area**. Extracted blobs have an area between ``minArea`` (inclusive) and ``maxArea`` (exclusive).
|
||||
|
||||
* **By circularity**. Extracted blobs have circularity (:math:`\frac{4*\pi*Area}{perimeter * perimeter}`) between ``minCircularity`` (inclusive) and ``maxCircularity`` (exclusive).
|
||||
|
||||
* **By ratio of the minimum inertia to maximum inertia**. Extracted blobs have this ratio between ``minInertiaRatio`` (inclusive) and ``maxInertiaRatio`` (exclusive).
|
||||
|
||||
* **By convexity**. Extracted blobs have convexity (area / area of blob convex hull) between ``minConvexity`` (inclusive) and ``maxConvexity`` (exclusive).
|
||||
|
||||
|
||||
Default values of parameters are tuned to extract dark circular blobs.
|
||||
|
||||
GridAdaptedFeatureDetector
|
||||
--------------------------
|
||||
.. ocv:class:: GridAdaptedFeatureDetector : public FeatureDetector
|
||||
|
||||
Class adapting a detector to partition the source image into a grid and detect points in each cell. ::
|
||||
|
||||
class GridAdaptedFeatureDetector : public FeatureDetector
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* detector Detector that will be adapted.
|
||||
* maxTotalKeypoints Maximum count of keypoints detected on the image.
|
||||
* Only the strongest keypoints will be kept.
|
||||
* gridRows Grid row count.
|
||||
* gridCols Grid column count.
|
||||
*/
|
||||
GridAdaptedFeatureDetector( const Ptr<FeatureDetector>& detector,
|
||||
int maxTotalKeypoints, int gridRows=4,
|
||||
int gridCols=4 );
|
||||
virtual void read( const FileNode& fn );
|
||||
virtual void write( FileStorage& fs ) const;
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
PyramidAdaptedFeatureDetector
|
||||
-----------------------------
|
||||
.. ocv:class:: PyramidAdaptedFeatureDetector : public FeatureDetector
|
||||
|
||||
Class adapting a detector to detect points over multiple levels of a Gaussian pyramid. Consider using this class for detectors that are not inherently scaled. ::
|
||||
|
||||
class PyramidAdaptedFeatureDetector : public FeatureDetector
|
||||
{
|
||||
public:
|
||||
PyramidAdaptedFeatureDetector( const Ptr<FeatureDetector>& detector,
|
||||
int levels=2 );
|
||||
virtual void read( const FileNode& fn );
|
||||
virtual void write( FileStorage& fs ) const;
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
DynamicAdaptedFeatureDetector
|
||||
-----------------------------
|
||||
.. ocv:class:: DynamicAdaptedFeatureDetector : public FeatureDetector
|
||||
|
||||
Adaptively adjusting detector that iteratively detects features until the desired number is found. ::
|
||||
|
||||
class DynamicAdaptedFeatureDetector: public FeatureDetector
|
||||
{
|
||||
public:
|
||||
DynamicAdaptedFeatureDetector( const Ptr<AdjusterAdapter>& adjuster,
|
||||
int min_features=400, int max_features=500, int max_iters=5 );
|
||||
...
|
||||
};
|
||||
|
||||
If the detector is persisted, it "remembers" the parameters
|
||||
used for the last detection. In this case, the detector may be used for consistent numbers
|
||||
of keypoints in a set of temporally related images, such as video streams or
|
||||
panorama series.
|
||||
|
||||
``DynamicAdaptedFeatureDetector`` uses another detector, such as FAST or SURF, to do the dirty work,
|
||||
with the help of ``AdjusterAdapter`` .
|
||||
If the detected number of features is not large enough,
|
||||
``AdjusterAdapter`` adjusts the detection parameters so that the next detection
|
||||
results in a bigger or smaller number of features. This is repeated until either the number of desired features are found
|
||||
or the parameters are maxed out.
|
||||
|
||||
Adapters can be easily implemented for any detector via the
|
||||
``AdjusterAdapter`` interface.
|
||||
|
||||
Beware that this is not thread-safe since the adjustment of parameters requires modification of the feature detector class instance.
|
||||
|
||||
Example of creating ``DynamicAdaptedFeatureDetector`` : ::
|
||||
|
||||
//sample usage:
|
||||
//will create a detector that attempts to find
|
||||
//100 - 110 FAST Keypoints, and will at most run
|
||||
//FAST feature detection 10 times until that
|
||||
//number of keypoints are found
|
||||
Ptr<FeatureDetector> detector(new DynamicAdaptedFeatureDetector (100, 110, 10,
|
||||
new FastAdjuster(20,true)));
|
||||
|
||||
|
||||
DynamicAdaptedFeatureDetector::DynamicAdaptedFeatureDetector
|
||||
------------------------------------------------------------
|
||||
The constructor
|
||||
|
||||
.. ocv:function:: DynamicAdaptedFeatureDetector::DynamicAdaptedFeatureDetector( const Ptr<AdjusterAdapter>& adjuster, int min_features=400, int max_features=500, int max_iters=5 )
|
||||
|
||||
:param adjuster: :ocv:class:`AdjusterAdapter` that detects features and adjusts parameters.
|
||||
|
||||
:param min_features: Minimum desired number of features.
|
||||
|
||||
:param max_features: Maximum desired number of features.
|
||||
|
||||
:param max_iters: Maximum number of times to try adjusting the feature detector parameters. For :ocv:class:`FastAdjuster` , this number can be high, but with ``Star`` or ``Surf`` many iterations can be time-consuming. At each iteration the detector is rerun.
|
||||
|
||||
AdjusterAdapter
|
||||
---------------
|
||||
.. ocv:class:: AdjusterAdapter : public FeatureDetector
|
||||
|
||||
Class providing an interface for adjusting parameters of a feature detector. This interface is used by :ocv:class:`DynamicAdaptedFeatureDetector` . It is a wrapper for :ocv:class:`FeatureDetector` that enables adjusting parameters after feature detection. ::
|
||||
|
||||
class AdjusterAdapter: public FeatureDetector
|
||||
{
|
||||
public:
|
||||
virtual ~AdjusterAdapter() {}
|
||||
virtual void tooFew(int min, int n_detected) = 0;
|
||||
virtual void tooMany(int max, int n_detected) = 0;
|
||||
virtual bool good() const = 0;
|
||||
virtual Ptr<AdjusterAdapter> clone() const = 0;
|
||||
static Ptr<AdjusterAdapter> create( const String& detectorType );
|
||||
};
|
||||
|
||||
|
||||
See
|
||||
:ocv:class:`FastAdjuster`,
|
||||
:ocv:class:`StarAdjuster`, and
|
||||
:ocv:class:`SurfAdjuster` for concrete implementations.
|
||||
|
||||
AdjusterAdapter::tooFew
|
||||
---------------------------
|
||||
Adjusts the detector parameters to detect more features.
|
||||
|
||||
.. ocv:function:: void AdjusterAdapter::tooFew(int min, int n_detected)
|
||||
|
||||
:param min: Minimum desired number of features.
|
||||
|
||||
:param n_detected: Number of features detected during the latest run.
|
||||
|
||||
Example: ::
|
||||
|
||||
void FastAdjuster::tooFew(int min, int n_detected)
|
||||
{
|
||||
thresh_--;
|
||||
}
|
||||
|
||||
AdjusterAdapter::tooMany
|
||||
----------------------------
|
||||
Adjusts the detector parameters to detect less features.
|
||||
|
||||
.. ocv:function:: void AdjusterAdapter::tooMany(int max, int n_detected)
|
||||
|
||||
:param max: Maximum desired number of features.
|
||||
|
||||
:param n_detected: Number of features detected during the latest run.
|
||||
|
||||
Example: ::
|
||||
|
||||
void FastAdjuster::tooMany(int min, int n_detected)
|
||||
{
|
||||
thresh_++;
|
||||
}
|
||||
|
||||
|
||||
AdjusterAdapter::good
|
||||
---------------------
|
||||
Returns false if the detector parameters cannot be adjusted any more.
|
||||
|
||||
.. ocv:function:: bool AdjusterAdapter::good() const
|
||||
|
||||
Example: ::
|
||||
|
||||
bool FastAdjuster::good() const
|
||||
{
|
||||
return (thresh_ > 1) && (thresh_ < 200);
|
||||
}
|
||||
|
||||
AdjusterAdapter::create
|
||||
-----------------------
|
||||
Creates an adjuster adapter by name
|
||||
|
||||
.. ocv:function:: Ptr<AdjusterAdapter> AdjusterAdapter::create( const String& detectorType )
|
||||
|
||||
Creates an adjuster adapter by name ``detectorType``. The detector name is the same as in :ocv:func:`FeatureDetector::create`, but now supports ``"FAST"``, ``"STAR"``, and ``"SURF"`` only.
|
||||
|
||||
FastAdjuster
|
||||
------------
|
||||
.. ocv:class:: FastAdjuster : public AdjusterAdapter
|
||||
|
||||
:ocv:class:`AdjusterAdapter` for :ocv:class:`FastFeatureDetector`. This class decreases or increases the threshold value by 1. ::
|
||||
|
||||
class FastAdjuster FastAdjuster: public AdjusterAdapter
|
||||
{
|
||||
public:
|
||||
FastAdjuster(int init_thresh = 20, bool nonmax = true);
|
||||
...
|
||||
};
|
||||
|
||||
StarAdjuster
|
||||
------------
|
||||
.. ocv:class:: StarAdjuster : public AdjusterAdapter
|
||||
|
||||
:ocv:class:`AdjusterAdapter` for :ocv:class:`StarFeatureDetector`. This class adjusts the ``responseThreshhold`` of ``StarFeatureDetector``. ::
|
||||
|
||||
class StarAdjuster: public AdjusterAdapter
|
||||
{
|
||||
StarAdjuster(double initial_thresh = 30.0);
|
||||
...
|
||||
};
|
||||
|
||||
SurfAdjuster
|
||||
------------
|
||||
.. ocv:class:: SurfAdjuster : public AdjusterAdapter
|
||||
|
||||
:ocv:class:`AdjusterAdapter` for ``SurfFeatureDetector``. ::
|
||||
|
||||
class CV_EXPORTS SurfAdjuster: public AdjusterAdapter
|
||||
{
|
||||
public:
|
||||
SurfAdjuster( double initial_thresh=400.f, double min_thresh=2, double max_thresh=1000 );
|
||||
|
||||
virtual void tooFew(int minv, int n_detected);
|
||||
virtual void tooMany(int maxv, int n_detected);
|
||||
virtual bool good() const;
|
||||
|
||||
virtual Ptr<AdjusterAdapter> clone() const;
|
||||
|
||||
...
|
||||
};
|
||||
@@ -1,276 +0,0 @@
|
||||
Common Interfaces of Generic Descriptor Matchers
|
||||
================================================
|
||||
|
||||
.. highlight:: cpp
|
||||
|
||||
Matchers of keypoint descriptors in OpenCV have wrappers with a common interface that enables you to easily switch
|
||||
between different algorithms solving the same problem. This section is devoted to matching descriptors
|
||||
that cannot be represented as vectors in a multidimensional space. ``GenericDescriptorMatcher`` is a more generic interface for descriptors. It does not make any assumptions about descriptor representation.
|
||||
Every descriptor with the
|
||||
:ocv:class:`DescriptorExtractor` interface has a wrapper with the ``GenericDescriptorMatcher`` interface (see
|
||||
:ocv:class:`VectorDescriptorMatcher` ).
|
||||
There are descriptors such as the One-way descriptor and Ferns that have the ``GenericDescriptorMatcher`` interface implemented but do not support ``DescriptorExtractor``.
|
||||
|
||||
.. note::
|
||||
|
||||
* An example explaining keypoint description can be found at opencv_source_code/samples/cpp/descriptor_extractor_matcher.cpp
|
||||
* An example on descriptor matching evaluation can be found at opencv_source_code/samples/cpp/detector_descriptor_matcher_evaluation.cpp
|
||||
* An example on one to many image matching can be found at opencv_source_code/samples/cpp/matching_to_many_images.cpp
|
||||
|
||||
GenericDescriptorMatcher
|
||||
------------------------
|
||||
.. ocv:class:: GenericDescriptorMatcher
|
||||
|
||||
Abstract interface for extracting and matching a keypoint descriptor. There are also :ocv:class:`DescriptorExtractor` and :ocv:class:`DescriptorMatcher` for these purposes but their interfaces are intended for descriptors represented as vectors in a multidimensional space. ``GenericDescriptorMatcher`` is a more generic interface for descriptors. ``DescriptorMatcher`` and ``GenericDescriptorMatcher`` have two groups of match methods: for matching keypoints of an image with another image or with an image set. ::
|
||||
|
||||
class GenericDescriptorMatcher
|
||||
{
|
||||
public:
|
||||
GenericDescriptorMatcher();
|
||||
virtual ~GenericDescriptorMatcher();
|
||||
|
||||
virtual void add( InputArrayOfArrays images,
|
||||
vector<vector<KeyPoint> >& keypoints );
|
||||
|
||||
const vector<Mat>& getTrainImages() const;
|
||||
const vector<vector<KeyPoint> >& getTrainKeypoints() const;
|
||||
virtual void clear();
|
||||
|
||||
virtual void train() = 0;
|
||||
|
||||
virtual bool isMaskSupported() = 0;
|
||||
|
||||
void classify( InputArray queryImage,
|
||||
vector<KeyPoint>& queryKeypoints,
|
||||
InputArray trainImage,
|
||||
vector<KeyPoint>& trainKeypoints ) const;
|
||||
void classify( InputArray queryImage,
|
||||
vector<KeyPoint>& queryKeypoints );
|
||||
|
||||
/*
|
||||
* Group of methods to match keypoints from an image pair.
|
||||
*/
|
||||
void match( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
|
||||
InputArray trainImage, vector<KeyPoint>& trainKeypoints,
|
||||
vector<DMatch>& matches, InputArray mask=noArray() ) const;
|
||||
void knnMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
|
||||
InputArray trainImage, vector<KeyPoint>& trainKeypoints,
|
||||
vector<vector<DMatch> >& matches, int k,
|
||||
InputArray mask=noArray(), bool compactResult=false ) const;
|
||||
void radiusMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
|
||||
InputArray trainImage, vector<KeyPoint>& trainKeypoints,
|
||||
vector<vector<DMatch> >& matches, float maxDistance,
|
||||
InputArray mask=noArray(), bool compactResult=false ) const;
|
||||
/*
|
||||
* Group of methods to match keypoints from one image to an image set.
|
||||
*/
|
||||
void match( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
|
||||
vector<DMatch>& matches, InputArrayOfArrays masks=noArray() );
|
||||
void knnMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
|
||||
vector<vector<DMatch> >& matches, int k,
|
||||
InputArrayOfArrays masks=noArray(), bool compactResult=false );
|
||||
void radiusMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
|
||||
vector<vector<DMatch> >& matches, float maxDistance,
|
||||
InputArrayOfArrays masks=noArray(), bool compactResult=false );
|
||||
|
||||
virtual void read( const FileNode& );
|
||||
virtual void write( FileStorage& ) const;
|
||||
|
||||
virtual Ptr<GenericDescriptorMatcher> clone( bool emptyTrainData=false ) const = 0;
|
||||
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
GenericDescriptorMatcher::add
|
||||
---------------------------------
|
||||
Adds images and their keypoints to the training collection stored in the class instance.
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::add( InputArrayOfArrays images, vector<vector<KeyPoint> >& keypoints )
|
||||
|
||||
:param images: Image collection.
|
||||
|
||||
:param keypoints: Point collection. It is assumed that ``keypoints[i]`` are keypoints detected in the image ``images[i]`` .
|
||||
|
||||
|
||||
|
||||
GenericDescriptorMatcher::getTrainImages
|
||||
--------------------------------------------
|
||||
Returns a train image collection.
|
||||
|
||||
.. ocv:function:: const vector<Mat>& GenericDescriptorMatcher::getTrainImages() const
|
||||
|
||||
|
||||
|
||||
GenericDescriptorMatcher::getTrainKeypoints
|
||||
-----------------------------------------------
|
||||
Returns a train keypoints collection.
|
||||
|
||||
.. ocv:function:: const vector<vector<KeyPoint> >& GenericDescriptorMatcher::getTrainKeypoints() const
|
||||
|
||||
|
||||
|
||||
GenericDescriptorMatcher::clear
|
||||
-----------------------------------
|
||||
Clears a train collection (images and keypoints).
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::clear()
|
||||
|
||||
|
||||
|
||||
GenericDescriptorMatcher::train
|
||||
-----------------------------------
|
||||
Trains descriptor matcher
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::train()
|
||||
|
||||
Prepares descriptor matcher, for example, creates a tree-based structure, to extract descriptors or to optimize descriptors matching.
|
||||
|
||||
|
||||
GenericDescriptorMatcher::isMaskSupported
|
||||
---------------------------------------------
|
||||
Returns ``true`` if a generic descriptor matcher supports masking permissible matches.
|
||||
|
||||
.. ocv:function:: bool GenericDescriptorMatcher::isMaskSupported()
|
||||
|
||||
|
||||
|
||||
GenericDescriptorMatcher::classify
|
||||
--------------------------------------
|
||||
Classifies keypoints from a query set.
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::classify( InputArray queryImage, vector<KeyPoint>& queryKeypoints, InputArray trainImage, vector<KeyPoint>& trainKeypoints ) const
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::classify( InputArray queryImage, vector<KeyPoint>& queryKeypoints )
|
||||
|
||||
:param queryImage: Query image.
|
||||
|
||||
:param queryKeypoints: Keypoints from a query image.
|
||||
|
||||
:param trainImage: Train image.
|
||||
|
||||
:param trainKeypoints: Keypoints from a train image.
|
||||
|
||||
The method classifies each keypoint from a query set. The first variant of the method takes a train image and its keypoints as an input argument. The second variant uses the internally stored training collection that can be built using the ``GenericDescriptorMatcher::add`` method.
|
||||
|
||||
The methods do the following:
|
||||
|
||||
#.
|
||||
Call the ``GenericDescriptorMatcher::match`` method to find correspondence between the query set and the training set.
|
||||
|
||||
#.
|
||||
Set the ``class_id`` field of each keypoint from the query set to ``class_id`` of the corresponding keypoint from the training set.
|
||||
|
||||
|
||||
|
||||
GenericDescriptorMatcher::match
|
||||
-----------------------------------
|
||||
Finds the best match in the training set for each keypoint from the query set.
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::match(InputArray queryImage, vector<KeyPoint>& queryKeypoints, InputArray trainImage, vector<KeyPoint>& trainKeypoints, vector<DMatch>& matches, InputArray mask=noArray() ) const
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::match( InputArray queryImage, vector<KeyPoint>& queryKeypoints, vector<DMatch>& matches, InputArrayOfArrays masks=noArray() )
|
||||
|
||||
:param queryImage: Query image.
|
||||
|
||||
:param queryKeypoints: Keypoints detected in ``queryImage`` .
|
||||
|
||||
:param trainImage: Train image. It is not added to a train image collection stored in the class object.
|
||||
|
||||
:param trainKeypoints: Keypoints detected in ``trainImage`` . They are not added to a train points collection stored in the class object.
|
||||
|
||||
:param matches: Matches. If a query descriptor (keypoint) is masked out in ``mask`` , match is added for this descriptor. So, ``matches`` size may be smaller than the query keypoints count.
|
||||
|
||||
:param mask: Mask specifying permissible matches between an input query and train keypoints.
|
||||
|
||||
:param masks: Set of masks. Each ``masks[i]`` specifies permissible matches between input query keypoints and stored train keypoints from the i-th image.
|
||||
|
||||
The methods find the best match for each query keypoint. In the first variant of the method, a train image and its keypoints are the input arguments. In the second variant, query keypoints are matched to the internally stored training collection that can be built using the ``GenericDescriptorMatcher::add`` method. Optional mask (or masks) can be passed to specify which query and training descriptors can be matched. Namely, ``queryKeypoints[i]`` can be matched with ``trainKeypoints[j]`` only if ``mask.at<uchar>(i,j)`` is non-zero.
|
||||
|
||||
|
||||
|
||||
GenericDescriptorMatcher::knnMatch
|
||||
--------------------------------------
|
||||
Finds the ``k`` best matches for each query keypoint.
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::knnMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints, InputArray trainImage, vector<KeyPoint>& trainKeypoints, vector<vector<DMatch> >& matches, int k, InputArray mask=noArray(), bool compactResult=false ) const
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::knnMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints, vector<vector<DMatch> >& matches, int k, InputArrayOfArrays masks=noArray(), bool compactResult=false )
|
||||
|
||||
The methods are extended variants of ``GenericDescriptorMatch::match``. The parameters are similar, and the semantics is similar to ``DescriptorMatcher::knnMatch``. But this class does not require explicitly computed keypoint descriptors.
|
||||
|
||||
|
||||
|
||||
GenericDescriptorMatcher::radiusMatch
|
||||
-----------------------------------------
|
||||
For each query keypoint, finds the training keypoints not farther than the specified distance.
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::radiusMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints, InputArray trainImage, vector<KeyPoint>& trainKeypoints, vector<vector<DMatch> >& matches, float maxDistance, InputArray mask=noArray(), bool compactResult=false ) const
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::radiusMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints, vector<vector<DMatch> >& matches, float maxDistance, InputArrayOfArrays masks=noArray(), bool compactResult=false )
|
||||
|
||||
The methods are similar to ``DescriptorMatcher::radius``. But this class does not require explicitly computed keypoint descriptors.
|
||||
|
||||
|
||||
|
||||
GenericDescriptorMatcher::read
|
||||
----------------------------------
|
||||
Reads a matcher object from a file node.
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::read( const FileNode& fn )
|
||||
|
||||
|
||||
|
||||
GenericDescriptorMatcher::write
|
||||
-----------------------------------
|
||||
Writes a match object to a file storage.
|
||||
|
||||
.. ocv:function:: void GenericDescriptorMatcher::write( FileStorage& fs ) const
|
||||
|
||||
|
||||
GenericDescriptorMatcher::clone
|
||||
-----------------------------------
|
||||
Clones the matcher.
|
||||
|
||||
.. ocv:function:: Ptr<GenericDescriptorMatcher> GenericDescriptorMatcher::clone( bool emptyTrainData=false ) const
|
||||
|
||||
:param emptyTrainData: If ``emptyTrainData`` is false, the method creates a deep copy of the object, that is, copies
|
||||
both parameters and train data. If ``emptyTrainData`` is true, the method creates an object copy with the current parameters
|
||||
but with empty train data.
|
||||
|
||||
|
||||
VectorDescriptorMatcher
|
||||
-----------------------
|
||||
.. ocv:class:: VectorDescriptorMatcher : public GenericDescriptorMatcher
|
||||
|
||||
Class used for matching descriptors that can be described as vectors in a finite-dimensional space. ::
|
||||
|
||||
class CV_EXPORTS VectorDescriptorMatcher : public GenericDescriptorMatcher
|
||||
{
|
||||
public:
|
||||
VectorDescriptorMatcher( const Ptr<DescriptorExtractor>& extractor, const Ptr<DescriptorMatcher>& matcher );
|
||||
virtual ~VectorDescriptorMatcher();
|
||||
|
||||
virtual void add( InputArrayOfArrays imgCollection,
|
||||
vector<vector<KeyPoint> >& pointCollection );
|
||||
virtual void clear();
|
||||
virtual void train();
|
||||
virtual bool isMaskSupported();
|
||||
|
||||
virtual void read( const FileNode& fn );
|
||||
virtual void write( FileStorage& fs ) const;
|
||||
|
||||
virtual Ptr<GenericDescriptorMatcher> clone( bool emptyTrainData=false ) const;
|
||||
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
Example: ::
|
||||
|
||||
VectorDescriptorMatcher matcher( new SurfDescriptorExtractor,
|
||||
new BruteForceMatcher<L2<float> > );
|
||||
@@ -1,86 +0,0 @@
|
||||
Drawing Function of Keypoints and Matches
|
||||
=========================================
|
||||
|
||||
|
||||
|
||||
drawMatches
|
||||
---------------
|
||||
Draws the found matches of keypoints from two images.
|
||||
|
||||
.. ocv:function:: void drawMatches( InputArray img1, const vector<KeyPoint>& keypoints1, InputArray img2, const vector<KeyPoint>& keypoints2, const vector<DMatch>& matches1to2, InputOutputArray outImg, const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1), const vector<char>& matchesMask=vector<char>(), int flags=DrawMatchesFlags::DEFAULT )
|
||||
|
||||
.. ocv:function:: void drawMatches( InputArray img1, const vector<KeyPoint>& keypoints1, InputArray img2, const vector<KeyPoint>& keypoints2, const vector<vector<DMatch> >& matches1to2, InputOutputArray outImg, const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1), const vector<vector<char> >& matchesMask=vector<vector<char> >(), int flags=DrawMatchesFlags::DEFAULT )
|
||||
|
||||
.. ocv:pyfunction:: cv2.drawMatches(img1, keypoints1, img2, keypoints2, matches1to2[, outImg[, matchColor[, singlePointColor[, matchesMask[, flags]]]]]) -> outImg
|
||||
|
||||
.. ocv:pyfunction:: cv2.drawMatchesKnn(img1, keypoints1, img2, keypoints2, matches1to2[, outImg[, matchColor[, singlePointColor[, matchesMask[, flags]]]]]) -> outImg
|
||||
|
||||
|
||||
:param img1: First source image.
|
||||
|
||||
:param keypoints1: Keypoints from the first source image.
|
||||
|
||||
:param img2: Second source image.
|
||||
|
||||
:param keypoints2: Keypoints from the second source image.
|
||||
|
||||
:param matches1to2: Matches from the first image to the second one, which means that ``keypoints1[i]`` has a corresponding point in ``keypoints2[matches[i]]`` .
|
||||
|
||||
:param outImg: Output image. Its content depends on the ``flags`` value defining what is drawn in the output image. See possible ``flags`` bit values below.
|
||||
|
||||
:param matchColor: Color of matches (lines and connected keypoints). If ``matchColor==Scalar::all(-1)`` , the color is generated randomly.
|
||||
|
||||
:param singlePointColor: Color of single keypoints (circles), which means that keypoints do not have the matches. If ``singlePointColor==Scalar::all(-1)`` , the color is generated randomly.
|
||||
|
||||
:param matchesMask: Mask determining which matches are drawn. If the mask is empty, all matches are drawn.
|
||||
|
||||
:param flags: Flags setting drawing features. Possible ``flags`` bit values are defined by ``DrawMatchesFlags``.
|
||||
|
||||
This function draws matches of keypoints from two images in the output image. Match is a line connecting two keypoints (circles). The structure ``DrawMatchesFlags`` is defined as follows:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
struct DrawMatchesFlags
|
||||
{
|
||||
enum
|
||||
{
|
||||
DEFAULT = 0, // Output image matrix will be created (Mat::create),
|
||||
// i.e. existing memory of output image may be reused.
|
||||
// Two source images, matches, and single keypoints
|
||||
// will be drawn.
|
||||
// For each keypoint, only the center point will be
|
||||
// drawn (without a circle around the keypoint with the
|
||||
// keypoint size and orientation).
|
||||
DRAW_OVER_OUTIMG = 1, // Output image matrix will not be
|
||||
// created (using Mat::create). Matches will be drawn
|
||||
// on existing content of output image.
|
||||
NOT_DRAW_SINGLE_POINTS = 2, // Single keypoints will not be drawn.
|
||||
DRAW_RICH_KEYPOINTS = 4 // For each keypoint, the circle around
|
||||
// keypoint with keypoint size and orientation will
|
||||
// be drawn.
|
||||
};
|
||||
};
|
||||
|
||||
..
|
||||
|
||||
|
||||
|
||||
drawKeypoints
|
||||
-----------------
|
||||
Draws keypoints.
|
||||
|
||||
.. ocv:function:: void drawKeypoints( InputArray image, const vector<KeyPoint>& keypoints, InputOutputArray outImage, const Scalar& color=Scalar::all(-1), int flags=DrawMatchesFlags::DEFAULT )
|
||||
|
||||
.. ocv:pyfunction:: cv2.drawKeypoints(image, keypoints[, outImage[, color[, flags]]]) -> outImage
|
||||
|
||||
:param image: Source image.
|
||||
|
||||
:param keypoints: Keypoints from the source image.
|
||||
|
||||
:param outImage: Output image. Its content depends on the ``flags`` value defining what is drawn in the output image. See possible ``flags`` bit values below.
|
||||
|
||||
:param color: Color of keypoints.
|
||||
|
||||
:param flags: Flags setting drawing features. Possible ``flags`` bit values are defined by ``DrawMatchesFlags``. See details above in :ocv:func:`drawMatches` .
|
||||
|
||||
.. note:: For Python API, flags are modified as `cv2.DRAW_MATCHES_FLAGS_DEFAULT`, `cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS`, `cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG`, `cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS`
|
||||
@@ -1,314 +0,0 @@
|
||||
Feature Detection and Description
|
||||
=================================
|
||||
|
||||
.. highlight:: cpp
|
||||
|
||||
.. note::
|
||||
|
||||
* An example explaining keypoint detection and description can be found at opencv_source_code/samples/cpp/descriptor_extractor_matcher.cpp
|
||||
|
||||
FAST
|
||||
----
|
||||
Detects corners using the FAST algorithm
|
||||
|
||||
.. ocv:function:: void FAST( InputArray image, vector<KeyPoint>& keypoints, int threshold, bool nonmaxSuppression=true )
|
||||
.. ocv:function:: void FAST( InputArray image, vector<KeyPoint>& keypoints, int threshold, bool nonmaxSuppression, int type )
|
||||
|
||||
.. ocv:pyfunction:: cv2.FastFeatureDetector([, threshold[, nonmaxSuppression]]) -> <FastFeatureDetector object>
|
||||
.. ocv:pyfunction:: cv2.FastFeatureDetector(threshold, nonmaxSuppression, type) -> <FastFeatureDetector object>
|
||||
.. ocv:pyfunction:: cv2.FastFeatureDetector.detect(image[, mask]) -> keypoints
|
||||
|
||||
|
||||
:param image: grayscale image where keypoints (corners) are detected.
|
||||
|
||||
:param keypoints: keypoints detected on the image.
|
||||
|
||||
:param threshold: threshold on difference between intensity of the central pixel and pixels of a circle around this pixel.
|
||||
|
||||
:param nonmaxSuppression: if true, non-maximum suppression is applied to detected corners (keypoints).
|
||||
|
||||
:param type: one of the three neighborhoods as defined in the paper: ``FastFeatureDetector::TYPE_9_16``, ``FastFeatureDetector::TYPE_7_12``, ``FastFeatureDetector::TYPE_5_8``
|
||||
|
||||
Detects corners using the FAST algorithm by [Rosten06]_.
|
||||
|
||||
.. note:: In Python API, types are given as ``cv2.FAST_FEATURE_DETECTOR_TYPE_5_8``, ``cv2.FAST_FEATURE_DETECTOR_TYPE_7_12`` and ``cv2.FAST_FEATURE_DETECTOR_TYPE_9_16``. For corner detection, use ``cv2.FAST.detect()`` method.
|
||||
|
||||
|
||||
.. [Rosten06] E. Rosten. Machine Learning for High-speed Corner Detection, 2006.
|
||||
|
||||
|
||||
BriefDescriptorExtractor
|
||||
------------------------
|
||||
.. ocv:class:: BriefDescriptorExtractor : public DescriptorExtractor
|
||||
|
||||
Class for computing BRIEF descriptors described in a paper of Calonder M., Lepetit V.,
|
||||
Strecha C., Fua P. *BRIEF: Binary Robust Independent Elementary Features* ,
|
||||
11th European Conference on Computer Vision (ECCV), Heraklion, Crete. LNCS Springer, September 2010. ::
|
||||
|
||||
class BriefDescriptorExtractor : public DescriptorExtractor
|
||||
{
|
||||
public:
|
||||
static const int PATCH_SIZE = 48;
|
||||
static const int KERNEL_SIZE = 9;
|
||||
|
||||
// bytes is a length of descriptor in bytes. It can be equal 16, 32 or 64 bytes.
|
||||
BriefDescriptorExtractor( int bytes = 32 );
|
||||
|
||||
virtual void read( const FileNode& );
|
||||
virtual void write( FileStorage& ) const;
|
||||
virtual int descriptorSize() const;
|
||||
virtual int descriptorType() const;
|
||||
virtual int defaultNorm() const;
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
.. note::
|
||||
|
||||
* A complete BRIEF extractor sample can be found at opencv_source_code/samples/cpp/brief_match_test.cpp
|
||||
|
||||
|
||||
MSER
|
||||
----
|
||||
.. ocv:class:: MSER : public FeatureDetector
|
||||
|
||||
Maximally stable extremal region extractor. ::
|
||||
|
||||
class MSER : public CvMSERParams
|
||||
{
|
||||
public:
|
||||
// default constructor
|
||||
MSER();
|
||||
// constructor that initializes all the algorithm parameters
|
||||
MSER( int _delta, int _min_area, int _max_area,
|
||||
float _max_variation, float _min_diversity,
|
||||
int _max_evolution, double _area_threshold,
|
||||
double _min_margin, int _edge_blur_size );
|
||||
// runs the extractor on the specified image; returns the MSERs,
|
||||
// each encoded as a contour (vector<Point>, see findContours)
|
||||
// the optional mask marks the area where MSERs are searched for
|
||||
void operator()( const Mat& image, vector<vector<Point> >& msers, const Mat& mask ) const;
|
||||
};
|
||||
|
||||
The class encapsulates all the parameters of the MSER extraction algorithm (see
|
||||
http://en.wikipedia.org/wiki/Maximally_stable_extremal_regions). Also see http://code.opencv.org/projects/opencv/wiki/MSER for useful comments and parameters description.
|
||||
|
||||
.. note::
|
||||
|
||||
* (Python) A complete example showing the use of the MSER detector can be found at opencv_source_code/samples/python2/mser.py
|
||||
|
||||
|
||||
ORB
|
||||
---
|
||||
.. ocv:class:: ORB : public Feature2D
|
||||
|
||||
Class implementing the ORB (*oriented BRIEF*) keypoint detector and descriptor extractor, described in [RRKB11]_. The algorithm uses FAST in pyramids to detect stable keypoints, selects the strongest features using FAST or Harris response, finds their orientation using first-order moments and computes the descriptors using BRIEF (where the coordinates of random point pairs (or k-tuples) are rotated according to the measured orientation).
|
||||
|
||||
.. [RRKB11] Ethan Rublee, Vincent Rabaud, Kurt Konolige, Gary R. Bradski: ORB: An efficient alternative to SIFT or SURF. ICCV 2011: 2564-2571.
|
||||
|
||||
ORB::ORB
|
||||
--------
|
||||
The ORB constructor
|
||||
|
||||
.. ocv:function:: ORB::ORB(int nfeatures = 500, float scaleFactor = 1.2f, int nlevels = 8, int edgeThreshold = 31, int firstLevel = 0, int WTA_K=2, int scoreType=ORB::HARRIS_SCORE, int patchSize=31)
|
||||
|
||||
.. ocv:pyfunction:: cv2.ORB([, nfeatures[, scaleFactor[, nlevels[, edgeThreshold[, firstLevel[, WTA_K[, scoreType[, patchSize]]]]]]]]) -> <ORB object>
|
||||
|
||||
|
||||
:param nfeatures: The maximum number of features to retain.
|
||||
|
||||
:param scaleFactor: Pyramid decimation ratio, greater than 1. ``scaleFactor==2`` means the classical pyramid, where each next level has 4x less pixels than the previous, but such a big scale factor will degrade feature matching scores dramatically. On the other hand, too close to 1 scale factor will mean that to cover certain scale range you will need more pyramid levels and so the speed will suffer.
|
||||
|
||||
:param nlevels: The number of pyramid levels. The smallest level will have linear size equal to ``input_image_linear_size/pow(scaleFactor, nlevels)``.
|
||||
|
||||
:param edgeThreshold: This is size of the border where the features are not detected. It should roughly match the ``patchSize`` parameter.
|
||||
|
||||
:param firstLevel: It should be 0 in the current implementation.
|
||||
|
||||
:param WTA_K: The number of points that produce each element of the oriented BRIEF descriptor. The default value 2 means the BRIEF where we take a random point pair and compare their brightnesses, so we get 0/1 response. Other possible values are 3 and 4. For example, 3 means that we take 3 random points (of course, those point coordinates are random, but they are generated from the pre-defined seed, so each element of BRIEF descriptor is computed deterministically from the pixel rectangle), find point of maximum brightness and output index of the winner (0, 1 or 2). Such output will occupy 2 bits, and therefore it will need a special variant of Hamming distance, denoted as ``NORM_HAMMING2`` (2 bits per bin). When ``WTA_K=4``, we take 4 random points to compute each bin (that will also occupy 2 bits with possible values 0, 1, 2 or 3).
|
||||
|
||||
:param scoreType: The default HARRIS_SCORE means that Harris algorithm is used to rank features (the score is written to ``KeyPoint::score`` and is used to retain best ``nfeatures`` features); FAST_SCORE is alternative value of the parameter that produces slightly less stable keypoints, but it is a little faster to compute.
|
||||
|
||||
:param patchSize: size of the patch used by the oriented BRIEF descriptor. Of course, on smaller pyramid layers the perceived image area covered by a feature will be larger.
|
||||
|
||||
ORB::operator()
|
||||
---------------
|
||||
Finds keypoints in an image and computes their descriptors
|
||||
|
||||
.. ocv:function:: void ORB::operator()(InputArray image, InputArray mask, vector<KeyPoint>& keypoints, OutputArray descriptors, bool useProvidedKeypoints=false ) const
|
||||
|
||||
.. ocv:pyfunction:: cv2.ORB.detect(image[, mask]) -> keypoints
|
||||
.. ocv:pyfunction:: cv2.ORB.compute(image, keypoints[, descriptors]) -> keypoints, descriptors
|
||||
.. ocv:pyfunction:: cv2.ORB.detectAndCompute(image, mask[, descriptors[, useProvidedKeypoints]]) -> keypoints, descriptors
|
||||
|
||||
|
||||
:param image: The input 8-bit grayscale image.
|
||||
|
||||
:param mask: The operation mask.
|
||||
|
||||
:param keypoints: The output vector of keypoints.
|
||||
|
||||
:param descriptors: The output descriptors. Pass ``cv::noArray()`` if you do not need it.
|
||||
|
||||
:param useProvidedKeypoints: If it is true, then the method will use the provided vector of keypoints instead of detecting them.
|
||||
|
||||
|
||||
BRISK
|
||||
-----
|
||||
.. ocv:class:: BRISK : public Feature2D
|
||||
|
||||
Class implementing the BRISK keypoint detector and descriptor extractor, described in [LCS11]_.
|
||||
|
||||
.. [LCS11] Stefan Leutenegger, Margarita Chli and Roland Siegwart: BRISK: Binary Robust Invariant Scalable Keypoints. ICCV 2011: 2548-2555.
|
||||
|
||||
BRISK::BRISK
|
||||
------------
|
||||
The BRISK constructor
|
||||
|
||||
.. ocv:function:: BRISK::BRISK(int thresh=30, int octaves=3, float patternScale=1.0f)
|
||||
|
||||
.. ocv:pyfunction:: cv2.BRISK([, thresh[, octaves[, patternScale]]]) -> <BRISK object>
|
||||
|
||||
:param thresh: FAST/AGAST detection threshold score.
|
||||
|
||||
:param octaves: detection octaves. Use 0 to do single scale.
|
||||
|
||||
:param patternScale: apply this scale to the pattern used for sampling the neighbourhood of a keypoint.
|
||||
|
||||
BRISK::BRISK
|
||||
------------
|
||||
The BRISK constructor for a custom pattern
|
||||
|
||||
.. ocv:function:: BRISK::BRISK(std::vector<float> &radiusList, std::vector<int> &numberList, float dMax=5.85f, float dMin=8.2f, std::vector<int> indexChange=std::vector<int>())
|
||||
|
||||
.. ocv:pyfunction:: cv2.BRISK(radiusList, numberList[, dMax[, dMin[, indexChange]]]) -> <BRISK object>
|
||||
|
||||
:param radiusList: defines the radii (in pixels) where the samples around a keypoint are taken (for keypoint scale 1).
|
||||
|
||||
:param numberList: defines the number of sampling points on the sampling circle. Must be the same size as radiusList..
|
||||
|
||||
:param dMax: threshold for the short pairings used for descriptor formation (in pixels for keypoint scale 1).
|
||||
|
||||
:param dMin: threshold for the long pairings used for orientation determination (in pixels for keypoint scale 1).
|
||||
|
||||
:param indexChanges: index remapping of the bits.
|
||||
|
||||
BRISK::operator()
|
||||
-----------------
|
||||
Finds keypoints in an image and computes their descriptors
|
||||
|
||||
.. ocv:function:: void BRISK::operator()(InputArray image, InputArray mask, vector<KeyPoint>& keypoints, OutputArray descriptors, bool useProvidedKeypoints=false ) const
|
||||
|
||||
.. ocv:pyfunction:: cv2.BRISK.detect(image[, mask]) -> keypoints
|
||||
.. ocv:pyfunction:: cv2.BRISK.compute(image, keypoints[, descriptors]) -> keypoints, descriptors
|
||||
.. ocv:pyfunction:: cv2.BRISK.detectAndCompute(image, mask[, descriptors[, useProvidedKeypoints]]) -> keypoints, descriptors
|
||||
|
||||
:param image: The input 8-bit grayscale image.
|
||||
|
||||
:param mask: The operation mask.
|
||||
|
||||
:param keypoints: The output vector of keypoints.
|
||||
|
||||
:param descriptors: The output descriptors. Pass ``cv::noArray()`` if you do not need it.
|
||||
|
||||
:param useProvidedKeypoints: If it is true, then the method will use the provided vector of keypoints instead of detecting them.
|
||||
|
||||
FREAK
|
||||
-----
|
||||
.. ocv:class:: FREAK : public DescriptorExtractor
|
||||
|
||||
Class implementing the FREAK (*Fast Retina Keypoint*) keypoint descriptor, described in [AOV12]_. The algorithm propose a novel keypoint descriptor inspired by the human visual system and more precisely the retina, coined Fast Retina Key- point (FREAK). A cascade of binary strings is computed by efficiently comparing image intensities over a retinal sampling pattern. FREAKs are in general faster to compute with lower memory load and also more robust than SIFT, SURF or BRISK. They are competitive alternatives to existing keypoints in particular for embedded applications.
|
||||
|
||||
.. [AOV12] A. Alahi, R. Ortiz, and P. Vandergheynst. FREAK: Fast Retina Keypoint. In IEEE Conference on Computer Vision and Pattern Recognition, 2012. CVPR 2012 Open Source Award Winner.
|
||||
|
||||
.. note::
|
||||
|
||||
* An example on how to use the FREAK descriptor can be found at opencv_source_code/samples/cpp/freak_demo.cpp
|
||||
|
||||
FREAK::FREAK
|
||||
------------
|
||||
The FREAK constructor
|
||||
|
||||
.. ocv:function:: FREAK::FREAK( bool orientationNormalized=true, bool scaleNormalized=true, float patternScale=22.0f, int nOctaves=4, const vector<int>& selectedPairs=vector<int>() )
|
||||
|
||||
:param orientationNormalized: Enable orientation normalization.
|
||||
:param scaleNormalized: Enable scale normalization.
|
||||
:param patternScale: Scaling of the description pattern.
|
||||
:param nOctaves: Number of octaves covered by the detected keypoints.
|
||||
:param selectedPairs: (Optional) user defined selected pairs indexes,
|
||||
|
||||
FREAK::selectPairs
|
||||
------------------
|
||||
Select the 512 best description pair indexes from an input (grayscale) image set. FREAK is available with a set of pairs learned off-line. Researchers can run a training process to learn their own set of pair. For more details read section 4.2 in: A. Alahi, R. Ortiz, and P. Vandergheynst. FREAK: Fast Retina Keypoint. In IEEE Conference on Computer Vision and Pattern Recognition, 2012.
|
||||
|
||||
We notice that for keypoint matching applications, image content has little effect on the selected pairs unless very specific what does matter is the detector type (blobs, corners,...) and the options used (scale/rotation invariance,...). Reduce corrThresh if not enough pairs are selected (43 points --> 903 possible pairs)
|
||||
|
||||
.. ocv:function:: vector<int> FREAK::selectPairs(const vector<Mat>& images, vector<vector<KeyPoint> >& keypoints, const double corrThresh = 0.7, bool verbose = true)
|
||||
|
||||
:param images: Grayscale image input set.
|
||||
:param keypoints: Set of detected keypoints
|
||||
:param corrThresh: Correlation threshold.
|
||||
:param verbose: Prints pair selection informations.
|
||||
|
||||
KAZE
|
||||
----
|
||||
.. ocv:class:: KAZE : public Feature2D
|
||||
|
||||
Class implementing the KAZE keypoint detector and descriptor extractor, described in [ABD12]_. ::
|
||||
|
||||
class CV_EXPORTS_W KAZE : public Feature2D
|
||||
{
|
||||
public:
|
||||
CV_WRAP KAZE();
|
||||
CV_WRAP explicit KAZE(bool extended, bool upright, float threshold = 0.001f,
|
||||
int octaves = 4, int sublevels = 4, int diffusivity = DIFF_PM_G2);
|
||||
};
|
||||
|
||||
.. note:: AKAZE descriptor can only be used with KAZE or AKAZE keypoints
|
||||
|
||||
.. [ABD12] KAZE Features. Pablo F. Alcantarilla, Adrien Bartoli and Andrew J. Davison. In European Conference on Computer Vision (ECCV), Fiorenze, Italy, October 2012.
|
||||
|
||||
KAZE::KAZE
|
||||
----------
|
||||
The KAZE constructor
|
||||
|
||||
.. ocv:function:: KAZE::KAZE(bool extended, bool upright, float threshold, int octaves, int sublevels, int diffusivity)
|
||||
|
||||
:param extended: Set to enable extraction of extended (128-byte) descriptor.
|
||||
:param upright: Set to enable use of upright descriptors (non rotation-invariant).
|
||||
:param threshold: Detector response threshold to accept point
|
||||
:param octaves: Maximum octave evolution of the image
|
||||
:param sublevels: Default number of sublevels per scale level
|
||||
:param diffusivity: Diffusivity type. DIFF_PM_G1, DIFF_PM_G2, DIFF_WEICKERT or DIFF_CHARBONNIER
|
||||
|
||||
AKAZE
|
||||
-----
|
||||
.. ocv:class:: AKAZE : public Feature2D
|
||||
|
||||
Class implementing the AKAZE keypoint detector and descriptor extractor, described in [ANB13]_. ::
|
||||
|
||||
class CV_EXPORTS_W AKAZE : public Feature2D
|
||||
{
|
||||
public:
|
||||
CV_WRAP AKAZE();
|
||||
CV_WRAP explicit AKAZE(int descriptor_type, int descriptor_size = 0, int descriptor_channels = 3,
|
||||
float threshold = 0.001f, int octaves = 4, int sublevels = 4, int diffusivity = DIFF_PM_G2);
|
||||
};
|
||||
|
||||
.. note:: AKAZE descriptor can only be used with KAZE or AKAZE keypoints
|
||||
|
||||
.. [ANB13] Fast Explicit Diffusion for Accelerated Features in Nonlinear Scale Spaces. Pablo F. Alcantarilla, Jesús Nuevo and Adrien Bartoli. In British Machine Vision Conference (BMVC), Bristol, UK, September 2013.
|
||||
|
||||
AKAZE::AKAZE
|
||||
------------
|
||||
The AKAZE constructor
|
||||
|
||||
.. ocv:function:: AKAZE::AKAZE(int descriptor_type, int descriptor_size, int descriptor_channels, float threshold, int octaves, int sublevels, int diffusivity)
|
||||
|
||||
:param descriptor_type: Type of the extracted descriptor: DESCRIPTOR_KAZE, DESCRIPTOR_KAZE_UPRIGHT, DESCRIPTOR_MLDB or DESCRIPTOR_MLDB_UPRIGHT.
|
||||
:param descriptor_size: Size of the descriptor in bits. 0 -> Full size
|
||||
:param descriptor_channels: Number of channels in the descriptor (1, 2, 3)
|
||||
:param threshold: Detector response threshold to accept point
|
||||
:param octaves: Maximum octave evolution of the image
|
||||
:param sublevels: Default number of sublevels per scale level
|
||||
:param diffusivity: Diffusivity type. DIFF_PM_G1, DIFF_PM_G2, DIFF_WEICKERT or DIFF_CHARBONNIER
|
||||
@@ -1,16 +0,0 @@
|
||||
*********************************
|
||||
features2d. 2D Features Framework
|
||||
*********************************
|
||||
|
||||
.. highlight:: cpp
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
feature_detection_and_description
|
||||
common_interfaces_of_feature_detectors
|
||||
common_interfaces_of_descriptor_extractors
|
||||
common_interfaces_of_descriptor_matchers
|
||||
common_interfaces_of_generic_descriptor_matchers
|
||||
drawing_function_of_keypoints_and_matches
|
||||
object_categorization
|
||||
@@ -1,213 +0,0 @@
|
||||
Object Categorization
|
||||
=====================
|
||||
|
||||
.. highlight:: cpp
|
||||
|
||||
This section describes approaches based on local 2D features and used to categorize objects.
|
||||
|
||||
.. note::
|
||||
|
||||
* A complete Bag-Of-Words sample can be found at opencv_source_code/samples/cpp/bagofwords_classification.cpp
|
||||
|
||||
* (Python) An example using the features2D framework to perform object categorization can be found at opencv_source_code/samples/python2/find_obj.py
|
||||
|
||||
BOWTrainer
|
||||
----------
|
||||
.. ocv:class:: BOWTrainer
|
||||
|
||||
Abstract base class for training the *bag of visual words* vocabulary from a set of descriptors.
|
||||
For details, see, for example, *Visual Categorization with Bags of Keypoints* by Gabriella Csurka, Christopher R. Dance,
|
||||
Lixin Fan, Jutta Willamowski, Cedric Bray, 2004. ::
|
||||
|
||||
class BOWTrainer
|
||||
{
|
||||
public:
|
||||
BOWTrainer(){}
|
||||
virtual ~BOWTrainer(){}
|
||||
|
||||
void add( const Mat& descriptors );
|
||||
const vector<Mat>& getDescriptors() const;
|
||||
int descriptorsCount() const;
|
||||
|
||||
virtual void clear();
|
||||
|
||||
virtual Mat cluster() const = 0;
|
||||
virtual Mat cluster( const Mat& descriptors ) const = 0;
|
||||
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
BOWTrainer::add
|
||||
-------------------
|
||||
Adds descriptors to a training set.
|
||||
|
||||
.. ocv:function:: void BOWTrainer::add( const Mat& descriptors )
|
||||
|
||||
:param descriptors: Descriptors to add to a training set. Each row of the ``descriptors`` matrix is a descriptor.
|
||||
|
||||
The training set is clustered using ``clustermethod`` to construct the vocabulary.
|
||||
|
||||
BOWTrainer::getDescriptors
|
||||
------------------------------
|
||||
Returns a training set of descriptors.
|
||||
|
||||
.. ocv:function:: const vector<Mat>& BOWTrainer::getDescriptors() const
|
||||
|
||||
|
||||
|
||||
BOWTrainer::descriptorsCount
|
||||
---------------------------------
|
||||
Returns the count of all descriptors stored in the training set.
|
||||
|
||||
.. ocv:function:: int BOWTrainer::descriptorsCount() const
|
||||
|
||||
|
||||
|
||||
BOWTrainer::cluster
|
||||
-----------------------
|
||||
Clusters train descriptors.
|
||||
|
||||
.. ocv:function:: Mat BOWTrainer::cluster() const
|
||||
|
||||
.. ocv:function:: Mat BOWTrainer::cluster( const Mat& descriptors ) const
|
||||
|
||||
:param descriptors: Descriptors to cluster. Each row of the ``descriptors`` matrix is a descriptor. Descriptors are not added to the inner train descriptor set.
|
||||
|
||||
The vocabulary consists of cluster centers. So, this method returns the vocabulary. In the first variant of the method, train descriptors stored in the object are clustered. In the second variant, input descriptors are clustered.
|
||||
|
||||
BOWKMeansTrainer
|
||||
----------------
|
||||
.. ocv:class:: BOWKMeansTrainer : public BOWTrainer
|
||||
|
||||
:ocv:func:`kmeans` -based class to train visual vocabulary using the *bag of visual words* approach.
|
||||
::
|
||||
|
||||
class BOWKMeansTrainer : public BOWTrainer
|
||||
{
|
||||
public:
|
||||
BOWKMeansTrainer( int clusterCount, const TermCriteria& termcrit=TermCriteria(),
|
||||
int attempts=3, int flags=KMEANS_PP_CENTERS );
|
||||
virtual ~BOWKMeansTrainer(){}
|
||||
|
||||
// Returns trained vocabulary (i.e. cluster centers).
|
||||
virtual Mat cluster() const;
|
||||
virtual Mat cluster( const Mat& descriptors ) const;
|
||||
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
BOWKMeansTrainer::BOWKMeansTrainer
|
||||
----------------------------------
|
||||
|
||||
The constructor.
|
||||
|
||||
.. ocv:function:: BOWKMeansTrainer::BOWKMeansTrainer( int clusterCount, const TermCriteria& termcrit=TermCriteria(), int attempts=3, int flags=KMEANS_PP_CENTERS )
|
||||
|
||||
See :ocv:func:`kmeans` function parameters.
|
||||
|
||||
BOWImgDescriptorExtractor
|
||||
-------------------------
|
||||
.. ocv:class:: BOWImgDescriptorExtractor
|
||||
|
||||
Class to compute an image descriptor using the *bag of visual words*. Such a computation consists of the following steps:
|
||||
|
||||
#. Compute descriptors for a given image and its keypoints set.
|
||||
#. Find the nearest visual words from the vocabulary for each keypoint descriptor.
|
||||
#. Compute the bag-of-words image descriptor as is a normalized histogram of vocabulary words encountered in the image. The ``i``-th bin of the histogram is a frequency of ``i``-th word of the vocabulary in the given image.
|
||||
|
||||
The class declaration is the following: ::
|
||||
|
||||
class BOWImgDescriptorExtractor
|
||||
{
|
||||
public:
|
||||
BOWImgDescriptorExtractor( const Ptr<DescriptorExtractor>& dextractor,
|
||||
const Ptr<DescriptorMatcher>& dmatcher );
|
||||
BOWImgDescriptorExtractor( const Ptr<DescriptorMatcher>& dmatcher );
|
||||
virtual ~BOWImgDescriptorExtractor(){}
|
||||
|
||||
void setVocabulary( const Mat& vocabulary );
|
||||
const Mat& getVocabulary() const;
|
||||
void compute( InputArray image, vector<KeyPoint>& keypoints,
|
||||
OutputArray imgDescriptor,
|
||||
vector<vector<int> >* pointIdxsOfClusters=0,
|
||||
Mat* descriptors=0 );
|
||||
void compute( InputArray descriptors, OutputArray imgDescriptor,
|
||||
std::vector<std::vector<int> >* pointIdxsOfClusters=0 );
|
||||
int descriptorSize() const;
|
||||
int descriptorType() const;
|
||||
|
||||
protected:
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
BOWImgDescriptorExtractor::BOWImgDescriptorExtractor
|
||||
--------------------------------------------------------
|
||||
The constructor.
|
||||
|
||||
.. ocv:function:: BOWImgDescriptorExtractor::BOWImgDescriptorExtractor( const Ptr<DescriptorExtractor>& dextractor, const Ptr<DescriptorMatcher>& dmatcher )
|
||||
.. ocv:function:: BOWImgDescriptorExtractor::BOWImgDescriptorExtractor( const Ptr<DescriptorMatcher>& dmatcher )
|
||||
|
||||
:param dextractor: Descriptor extractor that is used to compute descriptors for an input image and its keypoints.
|
||||
|
||||
:param dmatcher: Descriptor matcher that is used to find the nearest word of the trained vocabulary for each keypoint descriptor of the image.
|
||||
|
||||
|
||||
|
||||
BOWImgDescriptorExtractor::setVocabulary
|
||||
--------------------------------------------
|
||||
Sets a visual vocabulary.
|
||||
|
||||
.. ocv:function:: void BOWImgDescriptorExtractor::setVocabulary( const Mat& vocabulary )
|
||||
|
||||
:param vocabulary: Vocabulary (can be trained using the inheritor of :ocv:class:`BOWTrainer` ). Each row of the vocabulary is a visual word (cluster center).
|
||||
|
||||
|
||||
|
||||
BOWImgDescriptorExtractor::getVocabulary
|
||||
--------------------------------------------
|
||||
Returns the set vocabulary.
|
||||
|
||||
.. ocv:function:: const Mat& BOWImgDescriptorExtractor::getVocabulary() const
|
||||
|
||||
|
||||
|
||||
BOWImgDescriptorExtractor::compute
|
||||
--------------------------------------
|
||||
Computes an image descriptor using the set visual vocabulary.
|
||||
|
||||
.. ocv:function:: void BOWImgDescriptorExtractor::compute( InputArray image, vector<KeyPoint>& keypoints, OutputArray imgDescriptor, vector<vector<int> >* pointIdxsOfClusters=0, Mat* descriptors=0 )
|
||||
.. ocv:function:: void BOWImgDescriptorExtractor::compute( InputArray keypointDescriptors, OutputArray imgDescriptor, std::vector<std::vector<int> >* pointIdxsOfClusters=0 )
|
||||
|
||||
:param image: Image, for which the descriptor is computed.
|
||||
|
||||
:param keypoints: Keypoints detected in the input image.
|
||||
|
||||
:param keypointDescriptors: Computed descriptors to match with vocabulary.
|
||||
|
||||
:param imgDescriptor: Computed output image descriptor.
|
||||
|
||||
:param pointIdxsOfClusters: Indices of keypoints that belong to the cluster. This means that ``pointIdxsOfClusters[i]`` are keypoint indices that belong to the ``i`` -th cluster (word of vocabulary) returned if it is non-zero.
|
||||
|
||||
:param descriptors: Descriptors of the image keypoints that are returned if they are non-zero.
|
||||
|
||||
|
||||
|
||||
BOWImgDescriptorExtractor::descriptorSize
|
||||
---------------------------------------------
|
||||
Returns an image descriptor size if the vocabulary is set. Otherwise, it returns 0.
|
||||
|
||||
.. ocv:function:: int BOWImgDescriptorExtractor::descriptorSize() const
|
||||
|
||||
|
||||
|
||||
BOWImgDescriptorExtractor::descriptorType
|
||||
---------------------------------------------
|
||||
|
||||
Returns an image descriptor type.
|
||||
|
||||
.. ocv:function:: int BOWImgDescriptorExtractor::descriptorType() const
|
||||
@@ -0,0 +1,284 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use autodie; # die if problem reading or writing a file
|
||||
|
||||
my $filein = "./agast.txt";
|
||||
my $fileout = "./agast_new.txt";
|
||||
my $i1=1;
|
||||
my $i2=1;
|
||||
my $i3=1;
|
||||
my $tmp;
|
||||
my $ifcount0=0;
|
||||
my $ifcount1=0;
|
||||
my $ifcount2=0;
|
||||
my $ifcount3=0;
|
||||
my $ifcount4=0;
|
||||
my $elsecount;
|
||||
my $myfirstline = $ARGV[0];
|
||||
my $mylastline = $ARGV[1];
|
||||
my $tablename = $ARGV[2];
|
||||
my @array0 = ();
|
||||
my @array1 = ();
|
||||
my @array2 = ();
|
||||
my @array3 = ();
|
||||
my $homogeneous;
|
||||
my $success_homogeneous;
|
||||
my $structured;
|
||||
my $success_structured;
|
||||
|
||||
open(my $in1, "<", $filein) or die "Can't open $filein: $!";
|
||||
open(my $out, ">", $fileout) or die "Can't open $fileout: $!";
|
||||
|
||||
|
||||
$array0[0] = 0;
|
||||
$i1=1;
|
||||
while (my $line1 = <$in1>)
|
||||
{
|
||||
chomp $line1;
|
||||
$array0[$i1] = 0;
|
||||
if (($i1>=$myfirstline)&&($i1<=$mylastline))
|
||||
{
|
||||
if($line1=~/if\(ptr\[offset(\d+)/)
|
||||
{
|
||||
if($line1=~/if\(ptr\[offset(\d+).*\>.*cb/)
|
||||
{
|
||||
$tmp=$1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($line1=~/if\(ptr\[offset(\d+).*\<.*c\_b/)
|
||||
{
|
||||
$tmp=$1+128;
|
||||
}
|
||||
else
|
||||
{
|
||||
die "invalid array index!"
|
||||
}
|
||||
}
|
||||
$array1[$ifcount1] = $tmp;
|
||||
$array0[$ifcount1] = $i1;
|
||||
$ifcount1++;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
$i1++;
|
||||
}
|
||||
$homogeneous=$ifcount1;
|
||||
$success_homogeneous=$ifcount1+1;
|
||||
$structured=$ifcount1+2;
|
||||
$success_structured=$ifcount1+3;
|
||||
|
||||
close $in1 or die "Can't close $filein: $!";
|
||||
|
||||
open($in1, "<", $filein) or die "Can't open $filein: $!";
|
||||
|
||||
|
||||
$i1=1;
|
||||
while (my $line1 = <$in1>)
|
||||
{
|
||||
chomp $line1;
|
||||
if (($i1>=$myfirstline)&&($i1<=$mylastline))
|
||||
{
|
||||
if ($array0[$ifcount2] == $i1)
|
||||
{
|
||||
$array2[$ifcount2]=0;
|
||||
$array3[$ifcount2]=0;
|
||||
if ($array0[$ifcount2+1] == ($i1+1))
|
||||
{
|
||||
$array2[$ifcount2]=($ifcount2+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
open(my $in2, "<", $filein) or die "Can't open $filein: $!";
|
||||
$i2=1;
|
||||
while (my $line2 = <$in2>)
|
||||
{
|
||||
chomp $line2;
|
||||
if ($i2 == $i1)
|
||||
{
|
||||
last;
|
||||
}
|
||||
$i2++;
|
||||
}
|
||||
my $line2 = <$in2>;
|
||||
chomp $line2;
|
||||
if ($line2=~/goto (\w+)/)
|
||||
{
|
||||
$tmp=$1;
|
||||
if ($tmp eq "homogeneous")
|
||||
{
|
||||
$array2[$ifcount2]=$homogeneous;
|
||||
}
|
||||
if ($tmp eq "success_homogeneous")
|
||||
{
|
||||
$array2[$ifcount2]=$success_homogeneous;
|
||||
}
|
||||
if ($tmp eq "structured")
|
||||
{
|
||||
$array2[$ifcount2]=$structured;
|
||||
}
|
||||
if ($tmp eq "success_structured")
|
||||
{
|
||||
$array2[$ifcount2]=$success_structured;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
die "goto expected: $!";
|
||||
}
|
||||
close $in2 or die "Can't close $filein: $!";
|
||||
}
|
||||
#find next else and interpret it
|
||||
open(my $in3, "<", $filein) or die "Can't open $filein: $!";
|
||||
$i3=1;
|
||||
$ifcount3=0;
|
||||
$elsecount=0;
|
||||
while (my $line3 = <$in3>)
|
||||
{
|
||||
chomp $line3;
|
||||
$i3++;
|
||||
if ($i3 == $i1)
|
||||
{
|
||||
last;
|
||||
}
|
||||
}
|
||||
while (my $line3 = <$in3>)
|
||||
{
|
||||
chomp $line3;
|
||||
$ifcount3++;
|
||||
if (($elsecount==0)&&($i3>$i1))
|
||||
{
|
||||
if ($line3=~/goto (\w+)/)
|
||||
{
|
||||
$tmp=$1;
|
||||
if ($tmp eq "homogeneous")
|
||||
{
|
||||
$array3[$ifcount2]=$homogeneous;
|
||||
}
|
||||
if ($tmp eq "success_homogeneous")
|
||||
{
|
||||
$array3[$ifcount2]=$success_homogeneous;
|
||||
}
|
||||
if ($tmp eq "structured")
|
||||
{
|
||||
$array3[$ifcount2]=$structured;
|
||||
}
|
||||
if ($tmp eq "success_structured")
|
||||
{
|
||||
$array3[$ifcount2]=$success_structured;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($line3=~/if\(ptr\[offset/)
|
||||
{
|
||||
$ifcount4=0;
|
||||
while ($array0[$ifcount4]!=$i3)
|
||||
{
|
||||
$ifcount4++;
|
||||
if ($ifcount4==$ifcount1)
|
||||
{
|
||||
die "if else match expected: $!";
|
||||
}
|
||||
$array3[$ifcount2]=$ifcount4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
die "elseif or elsegoto match expected: $!";
|
||||
}
|
||||
}
|
||||
last;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($line3=~/if\(ptr\[offset/)
|
||||
{
|
||||
$elsecount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($line3=~/else/)
|
||||
{
|
||||
$elsecount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
$i3++;
|
||||
}
|
||||
printf("%3d [%3d][0x%08x]\n", $array0[$ifcount2], $ifcount2, (($array1[$ifcount2]&15)<<28)|($array2[$ifcount2]<<16)|(($array1[$ifcount2]&128)<<5)|($array3[$ifcount2]));
|
||||
close $in3 or die "Can't close $filein: $!";
|
||||
$ifcount2++;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
$i1++;
|
||||
}
|
||||
|
||||
printf(" [%3d][0x%08x]\n", $homogeneous, 252);
|
||||
printf(" [%3d][0x%08x]\n", $success_homogeneous, 253);
|
||||
printf(" [%3d][0x%08x]\n", $structured, 254);
|
||||
printf(" [%3d][0x%08x]\n", $success_structured, 255);
|
||||
|
||||
close $in1 or die "Can't close $filein: $!";
|
||||
|
||||
$ifcount0=0;
|
||||
$ifcount2=0;
|
||||
printf $out " static const unsigned long %s[] = {\n ", $tablename;
|
||||
while ($ifcount0 < $ifcount1)
|
||||
{
|
||||
printf $out "0x%08x, ", (($array1[$ifcount0]&15)<<28)|($array2[$ifcount0]<<16)|(($array1[$ifcount0]&128)<<5)|($array3[$ifcount0]);
|
||||
|
||||
$ifcount0++;
|
||||
$ifcount2++;
|
||||
if ($ifcount2==8)
|
||||
{
|
||||
$ifcount2=0;
|
||||
printf $out "\n";
|
||||
printf $out " ";
|
||||
}
|
||||
|
||||
}
|
||||
printf $out "0x%08x, ", 252;
|
||||
$ifcount0++;
|
||||
$ifcount2++;
|
||||
if ($ifcount2==8)
|
||||
{
|
||||
$ifcount2=0;
|
||||
printf $out "\n";
|
||||
printf $out " ";
|
||||
}
|
||||
printf $out "0x%08x, ", 253;
|
||||
$ifcount0++;
|
||||
$ifcount2++;
|
||||
if ($ifcount2==8)
|
||||
{
|
||||
$ifcount2=0;
|
||||
printf $out "\n";
|
||||
printf $out " ";
|
||||
}
|
||||
printf $out "0x%08x, ", 254;
|
||||
$ifcount0++;
|
||||
$ifcount2++;
|
||||
if ($ifcount2==8)
|
||||
{
|
||||
$ifcount2=0;
|
||||
printf $out "\n";
|
||||
printf $out " ";
|
||||
}
|
||||
printf $out "0x%08x\n", 255;
|
||||
$ifcount0++;
|
||||
$ifcount2++;
|
||||
printf $out " };\n\n";
|
||||
|
||||
$#array0 = -1;
|
||||
$#array1 = -1;
|
||||
$#array2 = -1;
|
||||
$#array3 = -1;
|
||||
|
||||
close $out or die "Can't close $fileout: $!";
|
||||
@@ -0,0 +1,244 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use autodie; # die if problem reading or writing a file
|
||||
|
||||
my $filein = "./agast_score.txt";
|
||||
my $fileout = "./agast_new.txt";
|
||||
my $i1=1;
|
||||
my $i2=1;
|
||||
my $i3=1;
|
||||
my $tmp;
|
||||
my $ifcount0=0;
|
||||
my $ifcount1=0;
|
||||
my $ifcount2=0;
|
||||
my $ifcount3=0;
|
||||
my $ifcount4=0;
|
||||
my $elsecount;
|
||||
my $myfirstline = $ARGV[0];
|
||||
my $mylastline = $ARGV[1];
|
||||
my $tablename = $ARGV[2];
|
||||
my @array0 = ();
|
||||
my @array1 = ();
|
||||
my @array2 = ();
|
||||
my @array3 = ();
|
||||
my $is_not_a_corner;
|
||||
my $is_a_corner;
|
||||
|
||||
open(my $in1, "<", $filein) or die "Can't open $filein: $!";
|
||||
open(my $out, ">", $fileout) or die "Can't open $fileout: $!";
|
||||
|
||||
|
||||
$array0[0] = 0;
|
||||
$i1=1;
|
||||
while (my $line1 = <$in1>)
|
||||
{
|
||||
chomp $line1;
|
||||
$array0[$i1] = 0;
|
||||
if (($i1>=$myfirstline)&&($i1<=$mylastline))
|
||||
{
|
||||
if($line1=~/if\(ptr\[offset(\d+)/)
|
||||
{
|
||||
if($line1=~/if\(ptr\[offset(\d+).*\>.*cb/)
|
||||
{
|
||||
$tmp=$1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($line1=~/if\(ptr\[offset(\d+).*\<.*c\_b/)
|
||||
{
|
||||
$tmp=$1+128;
|
||||
}
|
||||
else
|
||||
{
|
||||
die "invalid array index!"
|
||||
}
|
||||
}
|
||||
$array1[$ifcount1] = $tmp;
|
||||
$array0[$ifcount1] = $i1;
|
||||
$ifcount1++;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
$i1++;
|
||||
}
|
||||
$is_not_a_corner=$ifcount1;
|
||||
$is_a_corner=$ifcount1+1;
|
||||
|
||||
close $in1 or die "Can't close $filein: $!";
|
||||
|
||||
open($in1, "<", $filein) or die "Can't open $filein: $!";
|
||||
|
||||
|
||||
$i1=1;
|
||||
while (my $line1 = <$in1>)
|
||||
{
|
||||
chomp $line1;
|
||||
if (($i1>=$myfirstline)&&($i1<=$mylastline))
|
||||
{
|
||||
if ($array0[$ifcount2] == $i1)
|
||||
{
|
||||
$array2[$ifcount2]=0;
|
||||
$array3[$ifcount2]=0;
|
||||
if ($array0[$ifcount2+1] == ($i1+1))
|
||||
{
|
||||
$array2[$ifcount2]=($ifcount2+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
open(my $in2, "<", $filein) or die "Can't open $filein: $!";
|
||||
$i2=1;
|
||||
while (my $line2 = <$in2>)
|
||||
{
|
||||
chomp $line2;
|
||||
if ($i2 == $i1)
|
||||
{
|
||||
last;
|
||||
}
|
||||
$i2++;
|
||||
}
|
||||
my $line2 = <$in2>;
|
||||
chomp $line2;
|
||||
if ($line2=~/goto (\w+)/)
|
||||
{
|
||||
$tmp=$1;
|
||||
if ($tmp eq "is_not_a_corner")
|
||||
{
|
||||
$array2[$ifcount2]=$is_not_a_corner;
|
||||
}
|
||||
if ($tmp eq "is_a_corner")
|
||||
{
|
||||
$array2[$ifcount2]=$is_a_corner;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
die "goto expected: $!";
|
||||
}
|
||||
close $in2 or die "Can't close $filein: $!";
|
||||
}
|
||||
#find next else and interpret it
|
||||
open(my $in3, "<", $filein) or die "Can't open $filein: $!";
|
||||
$i3=1;
|
||||
$ifcount3=0;
|
||||
$elsecount=0;
|
||||
while (my $line3 = <$in3>)
|
||||
{
|
||||
chomp $line3;
|
||||
$i3++;
|
||||
if ($i3 == $i1)
|
||||
{
|
||||
last;
|
||||
}
|
||||
}
|
||||
while (my $line3 = <$in3>)
|
||||
{
|
||||
chomp $line3;
|
||||
$ifcount3++;
|
||||
if (($elsecount==0)&&($i3>$i1))
|
||||
{
|
||||
if ($line3=~/goto (\w+)/)
|
||||
{
|
||||
$tmp=$1;
|
||||
if ($tmp eq "is_not_a_corner")
|
||||
{
|
||||
$array3[$ifcount2]=$is_not_a_corner;
|
||||
}
|
||||
if ($tmp eq "is_a_corner")
|
||||
{
|
||||
$array3[$ifcount2]=$is_a_corner;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($line3=~/if\(ptr\[offset/)
|
||||
{
|
||||
$ifcount4=0;
|
||||
while ($array0[$ifcount4]!=$i3)
|
||||
{
|
||||
$ifcount4++;
|
||||
if ($ifcount4==$ifcount1)
|
||||
{
|
||||
die "if else match expected: $!";
|
||||
}
|
||||
$array3[$ifcount2]=$ifcount4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
die "elseif or elsegoto match expected: $!";
|
||||
}
|
||||
}
|
||||
last;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($line3=~/if\(ptr\[offset/)
|
||||
{
|
||||
$elsecount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($line3=~/else/)
|
||||
{
|
||||
$elsecount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
$i3++;
|
||||
}
|
||||
printf("%3d [%3d][0x%08x]\n", $array0[$ifcount2], $ifcount2, (($array1[$ifcount2]&15)<<28)|($array2[$ifcount2]<<16)|(($array1[$ifcount2]&128)<<5)|($array3[$ifcount2]));
|
||||
close $in3 or die "Can't close $filein: $!";
|
||||
$ifcount2++;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
$i1++;
|
||||
}
|
||||
|
||||
printf(" [%3d][0x%08x]\n", $is_not_a_corner, 254);
|
||||
printf(" [%3d][0x%08x]\n", $is_a_corner, 255);
|
||||
|
||||
close $in1 or die "Can't close $filein: $!";
|
||||
|
||||
$ifcount0=0;
|
||||
$ifcount2=0;
|
||||
printf $out " static const unsigned long %s[] = {\n ", $tablename;
|
||||
while ($ifcount0 < $ifcount1)
|
||||
{
|
||||
printf $out "0x%08x, ", (($array1[$ifcount0]&15)<<28)|($array2[$ifcount0]<<16)|(($array1[$ifcount0]&128)<<5)|($array3[$ifcount0]);
|
||||
|
||||
$ifcount0++;
|
||||
$ifcount2++;
|
||||
if ($ifcount2==8)
|
||||
{
|
||||
$ifcount2=0;
|
||||
printf $out "\n";
|
||||
printf $out " ";
|
||||
}
|
||||
|
||||
}
|
||||
printf $out "0x%08x, ", 254;
|
||||
$ifcount0++;
|
||||
$ifcount2++;
|
||||
if ($ifcount2==8)
|
||||
{
|
||||
$ifcount2=0;
|
||||
printf $out "\n";
|
||||
printf $out " ";
|
||||
}
|
||||
printf $out "0x%08x\n", 255;
|
||||
$ifcount0++;
|
||||
$ifcount2++;
|
||||
printf $out " };\n\n";
|
||||
|
||||
$#array0 = -1;
|
||||
$#array1 = -1;
|
||||
$#array2 = -1;
|
||||
$#array3 = -1;
|
||||
|
||||
close $out or die "Can't close $fileout: $!";
|
||||
@@ -0,0 +1,32 @@
|
||||
perl read_file_score32.pl 9059 9385 table_5_8_corner_struct
|
||||
move agast_new.txt agast_score_table.txt
|
||||
perl read_file_score32.pl 2215 3387 table_7_12d_corner_struct
|
||||
copy /A agast_score_table.txt + agast_new.txt agast_score_table.txt
|
||||
del agast_new.txt
|
||||
perl read_file_score32.pl 3428 9022 table_7_12s_corner_struct
|
||||
copy /A agast_score_table.txt + agast_new.txt agast_score_table.txt
|
||||
del agast_new.txt
|
||||
perl read_file_score32.pl 118 2174 table_9_16_corner_struct
|
||||
copy /A agast_score_table.txt + agast_new.txt agast_score_table.txt
|
||||
del agast_new.txt
|
||||
|
||||
perl read_file_nondiff32.pl 103 430 table_5_8_struct1
|
||||
move agast_new.txt agast_table.txt
|
||||
perl read_file_nondiff32.pl 440 779 table_5_8_struct2
|
||||
copy /A agast_table.txt + agast_new.txt agast_table.txt
|
||||
del agast_new.txt
|
||||
perl read_file_nondiff32.pl 869 2042 table_7_12d_struct1
|
||||
copy /A agast_table.txt + agast_new.txt agast_table.txt
|
||||
del agast_new.txt
|
||||
perl read_file_nondiff32.pl 2052 3225 table_7_12d_struct2
|
||||
copy /A agast_table.txt + agast_new.txt agast_table.txt
|
||||
del agast_new.txt
|
||||
perl read_file_nondiff32.pl 3315 4344 table_7_12s_struct1
|
||||
copy /A agast_table.txt + agast_new.txt agast_table.txt
|
||||
del agast_new.txt
|
||||
perl read_file_nondiff32.pl 4354 5308 table_7_12s_struct2
|
||||
copy /A agast_table.txt + agast_new.txt agast_table.txt
|
||||
del agast_new.txt
|
||||
perl read_file_nondiff32.pl 5400 7454 table_9_16_struct
|
||||
copy /A agast_table.txt + agast_new.txt agast_table.txt
|
||||
del agast_new.txt
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
#ifndef OPENCV_FEATURE2D_HAL_INTERFACE_H
|
||||
#define OPENCV_FEATURE2D_HAL_INTERFACE_H
|
||||
|
||||
#include "opencv2/core/cvdef.h"
|
||||
//! @addtogroup features2d_hal_interface
|
||||
//! @{
|
||||
|
||||
//! @name Fast feature detector types
|
||||
//! @sa cv::FastFeatureDetector
|
||||
//! @{
|
||||
#define CV_HAL_TYPE_5_8 0
|
||||
#define CV_HAL_TYPE_7_12 1
|
||||
#define CV_HAL_TYPE_9_16 2
|
||||
//! @}
|
||||
|
||||
//! @name Key point
|
||||
//! @sa cv::KeyPoint
|
||||
//! @{
|
||||
struct CV_EXPORTS cvhalKeyPoint
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float size;
|
||||
float angle;
|
||||
float response;
|
||||
int octave;
|
||||
int class_id;
|
||||
};
|
||||
//! @}
|
||||
|
||||
//! @}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
misc/java/src/cpp/features2d_manual.hpp
|
||||
include/opencv2/features2d.hpp
|
||||
@@ -0,0 +1 @@
|
||||
misc/java/src/cpp/features2d_converters.hpp
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"const_private_list" : [
|
||||
"OPPONENTEXTRACTOR",
|
||||
"GRIDDETECTOR",
|
||||
"PYRAMIDDETECTOR",
|
||||
"DYNAMICDETECTOR"
|
||||
],
|
||||
"type_dict" : {
|
||||
"Feature2D": {
|
||||
"j_type": "Feature2D",
|
||||
"jn_type": "long",
|
||||
"jni_type": "jlong",
|
||||
"jni_var": "Feature2D %(n)s",
|
||||
"suffix": "J",
|
||||
"j_import": "org.opencv.features2d.Feature2D"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
#define LOG_TAG "org.opencv.utils.Converters"
|
||||
#include "common.h"
|
||||
#include "features2d_converters.hpp"
|
||||
|
||||
using namespace cv;
|
||||
|
||||
#define CHECK_MAT(cond) if(!(cond)){ LOGD("FAILED: " #cond); return; }
|
||||
|
||||
|
||||
//vector_KeyPoint
|
||||
void Mat_to_vector_KeyPoint(Mat& mat, std::vector<KeyPoint>& v_kp)
|
||||
{
|
||||
v_kp.clear();
|
||||
CHECK_MAT(mat.type()==CV_32FC(7) && mat.cols==1);
|
||||
for(int i=0; i<mat.rows; i++)
|
||||
{
|
||||
Vec<float, 7> v = mat.at< Vec<float, 7> >(i, 0);
|
||||
KeyPoint kp(v[0], v[1], v[2], v[3], v[4], (int)v[5], (int)v[6]);
|
||||
v_kp.push_back(kp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void vector_KeyPoint_to_Mat(std::vector<KeyPoint>& v_kp, Mat& mat)
|
||||
{
|
||||
int count = (int)v_kp.size();
|
||||
mat.create(count, 1, CV_32FC(7));
|
||||
for(int i=0; i<count; i++)
|
||||
{
|
||||
KeyPoint kp = v_kp[i];
|
||||
mat.at< Vec<float, 7> >(i, 0) = Vec<float, 7>(kp.pt.x, kp.pt.y, kp.size, kp.angle, kp.response, (float)kp.octave, (float)kp.class_id);
|
||||
}
|
||||
}
|
||||
|
||||
//vector_DMatch
|
||||
void Mat_to_vector_DMatch(Mat& mat, std::vector<DMatch>& v_dm)
|
||||
{
|
||||
v_dm.clear();
|
||||
CHECK_MAT(mat.type()==CV_32FC4 && mat.cols==1);
|
||||
for(int i=0; i<mat.rows; i++)
|
||||
{
|
||||
Vec<float, 4> v = mat.at< Vec<float, 4> >(i, 0);
|
||||
DMatch dm((int)v[0], (int)v[1], (int)v[2], v[3]);
|
||||
v_dm.push_back(dm);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void vector_DMatch_to_Mat(std::vector<DMatch>& v_dm, Mat& mat)
|
||||
{
|
||||
int count = (int)v_dm.size();
|
||||
mat.create(count, 1, CV_32FC4);
|
||||
for(int i=0; i<count; i++)
|
||||
{
|
||||
DMatch dm = v_dm[i];
|
||||
mat.at< Vec<float, 4> >(i, 0) = Vec<float, 4>((float)dm.queryIdx, (float)dm.trainIdx, (float)dm.imgIdx, dm.distance);
|
||||
}
|
||||
}
|
||||
|
||||
void Mat_to_vector_vector_KeyPoint(Mat& mat, std::vector< std::vector< KeyPoint > >& vv_kp)
|
||||
{
|
||||
std::vector<Mat> vm;
|
||||
vm.reserve( mat.rows );
|
||||
Mat_to_vector_Mat(mat, vm);
|
||||
for(size_t i=0; i<vm.size(); i++)
|
||||
{
|
||||
std::vector<KeyPoint> vkp;
|
||||
Mat_to_vector_KeyPoint(vm[i], vkp);
|
||||
vv_kp.push_back(vkp);
|
||||
}
|
||||
}
|
||||
|
||||
void vector_vector_KeyPoint_to_Mat(std::vector< std::vector< KeyPoint > >& vv_kp, Mat& mat)
|
||||
{
|
||||
std::vector<Mat> vm;
|
||||
vm.reserve( vv_kp.size() );
|
||||
for(size_t i=0; i<vv_kp.size(); i++)
|
||||
{
|
||||
Mat m;
|
||||
vector_KeyPoint_to_Mat(vv_kp[i], m);
|
||||
vm.push_back(m);
|
||||
}
|
||||
vector_Mat_to_Mat(vm, mat);
|
||||
}
|
||||
|
||||
void Mat_to_vector_vector_DMatch(Mat& mat, std::vector< std::vector< DMatch > >& vv_dm)
|
||||
{
|
||||
std::vector<Mat> vm;
|
||||
vm.reserve( mat.rows );
|
||||
Mat_to_vector_Mat(mat, vm);
|
||||
for(size_t i=0; i<vm.size(); i++)
|
||||
{
|
||||
std::vector<DMatch> vdm;
|
||||
Mat_to_vector_DMatch(vm[i], vdm);
|
||||
vv_dm.push_back(vdm);
|
||||
}
|
||||
}
|
||||
|
||||
void vector_vector_DMatch_to_Mat(std::vector< std::vector< DMatch > >& vv_dm, Mat& mat)
|
||||
{
|
||||
std::vector<Mat> vm;
|
||||
vm.reserve( vv_dm.size() );
|
||||
for(size_t i=0; i<vv_dm.size(); i++)
|
||||
{
|
||||
Mat m;
|
||||
vector_DMatch_to_Mat(vv_dm[i], m);
|
||||
vm.push_back(m);
|
||||
}
|
||||
vector_Mat_to_Mat(vm, mat);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef __FEATURES2D_CONVERTERS_HPP__
|
||||
#define __FEATURES2D_CONVERTERS_HPP__
|
||||
|
||||
#include "opencv2/opencv_modules.hpp"
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/features2d.hpp"
|
||||
|
||||
void Mat_to_vector_KeyPoint(cv::Mat& mat, std::vector<cv::KeyPoint>& v_kp);
|
||||
void vector_KeyPoint_to_Mat(std::vector<cv::KeyPoint>& v_kp, cv::Mat& mat);
|
||||
|
||||
void Mat_to_vector_DMatch(cv::Mat& mat, std::vector<cv::DMatch>& v_dm);
|
||||
void vector_DMatch_to_Mat(std::vector<cv::DMatch>& v_dm, cv::Mat& mat);
|
||||
|
||||
void Mat_to_vector_vector_KeyPoint(cv::Mat& mat, std::vector< std::vector< cv::KeyPoint > >& vv_kp);
|
||||
void vector_vector_KeyPoint_to_Mat(std::vector< std::vector< cv::KeyPoint > >& vv_kp, cv::Mat& mat);
|
||||
|
||||
void Mat_to_vector_vector_DMatch(cv::Mat& mat, std::vector< std::vector< cv::DMatch > >& vv_dm);
|
||||
void vector_vector_DMatch_to_Mat(std::vector< std::vector< cv::DMatch > >& vv_dm, cv::Mat& mat);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,320 @@
|
||||
#ifndef __OPENCV_FEATURES_2D_MANUAL_HPP__
|
||||
#define __OPENCV_FEATURES_2D_MANUAL_HPP__
|
||||
|
||||
#include "opencv2/opencv_modules.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCV_FEATURES2D
|
||||
#include "opencv2/features2d.hpp"
|
||||
#include "features2d_converters.hpp"
|
||||
|
||||
#undef SIMPLEBLOB // to solve conflict with wincrypt.h on windows
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/**
|
||||
* @deprecated Please use direct instantiation of Feature2D classes
|
||||
*/
|
||||
class CV_EXPORTS_AS(FeatureDetector) javaFeatureDetector
|
||||
{
|
||||
public:
|
||||
CV_WRAP void detect( const Mat& image, CV_OUT std::vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const
|
||||
{ return wrapped->detect(image, keypoints, mask); }
|
||||
|
||||
CV_WRAP void detect( const std::vector<Mat>& images, CV_OUT std::vector<std::vector<KeyPoint> >& keypoints, const std::vector<Mat>& masks=std::vector<Mat>() ) const
|
||||
{ return wrapped->detect(images, keypoints, masks); }
|
||||
|
||||
CV_WRAP bool empty() const
|
||||
{ return wrapped->empty(); }
|
||||
|
||||
enum
|
||||
{
|
||||
FAST = 1,
|
||||
STAR = 2,
|
||||
SIFT = 3,
|
||||
SURF = 4,
|
||||
ORB = 5,
|
||||
MSER = 6,
|
||||
GFTT = 7,
|
||||
HARRIS = 8,
|
||||
SIMPLEBLOB = 9,
|
||||
DENSE = 10,
|
||||
BRISK = 11,
|
||||
AKAZE = 12,
|
||||
|
||||
|
||||
GRIDDETECTOR = 1000,
|
||||
|
||||
GRID_FAST = GRIDDETECTOR + FAST,
|
||||
GRID_STAR = GRIDDETECTOR + STAR,
|
||||
GRID_SIFT = GRIDDETECTOR + SIFT,
|
||||
GRID_SURF = GRIDDETECTOR + SURF,
|
||||
GRID_ORB = GRIDDETECTOR + ORB,
|
||||
GRID_MSER = GRIDDETECTOR + MSER,
|
||||
GRID_GFTT = GRIDDETECTOR + GFTT,
|
||||
GRID_HARRIS = GRIDDETECTOR + HARRIS,
|
||||
GRID_SIMPLEBLOB = GRIDDETECTOR + SIMPLEBLOB,
|
||||
GRID_DENSE = GRIDDETECTOR + DENSE,
|
||||
GRID_BRISK = GRIDDETECTOR + BRISK,
|
||||
GRID_AKAZE = GRIDDETECTOR + AKAZE,
|
||||
|
||||
|
||||
PYRAMIDDETECTOR = 2000,
|
||||
|
||||
PYRAMID_FAST = PYRAMIDDETECTOR + FAST,
|
||||
PYRAMID_STAR = PYRAMIDDETECTOR + STAR,
|
||||
PYRAMID_SIFT = PYRAMIDDETECTOR + SIFT,
|
||||
PYRAMID_SURF = PYRAMIDDETECTOR + SURF,
|
||||
PYRAMID_ORB = PYRAMIDDETECTOR + ORB,
|
||||
PYRAMID_MSER = PYRAMIDDETECTOR + MSER,
|
||||
PYRAMID_GFTT = PYRAMIDDETECTOR + GFTT,
|
||||
PYRAMID_HARRIS = PYRAMIDDETECTOR + HARRIS,
|
||||
PYRAMID_SIMPLEBLOB = PYRAMIDDETECTOR + SIMPLEBLOB,
|
||||
PYRAMID_DENSE = PYRAMIDDETECTOR + DENSE,
|
||||
PYRAMID_BRISK = PYRAMIDDETECTOR + BRISK,
|
||||
PYRAMID_AKAZE = PYRAMIDDETECTOR + AKAZE,
|
||||
|
||||
DYNAMICDETECTOR = 3000,
|
||||
|
||||
DYNAMIC_FAST = DYNAMICDETECTOR + FAST,
|
||||
DYNAMIC_STAR = DYNAMICDETECTOR + STAR,
|
||||
DYNAMIC_SIFT = DYNAMICDETECTOR + SIFT,
|
||||
DYNAMIC_SURF = DYNAMICDETECTOR + SURF,
|
||||
DYNAMIC_ORB = DYNAMICDETECTOR + ORB,
|
||||
DYNAMIC_MSER = DYNAMICDETECTOR + MSER,
|
||||
DYNAMIC_GFTT = DYNAMICDETECTOR + GFTT,
|
||||
DYNAMIC_HARRIS = DYNAMICDETECTOR + HARRIS,
|
||||
DYNAMIC_SIMPLEBLOB = DYNAMICDETECTOR + SIMPLEBLOB,
|
||||
DYNAMIC_DENSE = DYNAMICDETECTOR + DENSE,
|
||||
DYNAMIC_BRISK = DYNAMICDETECTOR + BRISK,
|
||||
DYNAMIC_AKAZE = DYNAMICDETECTOR + AKAZE
|
||||
};
|
||||
|
||||
/**
|
||||
* supported: FAST STAR SIFT SURF ORB MSER GFTT HARRIS BRISK AKAZE Grid(XXXX) Pyramid(XXXX) Dynamic(XXXX)
|
||||
* not supported: SimpleBlob, Dense
|
||||
* @deprecated
|
||||
*/
|
||||
CV_WRAP static Ptr<javaFeatureDetector> create( int detectorType )
|
||||
{
|
||||
//String name;
|
||||
if (detectorType > DYNAMICDETECTOR)
|
||||
{
|
||||
//name = "Dynamic";
|
||||
detectorType -= DYNAMICDETECTOR;
|
||||
}
|
||||
if (detectorType > PYRAMIDDETECTOR)
|
||||
{
|
||||
//name = "Pyramid";
|
||||
detectorType -= PYRAMIDDETECTOR;
|
||||
}
|
||||
if (detectorType > GRIDDETECTOR)
|
||||
{
|
||||
//name = "Grid";
|
||||
detectorType -= GRIDDETECTOR;
|
||||
}
|
||||
|
||||
Ptr<FeatureDetector> fd;
|
||||
switch(detectorType)
|
||||
{
|
||||
case FAST:
|
||||
fd = FastFeatureDetector::create();
|
||||
break;
|
||||
//case STAR:
|
||||
// fd = xfeatures2d::StarDetector::create();
|
||||
// break;
|
||||
//case SIFT:
|
||||
// name = name + "SIFT";
|
||||
// break;
|
||||
//case SURF:
|
||||
// name = name + "SURF";
|
||||
// break;
|
||||
case ORB:
|
||||
fd = ORB::create();
|
||||
break;
|
||||
case MSER:
|
||||
fd = MSER::create();
|
||||
break;
|
||||
case GFTT:
|
||||
fd = GFTTDetector::create();
|
||||
break;
|
||||
case HARRIS:
|
||||
{
|
||||
Ptr<GFTTDetector> gftt = GFTTDetector::create();
|
||||
gftt->setHarrisDetector(true);
|
||||
fd = gftt;
|
||||
}
|
||||
break;
|
||||
case SIMPLEBLOB:
|
||||
fd = SimpleBlobDetector::create();
|
||||
break;
|
||||
//case DENSE:
|
||||
// name = name + "Dense";
|
||||
// break;
|
||||
case BRISK:
|
||||
fd = BRISK::create();
|
||||
break;
|
||||
case AKAZE:
|
||||
fd = AKAZE::create();
|
||||
break;
|
||||
default:
|
||||
CV_Error( Error::StsBadArg, "Specified feature detector type is not supported." );
|
||||
break;
|
||||
}
|
||||
|
||||
return makePtr<javaFeatureDetector>(fd);
|
||||
}
|
||||
|
||||
CV_WRAP void write( const String& fileName ) const
|
||||
{
|
||||
FileStorage fs(fileName, FileStorage::WRITE);
|
||||
wrapped->write(fs);
|
||||
}
|
||||
|
||||
CV_WRAP void read( const String& fileName )
|
||||
{
|
||||
FileStorage fs(fileName, FileStorage::READ);
|
||||
wrapped->read(fs.root());
|
||||
}
|
||||
|
||||
javaFeatureDetector(Ptr<FeatureDetector> _wrapped) : wrapped(_wrapped)
|
||||
{}
|
||||
|
||||
private:
|
||||
|
||||
Ptr<FeatureDetector> wrapped;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
class CV_EXPORTS_AS(DescriptorExtractor) javaDescriptorExtractor
|
||||
{
|
||||
public:
|
||||
CV_WRAP void compute( const Mat& image, CV_IN_OUT std::vector<KeyPoint>& keypoints, Mat& descriptors ) const
|
||||
{ return wrapped->compute(image, keypoints, descriptors); }
|
||||
|
||||
CV_WRAP void compute( const std::vector<Mat>& images, CV_IN_OUT std::vector<std::vector<KeyPoint> >& keypoints, CV_OUT std::vector<Mat>& descriptors ) const
|
||||
{ return wrapped->compute(images, keypoints, descriptors); }
|
||||
|
||||
CV_WRAP int descriptorSize() const
|
||||
{ return wrapped->descriptorSize(); }
|
||||
|
||||
CV_WRAP int descriptorType() const
|
||||
{ return wrapped->descriptorType(); }
|
||||
|
||||
CV_WRAP bool empty() const
|
||||
{ return wrapped->empty(); }
|
||||
|
||||
enum
|
||||
{
|
||||
SIFT = 1,
|
||||
SURF = 2,
|
||||
ORB = 3,
|
||||
BRIEF = 4,
|
||||
BRISK = 5,
|
||||
FREAK = 6,
|
||||
AKAZE = 7,
|
||||
|
||||
|
||||
OPPONENTEXTRACTOR = 1000,
|
||||
|
||||
|
||||
|
||||
OPPONENT_SIFT = OPPONENTEXTRACTOR + SIFT,
|
||||
OPPONENT_SURF = OPPONENTEXTRACTOR + SURF,
|
||||
OPPONENT_ORB = OPPONENTEXTRACTOR + ORB,
|
||||
OPPONENT_BRIEF = OPPONENTEXTRACTOR + BRIEF,
|
||||
OPPONENT_BRISK = OPPONENTEXTRACTOR + BRISK,
|
||||
OPPONENT_FREAK = OPPONENTEXTRACTOR + FREAK,
|
||||
OPPONENT_AKAZE = OPPONENTEXTRACTOR + AKAZE
|
||||
};
|
||||
|
||||
//supported SIFT, SURF, ORB, BRIEF, BRISK, FREAK, AKAZE, Opponent(XXXX)
|
||||
//not supported: Calonder
|
||||
CV_WRAP static Ptr<javaDescriptorExtractor> create( int extractorType )
|
||||
{
|
||||
//String name;
|
||||
|
||||
if (extractorType > OPPONENTEXTRACTOR)
|
||||
{
|
||||
//name = "Opponent";
|
||||
extractorType -= OPPONENTEXTRACTOR;
|
||||
}
|
||||
|
||||
Ptr<DescriptorExtractor> de;
|
||||
switch(extractorType)
|
||||
{
|
||||
//case SIFT:
|
||||
// name = name + "SIFT";
|
||||
// break;
|
||||
//case SURF:
|
||||
// name = name + "SURF";
|
||||
// break;
|
||||
case ORB:
|
||||
de = ORB::create();
|
||||
break;
|
||||
//case BRIEF:
|
||||
// name = name + "BRIEF";
|
||||
// break;
|
||||
case BRISK:
|
||||
de = BRISK::create();
|
||||
break;
|
||||
//case FREAK:
|
||||
// name = name + "FREAK";
|
||||
// break;
|
||||
case AKAZE:
|
||||
de = AKAZE::create();
|
||||
break;
|
||||
default:
|
||||
CV_Error( Error::StsBadArg, "Specified descriptor extractor type is not supported." );
|
||||
break;
|
||||
}
|
||||
|
||||
return makePtr<javaDescriptorExtractor>(de);
|
||||
}
|
||||
|
||||
CV_WRAP void write( const String& fileName ) const
|
||||
{
|
||||
FileStorage fs(fileName, FileStorage::WRITE);
|
||||
wrapped->write(fs);
|
||||
}
|
||||
|
||||
CV_WRAP void read( const String& fileName )
|
||||
{
|
||||
FileStorage fs(fileName, FileStorage::READ);
|
||||
wrapped->read(fs.root());
|
||||
}
|
||||
|
||||
javaDescriptorExtractor(Ptr<DescriptorExtractor> _wrapped) : wrapped(_wrapped)
|
||||
{}
|
||||
|
||||
private:
|
||||
|
||||
Ptr<DescriptorExtractor> wrapped;
|
||||
};
|
||||
|
||||
#ifdef OPENCV_BINDINGS_PARSER
|
||||
//DO NOT REMOVE! The block is required for sources parser
|
||||
enum
|
||||
{
|
||||
DRAW_OVER_OUTIMG = 1, // Output image matrix will not be created (Mat::create).
|
||||
// Matches will be drawn on existing content of output image.
|
||||
NOT_DRAW_SINGLE_POINTS = 2, // Single keypoints will not be drawn.
|
||||
DRAW_RICH_KEYPOINTS = 4 // For each keypoint the circle around keypoint with keypoint size and
|
||||
// orientation will be drawn.
|
||||
};
|
||||
|
||||
CV_EXPORTS_AS(drawMatches2) void drawMatches( const Mat& img1, const std::vector<KeyPoint>& keypoints1,
|
||||
const Mat& img2, const std::vector<KeyPoint>& keypoints2,
|
||||
const std::vector<std::vector<DMatch> >& matches1to2, Mat& outImg,
|
||||
const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1),
|
||||
const std::vector<std::vector<char> >& matchesMask=std::vector<std::vector<char> >(), int flags=0);
|
||||
|
||||
#endif
|
||||
|
||||
} //cv
|
||||
|
||||
#endif // HAVE_OPENCV_FEATURES2D
|
||||
|
||||
#endif // __OPENCV_FEATURES_2D_MANUAL_HPP__
|
||||
@@ -0,0 +1,102 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class BRIEFDescriptorExtractorTest extends OpenCVTestCase {
|
||||
|
||||
Feature2D extractor;
|
||||
int matSize;
|
||||
|
||||
private Mat getTestImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(20, matSize / 2), new Point(matSize - 21, matSize / 2), new Scalar(100), 2);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 20), new Point(matSize / 2, matSize - 21), new Scalar(100), 2);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
extractor = createClassInstance(XFEATURES2D+"BriefDescriptorExtractor", DEFAULT_FACTORY, null, null);
|
||||
matSize = 100;
|
||||
}
|
||||
|
||||
public void testComputeListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testComputeMatListOfKeyPointMat() {
|
||||
KeyPoint point = new KeyPoint(55.775577545166016f, 44.224422454833984f, 16, 9.754629f, 8617.863f, 1, -1);
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint(point);
|
||||
Mat img = getTestImg();
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
Mat truth = new Mat(1, 32, CvType.CV_8UC1) {
|
||||
{
|
||||
put(0, 0, 96, 0, 76, 24, 47, 182, 68, 137,
|
||||
149, 195, 67, 16, 187, 224, 74, 8,
|
||||
82, 169, 87, 70, 44, 4, 192, 56,
|
||||
13, 128, 44, 106, 146, 72, 194, 245);
|
||||
}
|
||||
};
|
||||
|
||||
assertMatEqual(truth, descriptors);
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(extractor);
|
||||
}
|
||||
|
||||
public void testDescriptorSize() {
|
||||
assertEquals(32, extractor.descriptorSize());
|
||||
}
|
||||
|
||||
public void testDescriptorType() {
|
||||
assertEquals(CvType.CV_8U, extractor.descriptorType());
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
// assertFalse(extractor.empty());
|
||||
fail("Not yet implemented"); // BRIEF does not override empty() method
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(filename, "%YAML:1.0\n---\ndescriptorSize: 64\n");
|
||||
|
||||
extractor.read(filename);
|
||||
|
||||
assertEquals(64, extractor.descriptorSize());
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("xml");
|
||||
|
||||
extractor.write(filename);
|
||||
|
||||
String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<descriptorSize>32</descriptorSize>\n</opencv_storage>\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
public void testWriteYml() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
extractor.write(filename);
|
||||
|
||||
String truth = "%YAML:1.0\n---\ndescriptorSize: 32\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfDMatch;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.DMatch;
|
||||
import org.opencv.features2d.DescriptorMatcher;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class BruteForceDescriptorMatcherTest extends OpenCVTestCase {
|
||||
|
||||
DescriptorMatcher matcher;
|
||||
int matSize;
|
||||
DMatch[] truth;
|
||||
|
||||
private Mat getMaskImg() {
|
||||
return new Mat(5, 2, CvType.CV_8U, new Scalar(0)) {
|
||||
{
|
||||
put(0, 0, 1, 1, 1, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Mat getQueryDescriptors() {
|
||||
Mat img = getQueryImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
Feature2D detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
|
||||
setProperty(detector, "hessianThreshold", "double", 8000);
|
||||
setProperty(detector, "nOctaves", "int", 3);
|
||||
setProperty(detector, "nOctaveLayers", "int", 4);
|
||||
setProperty(detector, "upright", "boolean", false);
|
||||
|
||||
detector.detect(img, keypoints);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private Mat getQueryImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(30, matSize / 2), new Point(matSize - 31, matSize / 2), new Scalar(100), 3);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 30), new Point(matSize / 2, matSize - 31), new Scalar(100), 3);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
private Mat getTrainDescriptors() {
|
||||
Mat img = getTrainImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint(new KeyPoint(50, 50, 16, 0, 20000, 1, -1), new KeyPoint(42, 42, 16, 160, 10000, 1, -1));
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private Mat getTrainImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(20, matSize / 2), new Point(matSize - 21, matSize / 2), new Scalar(100), 2);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 20), new Point(matSize / 2, matSize - 21), new Scalar(100), 2);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE);
|
||||
matSize = 100;
|
||||
|
||||
truth = new DMatch[] {
|
||||
new DMatch(0, 0, 0, 0.6159003f),
|
||||
new DMatch(1, 1, 0, 0.9177120f),
|
||||
new DMatch(2, 1, 0, 0.3112163f),
|
||||
new DMatch(3, 1, 0, 0.2925074f),
|
||||
new DMatch(4, 1, 0, 0.26520672f)
|
||||
};
|
||||
}
|
||||
|
||||
public void testAdd() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
assertFalse(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClear() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
matcher.clear();
|
||||
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClone() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
Mat truth = train.clone();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
DescriptorMatcher cloned = matcher.clone();
|
||||
|
||||
assertNotNull(cloned);
|
||||
|
||||
List<Mat> descriptors = cloned.getTrainDescriptors();
|
||||
assertEquals(1, descriptors.size());
|
||||
assertMatEqual(truth, descriptors.get(0));
|
||||
}
|
||||
|
||||
public void testCloneBoolean() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
DescriptorMatcher cloned = matcher.clone(true);
|
||||
|
||||
assertNotNull(cloned);
|
||||
assertTrue(cloned.empty());
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(matcher);
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testGetTrainDescriptors() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
Mat truth = train.clone();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
List<Mat> descriptors = matcher.getTrainDescriptors();
|
||||
|
||||
assertEquals(1, descriptors.size());
|
||||
assertMatEqual(truth, descriptors.get(0));
|
||||
}
|
||||
|
||||
public void testIsMaskSupported() {
|
||||
assertTrue(matcher.isMaskSupported());
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchInt() {
|
||||
final int k = 3;
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
List<MatOfDMatch> matches = new ArrayList<MatOfDMatch>();
|
||||
matcher.knnMatch(query, train, matches, k);
|
||||
/*
|
||||
Log.d("knnMatch", "train = " + train);
|
||||
Log.d("knnMatch", "query = " + query);
|
||||
|
||||
matcher.add(train);
|
||||
matcher.knnMatch(query, matches, k);
|
||||
*/
|
||||
assertEquals(query.rows(), matches.size());
|
||||
for(int i = 0; i<matches.size(); i++)
|
||||
{
|
||||
MatOfDMatch vdm = matches.get(i);
|
||||
//Log.d("knn", "vdm["+i+"]="+vdm.dump());
|
||||
assertTrue(Math.min(k, train.rows()) >= vdm.total());
|
||||
for(DMatch dm : vdm.toArray())
|
||||
{
|
||||
assertEquals(dm.queryIdx, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
matcher.match(query, matches);
|
||||
|
||||
assertArrayDMatchEquals(truth, matches.toArray(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatchListOfMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
matcher.match(query, matches, Arrays.asList(mask));
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth[0], truth[1]), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches);
|
||||
|
||||
assertArrayDMatchEquals(truth, matches.toArray(), EPS);
|
||||
|
||||
// OpenCVTestRunner.Log("matches found: " + matches.size());
|
||||
// for (DMatch m : matches)
|
||||
// OpenCVTestRunner.Log(m.toString());
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatchMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches, mask);
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth[0], truth[1]), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(filename, "%YAML:1.0\n---\n");
|
||||
|
||||
matcher.read(filename);
|
||||
assertTrue(true);// BruteforceMatcher has no settings
|
||||
}
|
||||
|
||||
public void testTrain() {
|
||||
matcher.train();// BruteforceMatcher does not need to train
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
matcher.write(filename);
|
||||
|
||||
String truth = "%YAML:1.0\n---\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfDMatch;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.DMatch;
|
||||
import org.opencv.features2d.DescriptorMatcher;
|
||||
import org.opencv.features2d.FeatureDetector;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class BruteForceHammingDescriptorMatcherTest extends OpenCVTestCase {
|
||||
|
||||
DescriptorMatcher matcher;
|
||||
int matSize;
|
||||
DMatch[] truth;
|
||||
|
||||
private Mat getMaskImg() {
|
||||
return new Mat(4, 4, CvType.CV_8U, new Scalar(0)) {
|
||||
{
|
||||
put(0, 0, 1, 1, 1, 1, 1, 1, 1, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Mat getQueryDescriptors() {
|
||||
return getTestDescriptors(getQueryImg());
|
||||
}
|
||||
|
||||
private Mat getQueryImg() {
|
||||
Mat img = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(img, new Point(40, matSize - 40), new Point(matSize - 50, 50), new Scalar(0), 8);
|
||||
return img;
|
||||
}
|
||||
|
||||
private Mat getTestDescriptors(Mat img) {
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
FeatureDetector detector = FeatureDetector.create(FeatureDetector.FAST);
|
||||
Feature2D extractor = createClassInstance(XFEATURES2D+"BriefDescriptorExtractor", DEFAULT_FACTORY, null, null);
|
||||
|
||||
detector.detect(img, keypoints);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private Mat getTrainDescriptors() {
|
||||
return getTestDescriptors(getTrainImg());
|
||||
}
|
||||
|
||||
private Mat getTrainImg() {
|
||||
Mat img = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(img, new Point(40, 40), new Point(matSize - 40, matSize - 40), new Scalar(0), 8);
|
||||
return img;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
|
||||
matSize = 100;
|
||||
|
||||
truth = new DMatch[] {
|
||||
new DMatch(0, 0, 0, 51),
|
||||
new DMatch(1, 2, 0, 42),
|
||||
new DMatch(2, 1, 0, 40),
|
||||
new DMatch(3, 3, 0, 53) };
|
||||
}
|
||||
|
||||
public void testAdd() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
assertFalse(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClear() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
matcher.clear();
|
||||
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClone() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
Mat truth = train.clone();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
DescriptorMatcher cloned = matcher.clone();
|
||||
|
||||
assertNotNull(cloned);
|
||||
|
||||
List<Mat> descriptors = cloned.getTrainDescriptors();
|
||||
assertEquals(1, descriptors.size());
|
||||
assertMatEqual(truth, descriptors.get(0));
|
||||
}
|
||||
|
||||
public void testCloneBoolean() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
DescriptorMatcher cloned = matcher.clone(true);
|
||||
|
||||
assertNotNull(cloned);
|
||||
assertTrue(cloned.empty());
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(matcher);
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testGetTrainDescriptors() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
Mat truth = train.clone();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
List<Mat> descriptors = matcher.getTrainDescriptors();
|
||||
|
||||
assertEquals(1, descriptors.size());
|
||||
assertMatEqual(truth, descriptors.get(0));
|
||||
}
|
||||
|
||||
public void testIsMaskSupported() {
|
||||
assertTrue(matcher.isMaskSupported());
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
matcher.match(query, matches);
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatchListOfMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
matcher.match(query, matches, Arrays.asList(mask));
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth[0], truth[1]), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches);
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatchMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches, mask);
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth[0], truth[1]), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
ArrayList<MatOfDMatch> matches = new ArrayList<MatOfDMatch>();
|
||||
|
||||
matcher.radiusMatch(query, train, matches, 50.f);
|
||||
|
||||
assertEquals(4, matches.size());
|
||||
assertTrue(matches.get(0).empty());
|
||||
assertMatEqual(matches.get(1), new MatOfDMatch(truth[1]), EPS);
|
||||
assertMatEqual(matches.get(2), new MatOfDMatch(truth[2]), EPS);
|
||||
assertTrue(matches.get(3).empty());
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(filename, "%YAML:1.0\n---\n");
|
||||
|
||||
matcher.read(filename);
|
||||
assertTrue(true);// BruteforceMatcher has no settings
|
||||
}
|
||||
|
||||
public void testTrain() {
|
||||
matcher.train();// BruteforceMatcher does not need to train
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
matcher.write(filename);
|
||||
|
||||
String truth = "%YAML:1.0\n---\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfDMatch;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.DMatch;
|
||||
import org.opencv.features2d.DescriptorMatcher;
|
||||
import org.opencv.features2d.FeatureDetector;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class BruteForceHammingLUTDescriptorMatcherTest extends OpenCVTestCase {
|
||||
|
||||
DescriptorMatcher matcher;
|
||||
int matSize;
|
||||
DMatch[] truth;
|
||||
|
||||
private Mat getMaskImg() {
|
||||
return new Mat(4, 4, CvType.CV_8U, new Scalar(0)) {
|
||||
{
|
||||
put(0, 0, 1, 1, 1, 1, 1, 1, 1, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Mat getQueryDescriptors() {
|
||||
return getTestDescriptors(getQueryImg());
|
||||
}
|
||||
|
||||
private Mat getQueryImg() {
|
||||
Mat img = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(img, new Point(40, matSize - 40), new Point(matSize - 50, 50), new Scalar(0), 8);
|
||||
return img;
|
||||
}
|
||||
|
||||
private Mat getTestDescriptors(Mat img) {
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
FeatureDetector detector = FeatureDetector.create(FeatureDetector.FAST);
|
||||
Feature2D extractor = createClassInstance(XFEATURES2D+"BriefDescriptorExtractor", DEFAULT_FACTORY, null, null);
|
||||
|
||||
detector.detect(img, keypoints);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private Mat getTrainDescriptors() {
|
||||
return getTestDescriptors(getTrainImg());
|
||||
}
|
||||
|
||||
private Mat getTrainImg() {
|
||||
Mat img = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(img, new Point(40, 40), new Point(matSize - 40, matSize - 40), new Scalar(0), 8);
|
||||
return img;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMINGLUT);
|
||||
matSize = 100;
|
||||
|
||||
truth = new DMatch[] {
|
||||
new DMatch(0, 0, 0, 51),
|
||||
new DMatch(1, 2, 0, 42),
|
||||
new DMatch(2, 1, 0, 40),
|
||||
new DMatch(3, 3, 0, 53) };
|
||||
}
|
||||
|
||||
public void testAdd() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
assertFalse(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClear() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
matcher.clear();
|
||||
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClone() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
Mat truth = train.clone();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
DescriptorMatcher cloned = matcher.clone();
|
||||
|
||||
assertNotNull(cloned);
|
||||
|
||||
List<Mat> descriptors = cloned.getTrainDescriptors();
|
||||
assertEquals(1, descriptors.size());
|
||||
assertMatEqual(truth, descriptors.get(0));
|
||||
}
|
||||
|
||||
public void testCloneBoolean() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
DescriptorMatcher cloned = matcher.clone(true);
|
||||
|
||||
assertNotNull(cloned);
|
||||
assertTrue(cloned.empty());
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(matcher);
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testGetTrainDescriptors() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
Mat truth = train.clone();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
List<Mat> descriptors = matcher.getTrainDescriptors();
|
||||
|
||||
assertEquals(1, descriptors.size());
|
||||
assertMatEqual(truth, descriptors.get(0));
|
||||
}
|
||||
|
||||
public void testIsMaskSupported() {
|
||||
assertTrue(matcher.isMaskSupported());
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
matcher.match(query, matches);
|
||||
|
||||
assertArrayDMatchEquals(truth, matches.toArray(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatchListOfMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
matcher.match(query, matches, Arrays.asList(mask));
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth[0], truth[1]), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches);
|
||||
|
||||
/*
|
||||
OpenCVTestRunner.Log("matches found: " + matches.size());
|
||||
for (DMatch m : matches.toArray())
|
||||
OpenCVTestRunner.Log(m.toString());
|
||||
*/
|
||||
|
||||
assertArrayDMatchEquals(truth, matches.toArray(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatchMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches, mask);
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth[0], truth[1]), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(filename, "%YAML:1.0\n---\n");
|
||||
|
||||
matcher.read(filename);
|
||||
assertTrue(true);// BruteforceMatcher has no settings
|
||||
}
|
||||
|
||||
public void testTrain() {
|
||||
matcher.train();// BruteforceMatcher does not need to train
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
matcher.write(filename);
|
||||
|
||||
String truth = "%YAML:1.0\n---\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfDMatch;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.DMatch;
|
||||
import org.opencv.features2d.DescriptorMatcher;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class BruteForceL1DescriptorMatcherTest extends OpenCVTestCase {
|
||||
|
||||
DescriptorMatcher matcher;
|
||||
int matSize;
|
||||
DMatch[] truth;
|
||||
|
||||
private Mat getMaskImg() {
|
||||
return new Mat(5, 2, CvType.CV_8U, new Scalar(0)) {
|
||||
{
|
||||
put(0, 0, 1, 1, 1, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Mat getQueryDescriptors() {
|
||||
Mat img = getQueryImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
Feature2D detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
|
||||
setProperty(detector, "extended", "boolean", true);
|
||||
setProperty(detector, "hessianThreshold", "double", 8000);
|
||||
setProperty(detector, "nOctaveLayers", "int", 2);
|
||||
setProperty(detector, "nOctaves", "int", 3);
|
||||
setProperty(detector, "upright", "boolean", false);
|
||||
|
||||
detector.detect(img, keypoints);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private Mat getQueryImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(30, matSize / 2), new Point(matSize - 31, matSize / 2), new Scalar(100), 3);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 30), new Point(matSize / 2, matSize - 31), new Scalar(100), 3);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
private Mat getTrainDescriptors() {
|
||||
Mat img = getTrainImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint(new KeyPoint(50, 50, 16, 0, 20000, 1, -1), new KeyPoint(42, 42, 16, 160, 10000, 1, -1));
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private Mat getTrainImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(20, matSize / 2), new Point(matSize - 21, matSize / 2), new Scalar(100), 2);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 20), new Point(matSize / 2, matSize - 21), new Scalar(100), 2);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_L1);
|
||||
matSize = 100;
|
||||
|
||||
truth = new DMatch[] {
|
||||
new DMatch(0, 0, 0, 3.0710702f),
|
||||
new DMatch(1, 1, 0, 3.562016f),
|
||||
new DMatch(2, 1, 0, 1.3682679f),
|
||||
new DMatch(3, 1, 0, 1.3012862f),
|
||||
new DMatch(4, 1, 0, 1.1852086f)
|
||||
};
|
||||
}
|
||||
|
||||
public void testAdd() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
assertFalse(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClear() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
matcher.clear();
|
||||
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClone() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
Mat truth = train.clone();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
DescriptorMatcher cloned = matcher.clone();
|
||||
|
||||
assertNotNull(cloned);
|
||||
|
||||
List<Mat> descriptors = cloned.getTrainDescriptors();
|
||||
assertEquals(1, descriptors.size());
|
||||
assertMatEqual(truth, descriptors.get(0));
|
||||
}
|
||||
|
||||
public void testCloneBoolean() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
DescriptorMatcher cloned = matcher.clone(true);
|
||||
|
||||
assertNotNull(cloned);
|
||||
assertTrue(cloned.empty());
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(matcher);
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testGetTrainDescriptors() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
Mat truth = train.clone();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
List<Mat> descriptors = matcher.getTrainDescriptors();
|
||||
|
||||
assertEquals(1, descriptors.size());
|
||||
assertMatEqual(truth, descriptors.get(0));
|
||||
}
|
||||
|
||||
public void testIsMaskSupported() {
|
||||
assertTrue(matcher.isMaskSupported());
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
matcher.match(query, matches);
|
||||
|
||||
assertArrayDMatchEquals(truth, matches.toArray(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatchListOfMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
matcher.match(query, matches, Arrays.asList(mask));
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth[0], truth[1]), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches);
|
||||
|
||||
assertArrayDMatchEquals(truth, matches.toArray(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatchMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches, mask);
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth[0], truth[1]), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(filename, "%YAML:1.0\n---\n");
|
||||
|
||||
matcher.read(filename);
|
||||
assertTrue(true);// BruteforceMatcher has no settings
|
||||
}
|
||||
|
||||
public void testTrain() {
|
||||
matcher.train();// BruteforceMatcher does not need to train
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
matcher.write(filename);
|
||||
|
||||
String truth = "%YAML:1.0\n---\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfDMatch;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.DMatch;
|
||||
import org.opencv.features2d.DescriptorMatcher;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class BruteForceSL2DescriptorMatcherTest extends OpenCVTestCase {
|
||||
|
||||
DescriptorMatcher matcher;
|
||||
int matSize;
|
||||
DMatch[] truth;
|
||||
|
||||
private Mat getMaskImg() {
|
||||
return new Mat(5, 2, CvType.CV_8U, new Scalar(0)) {
|
||||
{
|
||||
put(0, 0, 1, 1, 1, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
private float sqr(float val){
|
||||
return val * val;
|
||||
}
|
||||
*/
|
||||
|
||||
private Mat getQueryDescriptors() {
|
||||
Mat img = getQueryImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
Feature2D detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
|
||||
setProperty(detector, "hessianThreshold", "double", 8000);
|
||||
setProperty(detector, "nOctaves", "int", 3);
|
||||
setProperty(detector, "nOctaveLayers", "int", 4);
|
||||
setProperty(detector, "upright", "boolean", false);
|
||||
|
||||
detector.detect(img, keypoints);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private Mat getQueryImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(30, matSize / 2), new Point(matSize - 31, matSize / 2), new Scalar(100), 3);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 30), new Point(matSize / 2, matSize - 31), new Scalar(100), 3);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
private Mat getTrainDescriptors() {
|
||||
Mat img = getTrainImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint(new KeyPoint(50, 50, 16, 0, 20000, 1, -1), new KeyPoint(42, 42, 16, 160, 10000, 1, -1));
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private Mat getTrainImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(20, matSize / 2), new Point(matSize - 21, matSize / 2), new Scalar(100), 2);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 20), new Point(matSize / 2, matSize - 21), new Scalar(100), 2);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_SL2);
|
||||
matSize = 100;
|
||||
|
||||
truth = new DMatch[] {
|
||||
new DMatch(0, 0, 0, 0.37933317f),
|
||||
new DMatch(1, 1, 0, 0.8421953f),
|
||||
new DMatch(2, 1, 0, 0.0968556f),
|
||||
new DMatch(3, 1, 0, 0.0855606f),
|
||||
new DMatch(4, 1, 0, 0.07033461f)
|
||||
};
|
||||
}
|
||||
|
||||
public void testAdd() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
assertFalse(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClear() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
matcher.clear();
|
||||
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClone() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
Mat truth = train.clone();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
DescriptorMatcher cloned = matcher.clone();
|
||||
|
||||
assertNotNull(cloned);
|
||||
|
||||
List<Mat> descriptors = cloned.getTrainDescriptors();
|
||||
assertEquals(1, descriptors.size());
|
||||
assertMatEqual(truth, descriptors.get(0));
|
||||
}
|
||||
|
||||
public void testCloneBoolean() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
DescriptorMatcher cloned = matcher.clone(true);
|
||||
|
||||
assertNotNull(cloned);
|
||||
assertTrue(cloned.empty());
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(matcher);
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testGetTrainDescriptors() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
Mat truth = train.clone();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
List<Mat> descriptors = matcher.getTrainDescriptors();
|
||||
|
||||
assertEquals(1, descriptors.size());
|
||||
assertMatEqual(truth, descriptors.get(0));
|
||||
}
|
||||
|
||||
public void testIsMaskSupported() {
|
||||
assertTrue(matcher.isMaskSupported());
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
matcher.match(query, matches);
|
||||
OpenCVTestRunner.Log(matches);
|
||||
OpenCVTestRunner.Log(matches);
|
||||
OpenCVTestRunner.Log(matches);
|
||||
|
||||
assertArrayDMatchEquals(truth, matches.toArray(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatchListOfMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
matcher.match(query, matches, Arrays.asList(mask));
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth[0], truth[1]), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches);
|
||||
|
||||
assertArrayDMatchEquals(truth, matches.toArray(), EPS);
|
||||
|
||||
// OpenCVTestRunner.Log("matches found: " + matches.size());
|
||||
// for (DMatch m : matches)
|
||||
// OpenCVTestRunner.Log(m.toString());
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatchMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches, mask);
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth[0], truth[1]), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(filename, "%YAML:1.0\n---\n");
|
||||
|
||||
matcher.read(filename);
|
||||
assertTrue(true);// BruteforceMatcher has no settings
|
||||
}
|
||||
|
||||
public void testTrain() {
|
||||
matcher.train();// BruteforceMatcher does not need to train
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
matcher.write(filename);
|
||||
|
||||
String truth = "%YAML:1.0\n---\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
|
||||
public class DENSEFeatureDetectorTest extends OpenCVTestCase {
|
||||
|
||||
public void testCreate() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPointMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.opencv.core.Core;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.features2d.FeatureDetector;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
public class FASTFeatureDetectorTest extends OpenCVTestCase {
|
||||
|
||||
FeatureDetector detector;
|
||||
KeyPoint[] truth;
|
||||
|
||||
private Mat getMaskImg() {
|
||||
Mat mask = new Mat(100, 100, CvType.CV_8U, new Scalar(255));
|
||||
Mat right = mask.submat(0, 100, 50, 100);
|
||||
right.setTo(new Scalar(0));
|
||||
return mask;
|
||||
}
|
||||
|
||||
private Mat getTestImg() {
|
||||
Mat img = new Mat(100, 100, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(img, new Point(30, 30), new Point(70, 70), new Scalar(0), 8);
|
||||
return img;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
detector = FeatureDetector.create(FeatureDetector.FAST);
|
||||
truth = new KeyPoint[] { new KeyPoint(32, 27, 7, -1, 254, 0, -1), new KeyPoint(27, 32, 7, -1, 254, 0, -1), new KeyPoint(73, 68, 7, -1, 254, 0, -1),
|
||||
new KeyPoint(68, 73, 7, -1, 254, 0, -1) };
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(detector);
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPoint() {
|
||||
Mat img = getTestImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(img, keypoints);
|
||||
|
||||
assertListKeyPointEquals(Arrays.asList(truth), keypoints.toList(), EPS);
|
||||
|
||||
// OpenCVTestRunner.Log("points found: " + keypoints.size());
|
||||
// for (KeyPoint kp : keypoints)
|
||||
// OpenCVTestRunner.Log(kp.toString());
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPointMat() {
|
||||
Mat img = getTestImg();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(img, keypoints, mask);
|
||||
|
||||
assertListKeyPointEquals(Arrays.asList(truth[0], truth[1]), keypoints.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
// assertFalse(detector.empty());
|
||||
fail("Not yet implemented"); //FAST does not override empty() method
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
writeFile(filename, "%YAML:1.0\n---\nthreshold: 130\nnonmaxSuppression: 1\n");
|
||||
detector.read(filename);
|
||||
|
||||
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(grayChess, keypoints1);
|
||||
|
||||
writeFile(filename, "%YAML:1.0\n---\nthreshold: 150\nnonmaxSuppression: 1\n");
|
||||
detector.read(filename);
|
||||
|
||||
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(grayChess, keypoints2);
|
||||
|
||||
assertTrue(keypoints2.total() <= keypoints1.total());
|
||||
}
|
||||
|
||||
public void testReadYml() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
writeFile(filename,
|
||||
"<?xml version=\"1.0\"?>\n<opencv_storage>\n<threshold>130</threshold>\n<nonmaxSuppression>1</nonmaxSuppression>\n</opencv_storage>\n");
|
||||
detector.read(filename);
|
||||
|
||||
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(grayChess, keypoints1);
|
||||
|
||||
writeFile(filename,
|
||||
"<?xml version=\"1.0\"?>\n<opencv_storage>\n<threshold>150</threshold>\n<nonmaxSuppression>1</nonmaxSuppression>\n</opencv_storage>\n");
|
||||
detector.read(filename);
|
||||
|
||||
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(grayChess, keypoints2);
|
||||
|
||||
assertTrue(keypoints2.total() <= keypoints1.total());
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("xml");
|
||||
|
||||
detector.write(filename);
|
||||
|
||||
// String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.FAST</name>\n<nonmaxSuppression>1</nonmaxSuppression>\n<threshold>10</threshold>\n<type>2</type>\n</opencv_storage>\n";
|
||||
String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
|
||||
String data = readFile(filename);
|
||||
//Log.d("qqq", "\"" + data + "\"");
|
||||
assertEquals(truth, data);
|
||||
}
|
||||
|
||||
public void testWriteYml() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
detector.write(filename);
|
||||
|
||||
// String truth = "%YAML:1.0\n---\nname: \"Feature2D.FAST\"\nnonmaxSuppression: 1\nthreshold: 10\ntype: 2\n";
|
||||
String truth = "%YAML:1.0\n---\n";
|
||||
String data = readFile(filename);
|
||||
|
||||
//Log.d("qqq", "\"" + data + "\"");
|
||||
assertEquals(truth, data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.opencv.calib3d.Calib3d;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfDMatch;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.MatOfPoint2f;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Range;
|
||||
import org.opencv.core.DMatch;
|
||||
import org.opencv.features2d.DescriptorMatcher;
|
||||
import org.opencv.features2d.Features2d;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.imgcodecs.Imgcodecs;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class Features2dTest extends OpenCVTestCase {
|
||||
|
||||
public void testDrawKeypointsMatListOfKeyPointMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawKeypointsMatListOfKeyPointMatScalar() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawKeypointsMatListOfKeyPointMatScalarInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawMatches2MatListOfKeyPointMatListOfKeyPointListOfListOfDMatchMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawMatches2MatListOfKeyPointMatListOfKeyPointListOfListOfDMatchMatScalar() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawMatches2MatListOfKeyPointMatListOfKeyPointListOfListOfDMatchMatScalarScalar() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawMatches2MatListOfKeyPointMatListOfKeyPointListOfListOfDMatchMatScalarScalarListOfListOfByte() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawMatches2MatListOfKeyPointMatListOfKeyPointListOfListOfDMatchMatScalarScalarListOfListOfByteInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawMatchesMatListOfKeyPointMatListOfKeyPointListOfDMatchMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawMatchesMatListOfKeyPointMatListOfKeyPointListOfDMatchMatScalar() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawMatchesMatListOfKeyPointMatListOfKeyPointListOfDMatchMatScalarScalar() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawMatchesMatListOfKeyPointMatListOfKeyPointListOfDMatchMatScalarScalarListOfByte() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDrawMatchesMatListOfKeyPointMatListOfKeyPointListOfDMatchMatScalarScalarListOfByteInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testPTOD()
|
||||
{
|
||||
String detectorCfg = "%YAML:1.0\n---\nhessianThreshold: 4000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n";
|
||||
String extractorCfg = "%YAML:1.0\n---\nnOctaves: 4\nnOctaveLayers: 2\nextended: 0\nupright: 0\n";
|
||||
|
||||
Feature2D detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE);
|
||||
|
||||
String detectorCfgFile = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(detectorCfgFile, detectorCfg);
|
||||
detector.read(detectorCfgFile);
|
||||
|
||||
String extractorCfgFile = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(extractorCfgFile, extractorCfg);
|
||||
extractor.read(extractorCfgFile);
|
||||
|
||||
Mat imgTrain = Imgcodecs.imread(OpenCVTestRunner.LENA_PATH, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
|
||||
Mat imgQuery = imgTrain.submat(new Range(0, imgTrain.rows() - 100), Range.all());
|
||||
|
||||
MatOfKeyPoint trainKeypoints = new MatOfKeyPoint();
|
||||
MatOfKeyPoint queryKeypoints = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(imgTrain, trainKeypoints);
|
||||
detector.detect(imgQuery, queryKeypoints);
|
||||
|
||||
// OpenCVTestRunner.Log("Keypoints found: " + trainKeypoints.size() +
|
||||
// ":" + queryKeypoints.size());
|
||||
|
||||
Mat trainDescriptors = new Mat();
|
||||
Mat queryDescriptors = new Mat();
|
||||
|
||||
extractor.compute(imgTrain, trainKeypoints, trainDescriptors);
|
||||
extractor.compute(imgQuery, queryKeypoints, queryDescriptors);
|
||||
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.add(Arrays.asList(trainDescriptors));
|
||||
matcher.match(queryDescriptors, matches);
|
||||
|
||||
// OpenCVTestRunner.Log("Matches found: " + matches.size());
|
||||
|
||||
DMatch adm[] = matches.toArray();
|
||||
List<Point> lp1 = new ArrayList<Point>(adm.length);
|
||||
List<Point> lp2 = new ArrayList<Point>(adm.length);
|
||||
KeyPoint tkp[] = trainKeypoints.toArray();
|
||||
KeyPoint qkp[] = queryKeypoints.toArray();
|
||||
for (int i = 0; i < adm.length; i++) {
|
||||
DMatch dm = adm[i];
|
||||
lp1.add(tkp[dm.trainIdx].pt);
|
||||
lp2.add(qkp[dm.queryIdx].pt);
|
||||
}
|
||||
|
||||
MatOfPoint2f points1 = new MatOfPoint2f(lp1.toArray(new Point[0]));
|
||||
MatOfPoint2f points2 = new MatOfPoint2f(lp2.toArray(new Point[0]));
|
||||
|
||||
Mat hmg = Calib3d.findHomography(points1, points2, Calib3d.RANSAC, 3);
|
||||
|
||||
assertMatEqual(Mat.eye(3, 3, CvType.CV_64F), hmg, EPS);
|
||||
|
||||
Mat outimg = new Mat();
|
||||
Features2d.drawMatches(imgQuery, queryKeypoints, imgTrain, trainKeypoints, matches, outimg);
|
||||
String outputPath = OpenCVTestRunner.getOutputFileName("PTODresult.png");
|
||||
Imgcodecs.imwrite(outputPath, outimg);
|
||||
// OpenCVTestRunner.Log("Output image is saved to: " + outputPath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.opencv.core.CvException;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfDMatch;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.DMatch;
|
||||
import org.opencv.features2d.DescriptorMatcher;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase {
|
||||
|
||||
static final String xmlParamsDefault = "<?xml version=\"1.0\"?>\n"
|
||||
+ "<opencv_storage>\n"
|
||||
+ "<format>3</format>\n"
|
||||
+ "<indexParams>\n"
|
||||
+ " <_>\n"
|
||||
+ " <name>algorithm</name>\n"
|
||||
+ " <type>23</type>\n"
|
||||
+ " <value>1</value></_>\n"
|
||||
+ " <_>\n"
|
||||
+ " <name>trees</name>\n"
|
||||
+ " <type>4</type>\n"
|
||||
+ " <value>4</value></_></indexParams>\n"
|
||||
+ "<searchParams>\n"
|
||||
+ " <_>\n"
|
||||
+ " <name>checks</name>\n"
|
||||
+ " <type>4</type>\n"
|
||||
+ " <value>32</value></_>\n"
|
||||
+ " <_>\n"
|
||||
+ " <name>eps</name>\n"
|
||||
+ " <type>5</type>\n"
|
||||
+ " <value>0.</value></_>\n"
|
||||
+ " <_>\n"
|
||||
+ " <name>sorted</name>\n"
|
||||
+ " <type>15</type>\n"
|
||||
+ " <value>1</value></_></searchParams>\n"
|
||||
+ "</opencv_storage>\n";
|
||||
static final String ymlParamsDefault = "%YAML:1.0\n---\n"
|
||||
+ "format: 3\n"
|
||||
+ "indexParams:\n"
|
||||
+ " -\n"
|
||||
+ " name: algorithm\n"
|
||||
+ " type: 23\n"
|
||||
+ " value: 1\n"
|
||||
+ " -\n"
|
||||
+ " name: trees\n"
|
||||
+ " type: 4\n"
|
||||
+ " value: 4\n"
|
||||
+ "searchParams:\n"
|
||||
+ " -\n"
|
||||
+ " name: checks\n"
|
||||
+ " type: 4\n"
|
||||
+ " value: 32\n"
|
||||
+ " -\n"
|
||||
+ " name: eps\n"
|
||||
+ " type: 5\n"
|
||||
+ " value: 0.\n"
|
||||
+ " -\n"
|
||||
+ " name: sorted\n"
|
||||
+ " type: 15\n"
|
||||
+ " value: 1\n";
|
||||
static final String ymlParamsModified = "%YAML:1.0\n---\n"
|
||||
+ "format: 3\n"
|
||||
+ "indexParams:\n"
|
||||
+ " -\n"
|
||||
+ " name: algorithm\n"
|
||||
+ " type: 23\n"
|
||||
+ " value: 6\n"// this line is changed!
|
||||
+ " -\n"
|
||||
+ " name: trees\n"
|
||||
+ " type: 4\n"
|
||||
+ " value: 4\n"
|
||||
+ "searchParams:\n"
|
||||
+ " -\n"
|
||||
+ " name: checks\n"
|
||||
+ " type: 4\n"
|
||||
+ " value: 32\n"
|
||||
+ " -\n"
|
||||
+ " name: eps\n"
|
||||
+ " type: 5\n"
|
||||
+ " value: 4.\n"// this line is changed!
|
||||
+ " -\n"
|
||||
+ " name: sorted\n"
|
||||
+ " type: 15\n"
|
||||
+ " value: 1\n";
|
||||
|
||||
DescriptorMatcher matcher;
|
||||
|
||||
int matSize;
|
||||
|
||||
DMatch[] truth;
|
||||
|
||||
private Mat getMaskImg() {
|
||||
return new Mat(5, 2, CvType.CV_8U, new Scalar(0)) {
|
||||
{
|
||||
put(0, 0, 1, 1, 1, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Mat getQueryDescriptors() {
|
||||
Mat img = getQueryImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
Feature2D detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
|
||||
setProperty(detector, "hessianThreshold", "double", 8000);
|
||||
setProperty(detector, "nOctaves", "int", 3);
|
||||
setProperty(detector, "upright", "boolean", false);
|
||||
|
||||
detector.detect(img, keypoints);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private Mat getQueryImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(30, matSize / 2), new Point(matSize - 31, matSize / 2), new Scalar(100), 3);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 30), new Point(matSize / 2, matSize - 31), new Scalar(100), 3);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
private Mat getTrainDescriptors() {
|
||||
Mat img = getTrainImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint(new KeyPoint(50, 50, 16, 0, 20000, 1, -1), new KeyPoint(42, 42, 16, 160, 10000, 1, -1));
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private Mat getTrainImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(20, matSize / 2), new Point(matSize - 21, matSize / 2), new Scalar(100), 2);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 20), new Point(matSize / 2, matSize - 21), new Scalar(100), 2);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED);
|
||||
matSize = 100;
|
||||
truth = new DMatch[] {
|
||||
new DMatch(0, 0, 0, 0.6159003f),
|
||||
new DMatch(1, 1, 0, 0.9177120f),
|
||||
new DMatch(2, 1, 0, 0.3112163f),
|
||||
new DMatch(3, 1, 0, 0.2925075f),
|
||||
new DMatch(4, 1, 0, 0.26520672f)
|
||||
};
|
||||
}
|
||||
|
||||
public void testAdd() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
assertFalse(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClear() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
matcher.clear();
|
||||
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testClone() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
try {
|
||||
matcher.clone();
|
||||
fail("Expected CvException (CV_StsNotImplemented)");
|
||||
} catch (CvException cverr) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testCloneBoolean() {
|
||||
matcher.add(Arrays.asList(new Mat()));
|
||||
|
||||
DescriptorMatcher cloned = matcher.clone(true);
|
||||
|
||||
assertNotNull(cloned);
|
||||
assertTrue(cloned.empty());
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(matcher);
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
assertTrue(matcher.empty());
|
||||
}
|
||||
|
||||
public void testGetTrainDescriptors() {
|
||||
Mat train = new Mat(1, 1, CvType.CV_8U, new Scalar(123));
|
||||
Mat truth = train.clone();
|
||||
matcher.add(Arrays.asList(train));
|
||||
|
||||
List<Mat> descriptors = matcher.getTrainDescriptors();
|
||||
|
||||
assertEquals(1, descriptors.size());
|
||||
assertMatEqual(truth, descriptors.get(0));
|
||||
}
|
||||
|
||||
public void testIsMaskSupported() {
|
||||
assertFalse(matcher.isMaskSupported());
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatListOfListOfDMatchIntListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchInt() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testKnnMatchMatMatListOfListOfDMatchIntMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
matcher.train();
|
||||
|
||||
matcher.match(query, matches);
|
||||
|
||||
assertArrayDMatchEquals(truth, matches.toArray(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatListOfDMatchListOfMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
matcher.add(Arrays.asList(train));
|
||||
matcher.train();
|
||||
|
||||
matcher.match(query, matches, Arrays.asList(mask));
|
||||
|
||||
assertArrayDMatchEquals(truth, matches.toArray(), EPS);
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatch() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches);
|
||||
|
||||
assertArrayDMatchEquals(truth, matches.toArray(), EPS);
|
||||
|
||||
// OpenCVTestRunner.Log(matches.toString());
|
||||
// OpenCVTestRunner.Log(matches);
|
||||
}
|
||||
|
||||
public void testMatchMatMatListOfDMatchMat() {
|
||||
Mat train = getTrainDescriptors();
|
||||
Mat query = getQueryDescriptors();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfDMatch matches = new MatOfDMatch();
|
||||
|
||||
matcher.match(query, train, matches, mask);
|
||||
|
||||
assertListDMatchEquals(Arrays.asList(truth), matches.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatListOfListOfDMatchFloatListOfMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRadiusMatchMatMatListOfListOfDMatchFloatMatBoolean() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
String filenameR = OpenCVTestRunner.getTempFileName("yml");
|
||||
String filenameW = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(filenameR, ymlParamsModified);
|
||||
|
||||
matcher.read(filenameR);
|
||||
matcher.write(filenameW);
|
||||
|
||||
assertEquals(ymlParamsModified, readFile(filenameW));
|
||||
}
|
||||
|
||||
public void testTrain() {
|
||||
Mat train = getTrainDescriptors();
|
||||
matcher.add(Arrays.asList(train));
|
||||
matcher.train();
|
||||
}
|
||||
|
||||
public void testTrainNoData() {
|
||||
try {
|
||||
matcher.train();
|
||||
fail("Expected CvException - FlannBasedMatcher::train should fail on empty train set");
|
||||
} catch (CvException cverr) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("xml");
|
||||
|
||||
matcher.write(filename);
|
||||
|
||||
assertEquals(xmlParamsDefault, readFile(filename));
|
||||
}
|
||||
|
||||
public void testWriteYml() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
matcher.write(filename);
|
||||
|
||||
assertEquals(ymlParamsDefault, readFile(filename));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
|
||||
public class GFTTFeatureDetectorTest extends OpenCVTestCase {
|
||||
|
||||
public void testCreate() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPointMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
|
||||
public class HARRISFeatureDetectorTest extends OpenCVTestCase {
|
||||
|
||||
public void testCreate() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPointMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
|
||||
public class MSERFeatureDetectorTest extends OpenCVTestCase {
|
||||
|
||||
public void testCreate() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPointMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import org.opencv.core.Core;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.features2d.DescriptorExtractor;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.features2d.ORB;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
public class ORBDescriptorExtractorTest extends OpenCVTestCase {
|
||||
|
||||
ORB extractor;
|
||||
int matSize;
|
||||
|
||||
public static void assertDescriptorsClose(Mat expected, Mat actual, int allowedDistance) {
|
||||
double distance = Core.norm(expected, actual, Core.NORM_HAMMING);
|
||||
assertTrue("expected:<" + allowedDistance + "> but was:<" + distance + ">", distance <= allowedDistance);
|
||||
}
|
||||
|
||||
private Mat getTestImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(20, matSize / 2), new Point(matSize - 21, matSize / 2), new Scalar(100), 2);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 20), new Point(matSize / 2, matSize - 21), new Scalar(100), 2);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
extractor = ORB.create();
|
||||
matSize = 100;
|
||||
}
|
||||
|
||||
public void testComputeListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testComputeMatListOfKeyPointMat() {
|
||||
KeyPoint point = new KeyPoint(55.775577545166016f, 44.224422454833984f, 16, 9.754629f, 8617.863f, 1, -1);
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint(point);
|
||||
Mat img = getTestImg();
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
Mat truth = new Mat(1, 32, CvType.CV_8UC1) {
|
||||
{
|
||||
put(0, 0,
|
||||
6, 74, 6, 129, 2, 130, 56, 0, 44, 132, 66, 165, 172, 6, 3, 72, 102, 61, 171, 214, 0, 144, 65, 232, 4, 32, 138, 131, 4, 21, 37, 217);
|
||||
}
|
||||
};
|
||||
assertDescriptorsClose(truth, descriptors, 1);
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(extractor);
|
||||
}
|
||||
|
||||
public void testDescriptorSize() {
|
||||
assertEquals(32, extractor.descriptorSize());
|
||||
}
|
||||
|
||||
public void testDescriptorType() {
|
||||
assertEquals(CvType.CV_8U, extractor.descriptorType());
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
// assertFalse(extractor.empty());
|
||||
fail("Not yet implemented"); // ORB does not override empty() method
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
KeyPoint point = new KeyPoint(55.775577545166016f, 44.224422454833984f, 16, 9.754629f, 8617.863f, 1, -1);
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint(point);
|
||||
Mat img = getTestImg();
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
// String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
// writeFile(filename, "%YAML:1.0\n---\nscaleFactor: 1.1\nnLevels: 3\nfirstLevel: 0\nedgeThreshold: 31\npatchSize: 31\n");
|
||||
// extractor.read(filename);
|
||||
extractor = ORB.create(500, 1.1f, 3, 31, 0, 2, ORB.HARRIS_SCORE, 31, 20);
|
||||
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
Mat truth = new Mat(1, 32, CvType.CV_8UC1) {
|
||||
{
|
||||
put(0, 0,
|
||||
6, 10, 22, 5, 2, 130, 56, 0, 44, 164, 66, 165, 140, 6, 1, 72, 38, 61, 163, 210, 0, 208, 1, 104, 4, 32, 74, 131, 0, 37, 37, 67);
|
||||
}
|
||||
};
|
||||
assertDescriptorsClose(truth, descriptors, 1);
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("xml");
|
||||
|
||||
extractor.write(filename);
|
||||
|
||||
// String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.ORB</name>\n<WTA_K>2</WTA_K>\n<edgeThreshold>31</edgeThreshold>\n<firstLevel>0</firstLevel>\n<nFeatures>500</nFeatures>\n<nLevels>8</nLevels>\n<patchSize>31</patchSize>\n<scaleFactor>1.2000000476837158e+00</scaleFactor>\n<scoreType>0</scoreType>\n</opencv_storage>\n";
|
||||
String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
|
||||
String actual = readFile(filename);
|
||||
actual = actual.replaceAll("e\\+000", "e+00"); // NOTE: workaround for different platforms double representation
|
||||
assertEquals(truth, actual);
|
||||
}
|
||||
|
||||
public void testWriteYml() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
extractor.write(filename);
|
||||
|
||||
// String truth = "%YAML:1.0\n---\nname: \"Feature2D.ORB\"\nWTA_K: 2\nedgeThreshold: 31\nfirstLevel: 0\nnFeatures: 500\nnLevels: 8\npatchSize: 31\nscaleFactor: 1.2000000476837158e+00\nscoreType: 0\n";
|
||||
String truth = "%YAML:1.0\n---\n";
|
||||
String actual = readFile(filename);
|
||||
actual = actual.replaceAll("e\\+000", "e+00"); // NOTE: workaround for different platforms double representation
|
||||
assertEquals(truth, actual);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
|
||||
public class ORBFeatureDetectorTest extends OpenCVTestCase {
|
||||
|
||||
public void testCreate() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPointMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class SIFTDescriptorExtractorTest extends OpenCVTestCase {
|
||||
|
||||
Feature2D extractor;
|
||||
KeyPoint keypoint;
|
||||
int matSize;
|
||||
Mat truth;
|
||||
|
||||
private Mat getTestImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(20, matSize / 2), new Point(matSize - 21, matSize / 2), new Scalar(100), 2);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 20), new Point(matSize / 2, matSize - 21), new Scalar(100), 2);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
extractor = createClassInstance(XFEATURES2D+"SIFT", DEFAULT_FACTORY, null, null);
|
||||
keypoint = new KeyPoint(55.775577545166016f, 44.224422454833984f, 16, 9.754629f, 8617.863f, 1, -1);
|
||||
matSize = 100;
|
||||
truth = new Mat(1, 128, CvType.CV_32FC1) {
|
||||
{
|
||||
put(0, 0,
|
||||
0, 0, 0, 1, 3, 0, 0, 0, 15, 23, 22, 20, 24, 2, 0, 0, 7, 8, 2, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 16, 13, 2, 0, 0, 117,
|
||||
86, 79, 68, 117, 42, 5, 5, 79, 60, 117, 25, 9, 2, 28, 19, 11, 13,
|
||||
20, 2, 0, 0, 5, 8, 0, 0, 76, 58, 34, 31, 97, 16, 95, 49, 117, 92,
|
||||
117, 112, 117, 76, 117, 54, 117, 25, 29, 22, 117, 117, 16, 11, 14,
|
||||
1, 0, 0, 22, 26, 0, 0, 0, 0, 1, 4, 15, 2, 47, 8, 0, 0, 82, 56, 31,
|
||||
17, 81, 12, 0, 0, 26, 23, 18, 23, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void testComputeListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testComputeMatListOfKeyPointMat() {
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint(keypoint);
|
||||
Mat img = getTestImg();
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
assertMatEqual(truth, descriptors, EPS);
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(extractor);
|
||||
}
|
||||
|
||||
public void testDescriptorSize() {
|
||||
assertEquals(128, extractor.descriptorSize());
|
||||
}
|
||||
|
||||
public void testDescriptorType() {
|
||||
assertEquals(CvType.CV_32F, extractor.descriptorType());
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
// assertFalse(extractor.empty());
|
||||
fail("Not yet implemented"); //SIFT does not override empty() method
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("xml");
|
||||
|
||||
extractor.write(filename);
|
||||
|
||||
// String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.SIFT</name>\n<contrastThreshold>4.0000000000000001e-02</contrastThreshold>\n<edgeThreshold>10.</edgeThreshold>\n<nFeatures>0</nFeatures>\n<nOctaveLayers>3</nOctaveLayers>\n<sigma>1.6000000000000001e+00</sigma>\n</opencv_storage>\n";
|
||||
String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
|
||||
String actual = readFile(filename);
|
||||
actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation
|
||||
assertEquals(truth, actual);
|
||||
}
|
||||
|
||||
public void testWriteYml() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
extractor.write(filename);
|
||||
|
||||
// String truth = "%YAML:1.0\n---\nname: \"Feature2D.SIFT\"\ncontrastThreshold: 4.0000000000000001e-02\nedgeThreshold: 10.\nnFeatures: 0\nnOctaveLayers: 3\nsigma: 1.6000000000000001e+00\n";
|
||||
String truth = "%YAML:1.0\n---\n";
|
||||
String actual = readFile(filename);
|
||||
actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation
|
||||
assertEquals(truth, actual);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
|
||||
public class SIFTFeatureDetectorTest extends OpenCVTestCase {
|
||||
|
||||
public void testCreate() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPointMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
import org.opencv.features2d.SimpleBlobDetector;
|
||||
|
||||
public class SIMPLEBLOBFeatureDetectorTest extends OpenCVTestCase {
|
||||
|
||||
Feature2D detector;
|
||||
int matSize;
|
||||
KeyPoint[] truth;
|
||||
|
||||
private Mat getMaskImg() {
|
||||
Mat mask = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Mat right = mask.submat(0, matSize, matSize / 2, matSize);
|
||||
right.setTo(new Scalar(0));
|
||||
return mask;
|
||||
}
|
||||
|
||||
private Mat getTestImg() {
|
||||
|
||||
int center = matSize / 2;
|
||||
int offset = 40;
|
||||
|
||||
Mat img = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.circle(img, new Point(center - offset, center), 24, new Scalar(0), -1);
|
||||
Imgproc.circle(img, new Point(center + offset, center), 20, new Scalar(50), -1);
|
||||
Imgproc.circle(img, new Point(center, center - offset), 18, new Scalar(100), -1);
|
||||
Imgproc.circle(img, new Point(center, center + offset), 14, new Scalar(150), -1);
|
||||
Imgproc.circle(img, new Point(center, center), 10, new Scalar(200), -1);
|
||||
return img;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
detector = SimpleBlobDetector.create();
|
||||
matSize = 200;
|
||||
truth = new KeyPoint[] {
|
||||
new KeyPoint( 140, 100, 41.036568f, -1, 0, 0, -1),
|
||||
new KeyPoint( 60, 100, 48.538486f, -1, 0, 0, -1),
|
||||
new KeyPoint(100, 60, 36.769554f, -1, 0, 0, -1),
|
||||
new KeyPoint(100, 140, 28.635643f, -1, 0, 0, -1),
|
||||
new KeyPoint(100, 100, 20.880613f, -1, 0, 0, -1)
|
||||
};
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(detector);
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPoint() {
|
||||
Mat img = getTestImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(img, keypoints);
|
||||
|
||||
assertListKeyPointEquals(Arrays.asList(truth), keypoints.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPointMat() {
|
||||
Mat img = getTestImg();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(img, keypoints, mask);
|
||||
|
||||
assertListKeyPointEquals(Arrays.asList(truth[1]), keypoints.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
// assertFalse(detector.empty());
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
Mat img = getTestImg();
|
||||
|
||||
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
|
||||
detector.detect(img, keypoints1);
|
||||
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(filename, "%YAML:1.0\nthresholdStep: 10\nminThreshold: 50\nmaxThreshold: 220\nminRepeatability: 2\nfilterByArea: true\nminArea: 800\nmaxArea: 5000\n");
|
||||
detector.read(filename);
|
||||
|
||||
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
|
||||
detector.detect(img, keypoints2);
|
||||
|
||||
assertTrue(keypoints2.total() <= keypoints1.total());
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("xml");
|
||||
|
||||
detector.write(filename);
|
||||
|
||||
String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<format>3</format>\n<thresholdStep>10.</thresholdStep>\n<minThreshold>50.</minThreshold>\n<maxThreshold>220.</maxThreshold>\n<minRepeatability>2</minRepeatability>\n<minDistBetweenBlobs>10.</minDistBetweenBlobs>\n<filterByColor>1</filterByColor>\n<blobColor>0</blobColor>\n<filterByArea>1</filterByArea>\n<minArea>25.</minArea>\n<maxArea>5000.</maxArea>\n<filterByCircularity>0</filterByCircularity>\n<minCircularity>8.0000001192092896e-01</minCircularity>\n<maxCircularity>3.4028234663852886e+38</maxCircularity>\n<filterByInertia>1</filterByInertia>\n<minInertiaRatio>1.0000000149011612e-01</minInertiaRatio>\n<maxInertiaRatio>3.4028234663852886e+38</maxInertiaRatio>\n<filterByConvexity>1</filterByConvexity>\n<minConvexity>9.4999998807907104e-01</minConvexity>\n<maxConvexity>3.4028234663852886e+38</maxConvexity>\n</opencv_storage>\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class STARFeatureDetectorTest extends OpenCVTestCase {
|
||||
|
||||
Feature2D detector;
|
||||
int matSize;
|
||||
KeyPoint[] truth;
|
||||
|
||||
private Mat getMaskImg() {
|
||||
Mat mask = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Mat right = mask.submat(0, matSize, matSize / 2, matSize);
|
||||
right.setTo(new Scalar(0));
|
||||
return mask;
|
||||
}
|
||||
|
||||
private Mat getTestImg() {
|
||||
Scalar color = new Scalar(0);
|
||||
int center = matSize / 2;
|
||||
int radius = 6;
|
||||
int offset = 40;
|
||||
|
||||
Mat img = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.circle(img, new Point(center - offset, center), radius, color, -1);
|
||||
Imgproc.circle(img, new Point(center + offset, center), radius, color, -1);
|
||||
Imgproc.circle(img, new Point(center, center - offset), radius, color, -1);
|
||||
Imgproc.circle(img, new Point(center, center + offset), radius, color, -1);
|
||||
Imgproc.circle(img, new Point(center, center), radius, color, -1);
|
||||
return img;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
detector = createClassInstance(XFEATURES2D+"StarDetector", DEFAULT_FACTORY, null, null);
|
||||
matSize = 200;
|
||||
truth = new KeyPoint[] {
|
||||
new KeyPoint( 95, 80, 22, -1, 31.5957f, 0, -1),
|
||||
new KeyPoint(105, 80, 22, -1, 31.5957f, 0, -1),
|
||||
new KeyPoint( 80, 95, 22, -1, 31.5957f, 0, -1),
|
||||
new KeyPoint(120, 95, 22, -1, 31.5957f, 0, -1),
|
||||
new KeyPoint(100, 100, 8, -1, 30.f, 0, -1),
|
||||
new KeyPoint( 80, 105, 22, -1, 31.5957f, 0, -1),
|
||||
new KeyPoint(120, 105, 22, -1, 31.5957f, 0, -1),
|
||||
new KeyPoint( 95, 120, 22, -1, 31.5957f, 0, -1),
|
||||
new KeyPoint(105, 120, 22, -1, 31.5957f, 0, -1)
|
||||
};
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(detector);
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPoint() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPoint() {
|
||||
Mat img = getTestImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(img, keypoints);
|
||||
|
||||
assertListKeyPointEquals(Arrays.asList(truth), keypoints.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPointMat() {
|
||||
Mat img = getTestImg();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(img, keypoints, mask);
|
||||
|
||||
assertListKeyPointEquals(Arrays.asList(truth[0], truth[2], truth[5], truth[7]), keypoints.toList(), EPS);
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
// assertFalse(detector.empty());
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
Mat img = getTestImg();
|
||||
|
||||
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
|
||||
detector.detect(img, keypoints1);
|
||||
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(filename, "%YAML:1.0\n---\nmaxSize: 45\nresponseThreshold: 150\nlineThresholdProjected: 10\nlineThresholdBinarized: 8\nsuppressNonmaxSize: 5\n");
|
||||
detector.read(filename);
|
||||
|
||||
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
|
||||
detector.detect(img, keypoints2);
|
||||
|
||||
assertTrue(keypoints2.total() <= keypoints1.total());
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("xml");
|
||||
|
||||
detector.write(filename);
|
||||
|
||||
// String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.STAR</name>\n<lineThresholdBinarized>8</lineThresholdBinarized>\n<lineThresholdProjected>10</lineThresholdProjected>\n<maxSize>45</maxSize>\n<responseThreshold>30</responseThreshold>\n<suppressNonmaxSize>5</suppressNonmaxSize>\n</opencv_storage>\n";
|
||||
String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
public void testWriteYml() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
detector.write(filename);
|
||||
|
||||
// String truth = "%YAML:1.0\n---\nname: \"Feature2D.STAR\"\nlineThresholdBinarized: 8\nlineThresholdProjected: 10\nmaxSize: 45\nresponseThreshold: 30\nsuppressNonmaxSize: 5\n";
|
||||
String truth = "%YAML:1.0\n---\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class SURFDescriptorExtractorTest extends OpenCVTestCase {
|
||||
|
||||
Feature2D extractor;
|
||||
int matSize;
|
||||
|
||||
private Mat getTestImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(20, matSize / 2), new Point(matSize - 21, matSize / 2), new Scalar(100), 2);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 20), new Point(matSize / 2, matSize - 21), new Scalar(100), 2);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
Class[] cParams = {double.class, int.class, int.class, boolean.class, boolean.class};
|
||||
Object[] oValues = {100, 2, 4, true, false};
|
||||
extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, cParams, oValues);
|
||||
|
||||
matSize = 100;
|
||||
}
|
||||
|
||||
public void testComputeListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testComputeMatListOfKeyPointMat() {
|
||||
KeyPoint point = new KeyPoint(55.775577545166016f, 44.224422454833984f, 16, 9.754629f, 8617.863f, 1, -1);
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint(point);
|
||||
Mat img = getTestImg();
|
||||
Mat descriptors = new Mat();
|
||||
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
|
||||
Mat truth = new Mat(1, 128, CvType.CV_32FC1) {
|
||||
{
|
||||
put(0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0.058821894, 0.058821894, -0.045962855, 0.046261817, 0.0085156476,
|
||||
0.0085754395, -0.0064509804, 0.0064509804, 0.00044069235, 0.00044069235, 0, 0, 0.00025723741,
|
||||
0.00025723741, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.00025723741, 0.00025723741, -0.00044069235,
|
||||
0.00044069235, 0, 0, 0.36278215, 0.36278215, -0.24688604, 0.26173124, 0.052068226, 0.052662034,
|
||||
-0.032815345, 0.032815345, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.0064523756,
|
||||
0.0064523756, 0.0082002236, 0.0088908644, -0.059001274, 0.059001274, 0.045789491, 0.04648013,
|
||||
0.11961588, 0.22789426, -0.01322381, 0.18291828, -0.14042182, 0.23973691, 0.073782086, 0.23769434,
|
||||
-0.027880307, 0.027880307, 0.049587864, 0.049587864, -0.33991757, 0.33991757, 0.21437603, 0.21437603,
|
||||
-0.0020763327, 0.0020763327, 0.006245892, 0.006245892, -0.04067041, 0.04067041, 0.019361559,
|
||||
0.019361559, 0, 0, -0.0035977389, 0.0035977389, 0, 0, -0.00099993451, 0.00099993451, 0.040670406,
|
||||
0.040670406, -0.019361559, 0.019361559, 0.006245892, 0.006245892, -0.0020763327, 0.0020763327,
|
||||
-0.00034532088, 0.00034532088, 0, 0, 0, 0, 0.00034532088, 0.00034532088, -0.00099993451,
|
||||
0.00099993451, 0, 0, 0, 0, 0.0035977389, 0.0035977389
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
assertMatEqual(truth, descriptors, EPS);
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(extractor);
|
||||
}
|
||||
|
||||
public void testDescriptorSize() {
|
||||
assertEquals(128, extractor.descriptorSize());
|
||||
}
|
||||
|
||||
public void testDescriptorType() {
|
||||
assertEquals(CvType.CV_32F, extractor.descriptorType());
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
// assertFalse(extractor.empty());
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(filename, "%YAML:1.0\n---\nnOctaves: 4\nnOctaveLayers: 2\nextended: 1\nupright: 0\n");
|
||||
|
||||
extractor.read(filename);
|
||||
|
||||
assertEquals(128, extractor.descriptorSize());
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("xml");
|
||||
|
||||
extractor.write(filename);
|
||||
|
||||
// String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.SURF</name>\n<extended>1</extended>\n<hessianThreshold>100.</hessianThreshold>\n<nOctaveLayers>2</nOctaveLayers>\n<nOctaves>4</nOctaves>\n<upright>0</upright>\n</opencv_storage>\n";
|
||||
String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
public void testWriteYml() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
extractor.write(filename);
|
||||
|
||||
// String truth = "%YAML:1.0\n---\nname: \"Feature2D.SURF\"\nextended: 1\nhessianThreshold: 100.\nnOctaveLayers: 2\nnOctaves: 4\nupright: 0\n";
|
||||
String truth = "%YAML:1.0\n---\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package org.opencv.test.features2d;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfKeyPoint;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.KeyPoint;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.features2d.Feature2D;
|
||||
|
||||
public class SURFFeatureDetectorTest extends OpenCVTestCase {
|
||||
|
||||
Feature2D detector;
|
||||
int matSize;
|
||||
KeyPoint[] truth;
|
||||
|
||||
private Mat getMaskImg() {
|
||||
Mat mask = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Mat right = mask.submat(0, matSize, matSize / 2, matSize);
|
||||
right.setTo(new Scalar(0));
|
||||
return mask;
|
||||
}
|
||||
|
||||
private Mat getTestImg() {
|
||||
Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255));
|
||||
Imgproc.line(cross, new Point(20, matSize / 2), new Point(matSize - 21, matSize / 2), new Scalar(100), 2);
|
||||
Imgproc.line(cross, new Point(matSize / 2, 20), new Point(matSize / 2, matSize - 21), new Scalar(100), 2);
|
||||
|
||||
return cross;
|
||||
}
|
||||
|
||||
private void order(List<KeyPoint> points) {
|
||||
Collections.sort(points, new Comparator<KeyPoint>() {
|
||||
public int compare(KeyPoint p1, KeyPoint p2) {
|
||||
if (p1.angle < p2.angle)
|
||||
return -1;
|
||||
if (p1.angle > p2.angle)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
|
||||
matSize = 100;
|
||||
truth = new KeyPoint[] {
|
||||
new KeyPoint(55.775578f, 55.775578f, 16, 80.245735f, 8617.8633f, 0, -1),
|
||||
new KeyPoint(44.224422f, 55.775578f, 16, 170.24574f, 8617.8633f, 0, -1),
|
||||
new KeyPoint(44.224422f, 44.224422f, 16, 260.24573f, 8617.8633f, 0, -1),
|
||||
new KeyPoint(55.775578f, 44.224422f, 16, 350.24573f, 8617.8633f, 0, -1)
|
||||
};
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
assertNotNull(detector);
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPoint() {
|
||||
|
||||
setProperty(detector, "hessianThreshold", "double", 8000);
|
||||
setProperty(detector, "nOctaves", "int", 3);
|
||||
setProperty(detector, "nOctaveLayers", "int", 4);
|
||||
setProperty(detector, "upright", "boolean", false);
|
||||
|
||||
List<MatOfKeyPoint> keypoints = new ArrayList<MatOfKeyPoint>();
|
||||
Mat cross = getTestImg();
|
||||
List<Mat> crosses = new ArrayList<Mat>(3);
|
||||
crosses.add(cross);
|
||||
crosses.add(cross);
|
||||
crosses.add(cross);
|
||||
|
||||
detector.detect(crosses, keypoints);
|
||||
|
||||
assertEquals(3, keypoints.size());
|
||||
|
||||
for (MatOfKeyPoint mkp : keypoints) {
|
||||
List<KeyPoint> lkp = mkp.toList();
|
||||
order(lkp);
|
||||
assertListKeyPointEquals(Arrays.asList(truth), lkp, EPS);
|
||||
}
|
||||
}
|
||||
|
||||
public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPoint() {
|
||||
|
||||
setProperty(detector, "hessianThreshold", "double", 8000);
|
||||
setProperty(detector, "nOctaves", "int", 3);
|
||||
setProperty(detector, "nOctaveLayers", "int", 4);
|
||||
setProperty(detector, "upright", "boolean", false);
|
||||
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
Mat cross = getTestImg();
|
||||
|
||||
detector.detect(cross, keypoints);
|
||||
|
||||
List<KeyPoint> lkp = keypoints.toList();
|
||||
order(lkp);
|
||||
assertListKeyPointEquals(Arrays.asList(truth), lkp, EPS);
|
||||
}
|
||||
|
||||
public void testDetectMatListOfKeyPointMat() {
|
||||
|
||||
setProperty(detector, "hessianThreshold", "double", 8000);
|
||||
setProperty(detector, "nOctaves", "int", 3);
|
||||
setProperty(detector, "nOctaveLayers", "int", 4);
|
||||
setProperty(detector, "upright", "boolean", false);
|
||||
|
||||
Mat img = getTestImg();
|
||||
Mat mask = getMaskImg();
|
||||
MatOfKeyPoint keypoints = new MatOfKeyPoint();
|
||||
|
||||
detector.detect(img, keypoints, mask);
|
||||
|
||||
List<KeyPoint> lkp = keypoints.toList();
|
||||
order(lkp);
|
||||
assertListKeyPointEquals(Arrays.asList(truth[1], truth[2]), lkp, EPS);
|
||||
}
|
||||
|
||||
public void testEmpty() {
|
||||
// assertFalse(detector.empty());
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testRead() {
|
||||
Mat cross = getTestImg();
|
||||
|
||||
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
|
||||
detector.detect(cross, keypoints1);
|
||||
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
writeFile(filename, "%YAML:1.0\n---\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n");
|
||||
detector.read(filename);
|
||||
|
||||
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
|
||||
detector.detect(cross, keypoints2);
|
||||
|
||||
assertTrue(keypoints2.total() <= keypoints1.total());
|
||||
}
|
||||
|
||||
public void testWrite() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("xml");
|
||||
|
||||
detector.write(filename);
|
||||
|
||||
// String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.SURF</name>\n<extended>0</extended>\n<hessianThreshold>100.</hessianThreshold>\n<nOctaveLayers>3</nOctaveLayers>\n<nOctaves>4</nOctaves>\n<upright>0</upright>\n</opencv_storage>\n";
|
||||
String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
public void testWriteYml() {
|
||||
String filename = OpenCVTestRunner.getTempFileName("yml");
|
||||
|
||||
detector.write(filename);
|
||||
|
||||
// String truth = "%YAML:1.0\n---\nname: \"Feature2D.SURF\"\nextended: 0\nhessianThreshold: 100.\nnOctaveLayers: 3\nnOctaves: 4\nupright: 0\n";
|
||||
String truth = "%YAML:1.0\n---\n";
|
||||
assertEquals(truth, readFile(filename));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifdef HAVE_OPENCV_FEATURES2D
|
||||
typedef SimpleBlobDetector::Params SimpleBlobDetector_Params;
|
||||
#endif
|
||||
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Feature homography
|
||||
==================
|
||||
|
||||
Example of using features2d framework for interactive video homography matching.
|
||||
ORB features and FLANN matcher are used. The actual tracking is implemented by
|
||||
PlaneTracker class in plane_tracker.py
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
import sys
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
xrange = range
|
||||
|
||||
# local modules
|
||||
from tst_scene_render import TestSceneRender
|
||||
|
||||
def intersectionRate(s1, s2):
|
||||
|
||||
x1, y1, x2, y2 = s1
|
||||
s1 = np.array([[x1, y1], [x2,y1], [x2, y2], [x1, y2]])
|
||||
|
||||
area, _intersection = cv.intersectConvexConvex(s1, np.array(s2))
|
||||
return 2 * area / (cv.contourArea(s1) + cv.contourArea(np.array(s2)))
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
class feature_homography_test(NewOpenCVTests):
|
||||
|
||||
render = None
|
||||
tracker = None
|
||||
framesCounter = 0
|
||||
frame = None
|
||||
|
||||
def test_feature_homography(self):
|
||||
|
||||
self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'),
|
||||
self.get_sample('samples/data/box.png'), noise = 0.5, speed = 0.5)
|
||||
self.frame = self.render.getNextFrame()
|
||||
self.tracker = PlaneTracker()
|
||||
self.tracker.clear()
|
||||
self.tracker.add_target(self.frame, self.render.getCurrentRect())
|
||||
|
||||
while self.framesCounter < 100:
|
||||
self.framesCounter += 1
|
||||
tracked = self.tracker.track(self.frame)
|
||||
if len(tracked) > 0:
|
||||
tracked = tracked[0]
|
||||
self.assertGreater(intersectionRate(self.render.getCurrentRect(), np.int32(tracked.quad)), 0.6)
|
||||
else:
|
||||
self.assertEqual(0, 1, 'Tracking error')
|
||||
self.frame = self.render.getNextFrame()
|
||||
|
||||
|
||||
# built-in modules
|
||||
from collections import namedtuple
|
||||
|
||||
FLANN_INDEX_KDTREE = 1
|
||||
FLANN_INDEX_LSH = 6
|
||||
flann_params= dict(algorithm = FLANN_INDEX_LSH,
|
||||
table_number = 6, # 12
|
||||
key_size = 12, # 20
|
||||
multi_probe_level = 1) #2
|
||||
|
||||
MIN_MATCH_COUNT = 10
|
||||
|
||||
'''
|
||||
image - image to track
|
||||
rect - tracked rectangle (x1, y1, x2, y2)
|
||||
keypoints - keypoints detected inside rect
|
||||
descrs - their descriptors
|
||||
data - some user-provided data
|
||||
'''
|
||||
PlanarTarget = namedtuple('PlaneTarget', 'image, rect, keypoints, descrs, data')
|
||||
|
||||
'''
|
||||
target - reference to PlanarTarget
|
||||
p0 - matched points coords in target image
|
||||
p1 - matched points coords in input frame
|
||||
H - homography matrix from p0 to p1
|
||||
quad - target boundary quad in input frame
|
||||
'''
|
||||
TrackedTarget = namedtuple('TrackedTarget', 'target, p0, p1, H, quad')
|
||||
|
||||
class PlaneTracker:
|
||||
def __init__(self):
|
||||
self.detector = cv.AKAZE_create(threshold = 0.003)
|
||||
self.matcher = cv.FlannBasedMatcher(flann_params, {}) # bug : need to pass empty dict (#1329)
|
||||
self.targets = []
|
||||
self.frame_points = []
|
||||
|
||||
def add_target(self, image, rect, data=None):
|
||||
'''Add a new tracking target.'''
|
||||
x0, y0, x1, y1 = rect
|
||||
raw_points, raw_descrs = self.detect_features(image)
|
||||
points, descs = [], []
|
||||
for kp, desc in zip(raw_points, raw_descrs):
|
||||
x, y = kp.pt
|
||||
if x0 <= x <= x1 and y0 <= y <= y1:
|
||||
points.append(kp)
|
||||
descs.append(desc)
|
||||
descs = np.uint8(descs)
|
||||
self.matcher.add([descs])
|
||||
target = PlanarTarget(image = image, rect=rect, keypoints = points, descrs=descs, data=data)
|
||||
self.targets.append(target)
|
||||
|
||||
def clear(self):
|
||||
'''Remove all targets'''
|
||||
self.targets = []
|
||||
self.matcher.clear()
|
||||
|
||||
def track(self, frame):
|
||||
'''Returns a list of detected TrackedTarget objects'''
|
||||
self.frame_points, frame_descrs = self.detect_features(frame)
|
||||
if len(self.frame_points) < MIN_MATCH_COUNT:
|
||||
return []
|
||||
matches = self.matcher.knnMatch(frame_descrs, k = 2)
|
||||
matches = [m[0] for m in matches if len(m) == 2 and m[0].distance < m[1].distance * 0.75]
|
||||
if len(matches) < MIN_MATCH_COUNT:
|
||||
return []
|
||||
matches_by_id = [[] for _ in xrange(len(self.targets))]
|
||||
for m in matches:
|
||||
matches_by_id[m.imgIdx].append(m)
|
||||
tracked = []
|
||||
for imgIdx, matches in enumerate(matches_by_id):
|
||||
if len(matches) < MIN_MATCH_COUNT:
|
||||
continue
|
||||
target = self.targets[imgIdx]
|
||||
p0 = [target.keypoints[m.trainIdx].pt for m in matches]
|
||||
p1 = [self.frame_points[m.queryIdx].pt for m in matches]
|
||||
p0, p1 = np.float32((p0, p1))
|
||||
H, status = cv.findHomography(p0, p1, cv.RANSAC, 3.0)
|
||||
status = status.ravel() != 0
|
||||
if status.sum() < MIN_MATCH_COUNT:
|
||||
continue
|
||||
p0, p1 = p0[status], p1[status]
|
||||
|
||||
x0, y0, x1, y1 = target.rect
|
||||
quad = np.float32([[x0, y0], [x1, y0], [x1, y1], [x0, y1]])
|
||||
quad = cv.perspectiveTransform(quad.reshape(1, -1, 2), H).reshape(-1, 2)
|
||||
|
||||
track = TrackedTarget(target=target, p0=p0, p1=p1, H=H, quad=quad)
|
||||
tracked.append(track)
|
||||
tracked.sort(key = lambda t: len(t.p0), reverse=True)
|
||||
return tracked
|
||||
|
||||
def detect_features(self, frame):
|
||||
'''detect_features(self, frame) -> keypoints, descrs'''
|
||||
keypoints, descrs = self.detector.detectAndCompute(frame, None)
|
||||
if descrs is None: # detectAndCompute returns descs=None if no keypoints found
|
||||
descrs = []
|
||||
return keypoints, descrs
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
NewOpenCVTests.bootstrap()
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
|
||||
namespace cvtest {
|
||||
namespace opencv_test {
|
||||
namespace ocl {
|
||||
|
||||
//////////////////// BruteForceMatch /////////////////
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
#include "../perf_precomp.hpp"
|
||||
#include "opencv2/ts/ocl_perf.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
|
||||
namespace cvtest {
|
||||
namespace ocl {
|
||||
|
||||
enum { TYPE_5_8 =FastFeatureDetector::TYPE_5_8, TYPE_7_12 = FastFeatureDetector::TYPE_7_12, TYPE_9_16 = FastFeatureDetector::TYPE_9_16 };
|
||||
CV_ENUM(FastType, TYPE_5_8, TYPE_7_12)
|
||||
|
||||
typedef std::tr1::tuple<string, FastType> File_Type_t;
|
||||
typedef TestBaseWithParam<File_Type_t> FASTFixture;
|
||||
|
||||
#define FAST_IMAGES \
|
||||
"cv/detectors_descriptors_evaluation/images_datasets/leuven/img1.png",\
|
||||
"stitching/a3.png"
|
||||
|
||||
OCL_PERF_TEST_P(FASTFixture, FastDetect, testing::Combine(
|
||||
testing::Values(FAST_IMAGES),
|
||||
FastType::all()
|
||||
))
|
||||
{
|
||||
string filename = getDataPath(get<0>(GetParam()));
|
||||
int type = get<1>(GetParam());
|
||||
Mat mframe = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
if (mframe.empty())
|
||||
FAIL() << "Unable to load source image " << filename;
|
||||
|
||||
UMat frame;
|
||||
mframe.copyTo(frame);
|
||||
declare.in(frame);
|
||||
|
||||
Ptr<FeatureDetector> fd = Algorithm::create<FeatureDetector>("Feature2D.FAST");
|
||||
ASSERT_FALSE( fd.empty() );
|
||||
fd->set("threshold", 20);
|
||||
fd->set("nonmaxSuppression", true);
|
||||
fd->set("type", type);
|
||||
vector<KeyPoint> points;
|
||||
|
||||
OCL_TEST_CYCLE() fd->detect(frame, points);
|
||||
|
||||
SANITY_CHECK_KEYPOINTS(points);
|
||||
}
|
||||
|
||||
} // ocl
|
||||
} // cvtest
|
||||
|
||||
#endif // HAVE_OPENCL
|
||||
@@ -0,0 +1,81 @@
|
||||
#include "../perf_precomp.hpp"
|
||||
#include "opencv2/ts/ocl_perf.hpp"
|
||||
#include "../perf_feature2d.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
|
||||
namespace opencv_test {
|
||||
namespace ocl {
|
||||
|
||||
OCL_PERF_TEST_P(feature2d, detect, testing::Combine(Feature2DType::all(), TEST_IMAGES))
|
||||
{
|
||||
Ptr<Feature2D> detector = getFeature2D(get<0>(GetParam()));
|
||||
std::string filename = getDataPath(get<1>(GetParam()));
|
||||
Mat mimg = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
ASSERT_FALSE(mimg.empty());
|
||||
ASSERT_TRUE(detector);
|
||||
|
||||
UMat img, mask;
|
||||
mimg.copyTo(img);
|
||||
declare.in(img);
|
||||
vector<KeyPoint> points;
|
||||
|
||||
OCL_TEST_CYCLE() detector->detect(img, points, mask);
|
||||
|
||||
EXPECT_GT(points.size(), 20u);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
OCL_PERF_TEST_P(feature2d, extract, testing::Combine(testing::Values(DETECTORS_EXTRACTORS), TEST_IMAGES))
|
||||
{
|
||||
Ptr<Feature2D> detector = AKAZE::create();
|
||||
Ptr<Feature2D> extractor = getFeature2D(get<0>(GetParam()));
|
||||
std::string filename = getDataPath(get<1>(GetParam()));
|
||||
Mat mimg = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
ASSERT_FALSE(mimg.empty());
|
||||
ASSERT_TRUE(extractor);
|
||||
|
||||
UMat img, mask;
|
||||
mimg.copyTo(img);
|
||||
declare.in(img);
|
||||
vector<KeyPoint> points;
|
||||
detector->detect(img, points, mask);
|
||||
|
||||
EXPECT_GT(points.size(), 20u);
|
||||
|
||||
UMat descriptors;
|
||||
|
||||
OCL_TEST_CYCLE() extractor->compute(img, points, descriptors);
|
||||
|
||||
EXPECT_EQ((size_t)descriptors.rows, points.size());
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
OCL_PERF_TEST_P(feature2d, detectAndExtract, testing::Combine(testing::Values(DETECTORS_EXTRACTORS), TEST_IMAGES))
|
||||
{
|
||||
Ptr<Feature2D> detector = getFeature2D(get<0>(GetParam()));
|
||||
std::string filename = getDataPath(get<1>(GetParam()));
|
||||
Mat mimg = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
ASSERT_FALSE(mimg.empty());
|
||||
ASSERT_TRUE(detector);
|
||||
|
||||
UMat img, mask;
|
||||
mimg.copyTo(img);
|
||||
declare.in(img);
|
||||
vector<KeyPoint> points;
|
||||
UMat descriptors;
|
||||
|
||||
OCL_TEST_CYCLE() detector->detectAndCompute(img, mask, points, descriptors, false);
|
||||
|
||||
EXPECT_GT(points.size(), 20u);
|
||||
EXPECT_EQ((size_t)descriptors.rows, points.size());
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
} // ocl
|
||||
} // cvtest
|
||||
|
||||
#endif // HAVE_OPENCL
|
||||
@@ -1,86 +0,0 @@
|
||||
#include "../perf_precomp.hpp"
|
||||
#include "opencv2/ts/ocl_perf.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
|
||||
namespace cvtest {
|
||||
namespace ocl {
|
||||
|
||||
typedef ::perf::TestBaseWithParam<std::string> ORBFixture;
|
||||
|
||||
#define ORB_IMAGES OCL_PERF_ENUM("cv/detectors_descriptors_evaluation/images_datasets/leuven/img1.png", "stitching/a3.png")
|
||||
|
||||
OCL_PERF_TEST_P(ORBFixture, ORB_Detect, ORB_IMAGES)
|
||||
{
|
||||
string filename = getDataPath(GetParam());
|
||||
Mat mframe = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
if (mframe.empty())
|
||||
FAIL() << "Unable to load source image " << filename;
|
||||
|
||||
UMat frame, mask;
|
||||
mframe.copyTo(frame);
|
||||
|
||||
declare.in(frame);
|
||||
ORB detector(1500, 1.3f, 1);
|
||||
vector<KeyPoint> points;
|
||||
|
||||
OCL_TEST_CYCLE() detector(frame, mask, points);
|
||||
|
||||
std::sort(points.begin(), points.end(), comparators::KeypointGreater());
|
||||
SANITY_CHECK_KEYPOINTS(points, 1e-5);
|
||||
}
|
||||
|
||||
OCL_PERF_TEST_P(ORBFixture, ORB_Extract, ORB_IMAGES)
|
||||
{
|
||||
string filename = getDataPath(GetParam());
|
||||
Mat mframe = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
if (mframe.empty())
|
||||
FAIL() << "Unable to load source image " << filename;
|
||||
|
||||
UMat mask, frame;
|
||||
mframe.copyTo(frame);
|
||||
|
||||
declare.in(frame);
|
||||
|
||||
ORB detector(1500, 1.3f, 1);
|
||||
vector<KeyPoint> points;
|
||||
detector(frame, mask, points);
|
||||
std::sort(points.begin(), points.end(), comparators::KeypointGreater());
|
||||
|
||||
UMat descriptors;
|
||||
|
||||
OCL_TEST_CYCLE() detector(frame, mask, points, descriptors, true);
|
||||
|
||||
SANITY_CHECK(descriptors);
|
||||
}
|
||||
|
||||
OCL_PERF_TEST_P(ORBFixture, ORB_Full, ORB_IMAGES)
|
||||
{
|
||||
string filename = getDataPath(GetParam());
|
||||
Mat mframe = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
if (mframe.empty())
|
||||
FAIL() << "Unable to load source image " << filename;
|
||||
|
||||
UMat mask, frame;
|
||||
mframe.copyTo(frame);
|
||||
|
||||
declare.in(frame);
|
||||
ORB detector(1500, 1.3f, 1);
|
||||
|
||||
vector<KeyPoint> points;
|
||||
UMat descriptors;
|
||||
|
||||
OCL_TEST_CYCLE() detector(frame, mask, points, descriptors, false);
|
||||
|
||||
::perf::sort(points, descriptors);
|
||||
SANITY_CHECK_KEYPOINTS(points, 1e-5);
|
||||
SANITY_CHECK(descriptors);
|
||||
}
|
||||
|
||||
} // ocl
|
||||
} // cvtest
|
||||
|
||||
#endif // HAVE_OPENCL
|
||||
@@ -1,20 +1,18 @@
|
||||
#include "perf_precomp.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
namespace opencv_test
|
||||
{
|
||||
using namespace perf;
|
||||
using std::tr1::make_tuple;
|
||||
using std::tr1::get;
|
||||
|
||||
CV_ENUM(NormType, NORM_L1, NORM_L2, NORM_L2SQR, NORM_HAMMING, NORM_HAMMING2)
|
||||
|
||||
typedef std::tr1::tuple<NormType, MatType, bool> Norm_Destination_CrossCheck_t;
|
||||
typedef tuple<NormType, MatType, bool> Norm_Destination_CrossCheck_t;
|
||||
typedef perf::TestBaseWithParam<Norm_Destination_CrossCheck_t> Norm_Destination_CrossCheck;
|
||||
|
||||
typedef std::tr1::tuple<NormType, bool> Norm_CrossCheck_t;
|
||||
typedef tuple<NormType, bool> Norm_CrossCheck_t;
|
||||
typedef perf::TestBaseWithParam<Norm_CrossCheck_t> Norm_CrossCheck;
|
||||
|
||||
typedef std::tr1::tuple<MatType, bool> Source_CrossCheck_t;
|
||||
typedef tuple<MatType, bool> Source_CrossCheck_t;
|
||||
typedef perf::TestBaseWithParam<Source_CrossCheck_t> Source_CrossCheck;
|
||||
|
||||
void generateData( Mat& query, Mat& train, const int sourceType );
|
||||
@@ -144,7 +142,7 @@ void generateData( Mat& query, Mat& train, const int sourceType )
|
||||
rng.fill( buf, RNG::UNIFORM, Scalar::all(0), Scalar(3) );
|
||||
buf.convertTo( query, sourceType );
|
||||
|
||||
// Generate train decriptors as follows:
|
||||
// Generate train descriptors as follows:
|
||||
// copy each query descriptor to train set countFactor times
|
||||
// and perturb some one element of the copied descriptors in
|
||||
// in ascending order. General boundaries of the perturbation
|
||||
@@ -165,3 +163,5 @@ void generateData( Mat& query, Mat& train, const int sourceType )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#include "perf_precomp.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using namespace perf;
|
||||
using std::tr1::make_tuple;
|
||||
using std::tr1::get;
|
||||
|
||||
enum { TYPE_5_8 =FastFeatureDetector::TYPE_5_8, TYPE_7_12 = FastFeatureDetector::TYPE_7_12, TYPE_9_16 = FastFeatureDetector::TYPE_9_16 };
|
||||
CV_ENUM(FastType, TYPE_5_8, TYPE_7_12, TYPE_9_16)
|
||||
|
||||
typedef std::tr1::tuple<string, FastType> File_Type_t;
|
||||
typedef perf::TestBaseWithParam<File_Type_t> fast;
|
||||
|
||||
#define FAST_IMAGES \
|
||||
"cv/detectors_descriptors_evaluation/images_datasets/leuven/img1.png",\
|
||||
"stitching/a3.png"
|
||||
|
||||
PERF_TEST_P(fast, detect, testing::Combine(
|
||||
testing::Values(FAST_IMAGES),
|
||||
FastType::all()
|
||||
))
|
||||
{
|
||||
string filename = getDataPath(get<0>(GetParam()));
|
||||
int type = get<1>(GetParam());
|
||||
Mat frame = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
if (frame.empty())
|
||||
FAIL() << "Unable to load source image " << filename;
|
||||
|
||||
declare.in(frame);
|
||||
|
||||
Ptr<FeatureDetector> fd = Algorithm::create<FeatureDetector>("Feature2D.FAST");
|
||||
ASSERT_FALSE( fd.empty() );
|
||||
fd->set("threshold", 20);
|
||||
fd->set("nonmaxSuppression", true);
|
||||
fd->set("type", type);
|
||||
vector<KeyPoint> points;
|
||||
|
||||
TEST_CYCLE() fd->detect(frame, points);
|
||||
|
||||
SANITY_CHECK_KEYPOINTS(points);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "perf_feature2d.hpp"
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
using namespace perf;
|
||||
|
||||
PERF_TEST_P(feature2d, detect, testing::Combine(Feature2DType::all(), TEST_IMAGES))
|
||||
{
|
||||
Ptr<Feature2D> detector = getFeature2D(get<0>(GetParam()));
|
||||
std::string filename = getDataPath(get<1>(GetParam()));
|
||||
Mat img = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(detector);
|
||||
|
||||
declare.in(img);
|
||||
Mat mask;
|
||||
vector<KeyPoint> points;
|
||||
|
||||
TEST_CYCLE() detector->detect(img, points, mask);
|
||||
|
||||
EXPECT_GT(points.size(), 20u);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P(feature2d, extract, testing::Combine(testing::Values(DETECTORS_EXTRACTORS), TEST_IMAGES))
|
||||
{
|
||||
Ptr<Feature2D> detector = AKAZE::create();
|
||||
Ptr<Feature2D> extractor = getFeature2D(get<0>(GetParam()));
|
||||
std::string filename = getDataPath(get<1>(GetParam()));
|
||||
Mat img = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(extractor);
|
||||
|
||||
declare.in(img);
|
||||
Mat mask;
|
||||
vector<KeyPoint> points;
|
||||
detector->detect(img, points, mask);
|
||||
|
||||
EXPECT_GT(points.size(), 20u);
|
||||
|
||||
Mat descriptors;
|
||||
|
||||
TEST_CYCLE() extractor->compute(img, points, descriptors);
|
||||
|
||||
EXPECT_EQ((size_t)descriptors.rows, points.size());
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P(feature2d, detectAndExtract, testing::Combine(testing::Values(DETECTORS_EXTRACTORS), TEST_IMAGES))
|
||||
{
|
||||
Ptr<Feature2D> detector = getFeature2D(get<0>(GetParam()));
|
||||
std::string filename = getDataPath(get<1>(GetParam()));
|
||||
Mat img = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(detector);
|
||||
|
||||
declare.in(img);
|
||||
Mat mask;
|
||||
vector<KeyPoint> points;
|
||||
Mat descriptors;
|
||||
|
||||
TEST_CYCLE() detector->detectAndCompute(img, mask, points, descriptors, false);
|
||||
|
||||
EXPECT_GT(points.size(), 20u);
|
||||
EXPECT_EQ((size_t)descriptors.rows, points.size());
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,87 @@
|
||||
#ifndef __OPENCV_PERF_FEATURE2D_HPP__
|
||||
#define __OPENCV_PERF_FEATURE2D_HPP__
|
||||
|
||||
#include "perf_precomp.hpp"
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
|
||||
/* configuration for tests of detectors/descriptors. shared between ocl and cpu tests. */
|
||||
|
||||
// detectors/descriptors configurations to test
|
||||
#define DETECTORS_ONLY \
|
||||
FAST_DEFAULT, FAST_20_TRUE_TYPE5_8, FAST_20_TRUE_TYPE7_12, FAST_20_TRUE_TYPE9_16, \
|
||||
FAST_20_FALSE_TYPE5_8, FAST_20_FALSE_TYPE7_12, FAST_20_FALSE_TYPE9_16, \
|
||||
\
|
||||
AGAST_DEFAULT, AGAST_5_8, AGAST_7_12d, AGAST_7_12s, AGAST_OAST_9_16, \
|
||||
\
|
||||
MSER_DEFAULT
|
||||
|
||||
#define DETECTORS_EXTRACTORS \
|
||||
ORB_DEFAULT, ORB_1500_13_1, \
|
||||
AKAZE_DEFAULT, AKAZE_DESCRIPTOR_KAZE, \
|
||||
BRISK_DEFAULT, \
|
||||
KAZE_DEFAULT
|
||||
|
||||
#define CV_ENUM_EXPAND(name, ...) CV_ENUM(name, __VA_ARGS__)
|
||||
|
||||
enum Feature2DVals { DETECTORS_ONLY, DETECTORS_EXTRACTORS };
|
||||
CV_ENUM_EXPAND(Feature2DType, DETECTORS_ONLY, DETECTORS_EXTRACTORS)
|
||||
|
||||
typedef tuple<Feature2DType, string> Feature2DType_String_t;
|
||||
typedef perf::TestBaseWithParam<Feature2DType_String_t> feature2d;
|
||||
|
||||
#define TEST_IMAGES testing::Values(\
|
||||
"cv/detectors_descriptors_evaluation/images_datasets/leuven/img1.png",\
|
||||
"stitching/a3.png", \
|
||||
"stitching/s2.jpg")
|
||||
|
||||
static inline Ptr<Feature2D> getFeature2D(Feature2DType type)
|
||||
{
|
||||
switch(type) {
|
||||
case ORB_DEFAULT:
|
||||
return ORB::create();
|
||||
case ORB_1500_13_1:
|
||||
return ORB::create(1500, 1.3f, 1);
|
||||
case FAST_DEFAULT:
|
||||
return FastFeatureDetector::create();
|
||||
case FAST_20_TRUE_TYPE5_8:
|
||||
return FastFeatureDetector::create(20, true, FastFeatureDetector::TYPE_5_8);
|
||||
case FAST_20_TRUE_TYPE7_12:
|
||||
return FastFeatureDetector::create(20, true, FastFeatureDetector::TYPE_7_12);
|
||||
case FAST_20_TRUE_TYPE9_16:
|
||||
return FastFeatureDetector::create(20, true, FastFeatureDetector::TYPE_9_16);
|
||||
case FAST_20_FALSE_TYPE5_8:
|
||||
return FastFeatureDetector::create(20, false, FastFeatureDetector::TYPE_5_8);
|
||||
case FAST_20_FALSE_TYPE7_12:
|
||||
return FastFeatureDetector::create(20, false, FastFeatureDetector::TYPE_7_12);
|
||||
case FAST_20_FALSE_TYPE9_16:
|
||||
return FastFeatureDetector::create(20, false, FastFeatureDetector::TYPE_9_16);
|
||||
case AGAST_DEFAULT:
|
||||
return AgastFeatureDetector::create();
|
||||
case AGAST_5_8:
|
||||
return AgastFeatureDetector::create(70, true, AgastFeatureDetector::AGAST_5_8);
|
||||
case AGAST_7_12d:
|
||||
return AgastFeatureDetector::create(70, true, AgastFeatureDetector::AGAST_7_12d);
|
||||
case AGAST_7_12s:
|
||||
return AgastFeatureDetector::create(70, true, AgastFeatureDetector::AGAST_7_12s);
|
||||
case AGAST_OAST_9_16:
|
||||
return AgastFeatureDetector::create(70, true, AgastFeatureDetector::OAST_9_16);
|
||||
case AKAZE_DEFAULT:
|
||||
return AKAZE::create();
|
||||
case AKAZE_DESCRIPTOR_KAZE:
|
||||
return AKAZE::create(AKAZE::DESCRIPTOR_KAZE);
|
||||
case BRISK_DEFAULT:
|
||||
return BRISK::create();
|
||||
case KAZE_DEFAULT:
|
||||
return KAZE::create();
|
||||
case MSER_DEFAULT:
|
||||
return MSER::create();
|
||||
default:
|
||||
return Ptr<Feature2D>();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // __OPENCV_PERF_FEATURE2D_HPP__
|
||||
@@ -1,77 +0,0 @@
|
||||
#include "perf_precomp.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using namespace perf;
|
||||
using std::tr1::make_tuple;
|
||||
using std::tr1::get;
|
||||
|
||||
typedef perf::TestBaseWithParam<std::string> orb;
|
||||
|
||||
#define ORB_IMAGES \
|
||||
"cv/detectors_descriptors_evaluation/images_datasets/leuven/img1.png",\
|
||||
"stitching/a3.png"
|
||||
|
||||
PERF_TEST_P(orb, detect, testing::Values(ORB_IMAGES))
|
||||
{
|
||||
string filename = getDataPath(GetParam());
|
||||
Mat frame = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
if (frame.empty())
|
||||
FAIL() << "Unable to load source image " << filename;
|
||||
|
||||
Mat mask;
|
||||
declare.in(frame);
|
||||
ORB detector(1500, 1.3f, 1);
|
||||
vector<KeyPoint> points;
|
||||
|
||||
TEST_CYCLE() detector(frame, mask, points);
|
||||
|
||||
sort(points.begin(), points.end(), comparators::KeypointGreater());
|
||||
SANITY_CHECK_KEYPOINTS(points, 1e-5);
|
||||
}
|
||||
|
||||
PERF_TEST_P(orb, extract, testing::Values(ORB_IMAGES))
|
||||
{
|
||||
string filename = getDataPath(GetParam());
|
||||
Mat frame = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
if (frame.empty())
|
||||
FAIL() << "Unable to load source image " << filename;
|
||||
|
||||
Mat mask;
|
||||
declare.in(frame);
|
||||
|
||||
ORB detector(1500, 1.3f, 1);
|
||||
vector<KeyPoint> points;
|
||||
detector(frame, mask, points);
|
||||
sort(points.begin(), points.end(), comparators::KeypointGreater());
|
||||
|
||||
Mat descriptors;
|
||||
|
||||
TEST_CYCLE() detector(frame, mask, points, descriptors, true);
|
||||
|
||||
SANITY_CHECK(descriptors);
|
||||
}
|
||||
|
||||
PERF_TEST_P(orb, full, testing::Values(ORB_IMAGES))
|
||||
{
|
||||
string filename = getDataPath(GetParam());
|
||||
Mat frame = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
if (frame.empty())
|
||||
FAIL() << "Unable to load source image " << filename;
|
||||
|
||||
Mat mask;
|
||||
declare.in(frame);
|
||||
ORB detector(1500, 1.3f, 1);
|
||||
|
||||
vector<KeyPoint> points;
|
||||
Mat descriptors;
|
||||
|
||||
TEST_CYCLE() detector(frame, mask, points, descriptors, false);
|
||||
|
||||
perf::sort(points, descriptors);
|
||||
SANITY_CHECK_KEYPOINTS(points, 1e-5);
|
||||
SANITY_CHECK(descriptors);
|
||||
}
|
||||
@@ -1,20 +1,7 @@
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wmissing-declarations"
|
||||
# if defined __clang__ || defined __APPLE__
|
||||
# pragma GCC diagnostic ignored "-Wmissing-prototypes"
|
||||
# pragma GCC diagnostic ignored "-Wextra"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef __OPENCV_PERF_PRECOMP_HPP__
|
||||
#define __OPENCV_PERF_PRECOMP_HPP__
|
||||
|
||||
#include "opencv2/ts.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/features2d.hpp"
|
||||
|
||||
#ifdef GTEST_CREATE_SHARED_LIBRARY
|
||||
#error no modules except ts should have GTEST_CREATE_SHARED_LIBRARY defined
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,69 @@
|
||||
/* This is AGAST and OAST, an optimal and accelerated corner detector
|
||||
based on the accelerated segment tests
|
||||
Below is the original copyright and the references */
|
||||
|
||||
/*
|
||||
Copyright (C) 2010 Elmar Mair
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
*Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
*Redistributions 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.
|
||||
|
||||
*Neither the name of the University of Cambridge nor the names of
|
||||
its contributors may 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 COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
The references are:
|
||||
* Adaptive and Generic Corner Detection Based on the Accelerated Segment Test,
|
||||
Elmar Mair and Gregory D. Hager and Darius Burschka
|
||||
and Michael Suppa and Gerhard Hirzinger ECCV 2010
|
||||
URL: http://www6.in.tum.de/Main/ResearchAgast
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __OPENCV_FEATURES_2D_AGAST_HPP__
|
||||
#define __OPENCV_FEATURES_2D_AGAST_HPP__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "precomp.hpp"
|
||||
namespace cv
|
||||
{
|
||||
|
||||
#if !(defined __i386__ || defined(_M_IX86) || defined __x86_64__ || defined(_M_X64))
|
||||
int agast_tree_search(const uint32_t table_struct32[], int pixel_[], const unsigned char* const ptr, int threshold);
|
||||
int AGAST_ALL_SCORE(const uchar* ptr, const int pixel[], int threshold, int agasttype);
|
||||
#endif //!(defined __i386__ || defined(_M_IX86) || defined __x86_64__ || defined(_M_X64))
|
||||
|
||||
|
||||
void makeAgastOffsets(int pixel[16], int row_stride, int type);
|
||||
|
||||
template<int type>
|
||||
int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold);
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
+160
-155
@@ -52,22 +52,15 @@ http://www.robesafe.com/personal/pablo.alcantarilla/papers/Alcantarilla13bmvc.pd
|
||||
#include "kaze/AKAZEFeatures.h"
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
namespace cv
|
||||
{
|
||||
AKAZE::AKAZE()
|
||||
: descriptor(DESCRIPTOR_MLDB)
|
||||
, descriptor_channels(3)
|
||||
, descriptor_size(0)
|
||||
, threshold(0.001f)
|
||||
, octaves(4)
|
||||
, sublevels(4)
|
||||
, diffusivity(DIFF_PM_G2)
|
||||
{
|
||||
}
|
||||
using namespace std;
|
||||
|
||||
AKAZE::AKAZE(int _descriptor_type, int _descriptor_size, int _descriptor_channels,
|
||||
class AKAZE_Impl : public AKAZE
|
||||
{
|
||||
public:
|
||||
AKAZE_Impl(int _descriptor_type, int _descriptor_size, int _descriptor_channels,
|
||||
float _threshold, int _octaves, int _sublevels, int _diffusivity)
|
||||
: descriptor(_descriptor_type)
|
||||
, descriptor_channels(_descriptor_channels)
|
||||
@@ -76,173 +69,185 @@ namespace cv
|
||||
, octaves(_octaves)
|
||||
, sublevels(_sublevels)
|
||||
, diffusivity(_diffusivity)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AKAZE::~AKAZE()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// returns the descriptor size in bytes
|
||||
int AKAZE::descriptorSize() const
|
||||
{
|
||||
switch (descriptor)
|
||||
{
|
||||
case cv::DESCRIPTOR_KAZE:
|
||||
case cv::DESCRIPTOR_KAZE_UPRIGHT:
|
||||
return 64;
|
||||
|
||||
case cv::DESCRIPTOR_MLDB:
|
||||
case cv::DESCRIPTOR_MLDB_UPRIGHT:
|
||||
// We use the full length binary descriptor -> 486 bits
|
||||
if (descriptor_size == 0)
|
||||
{
|
||||
int t = (6 + 36 + 120) * descriptor_channels;
|
||||
return (int)ceil(t / 8.);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We use the random bit selection length binary descriptor
|
||||
return (int)ceil(descriptor_size / 8.);
|
||||
}
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// returns the descriptor type
|
||||
int AKAZE::descriptorType() const
|
||||
{
|
||||
switch (descriptor)
|
||||
virtual ~AKAZE_Impl() CV_OVERRIDE
|
||||
{
|
||||
case cv::DESCRIPTOR_KAZE:
|
||||
case cv::DESCRIPTOR_KAZE_UPRIGHT:
|
||||
return CV_32F;
|
||||
|
||||
case cv::DESCRIPTOR_MLDB:
|
||||
case cv::DESCRIPTOR_MLDB_UPRIGHT:
|
||||
return CV_8U;
|
||||
}
|
||||
|
||||
void setDescriptorType(int dtype) CV_OVERRIDE { descriptor = dtype; }
|
||||
int getDescriptorType() const CV_OVERRIDE { return descriptor; }
|
||||
|
||||
void setDescriptorSize(int dsize) CV_OVERRIDE { descriptor_size = dsize; }
|
||||
int getDescriptorSize() const CV_OVERRIDE { return descriptor_size; }
|
||||
|
||||
void setDescriptorChannels(int dch) CV_OVERRIDE { descriptor_channels = dch; }
|
||||
int getDescriptorChannels() const CV_OVERRIDE { return descriptor_channels; }
|
||||
|
||||
void setThreshold(double threshold_) CV_OVERRIDE { threshold = (float)threshold_; }
|
||||
double getThreshold() const CV_OVERRIDE { return threshold; }
|
||||
|
||||
void setNOctaves(int octaves_) CV_OVERRIDE { octaves = octaves_; }
|
||||
int getNOctaves() const CV_OVERRIDE { return octaves; }
|
||||
|
||||
void setNOctaveLayers(int octaveLayers_) CV_OVERRIDE { sublevels = octaveLayers_; }
|
||||
int getNOctaveLayers() const CV_OVERRIDE { return sublevels; }
|
||||
|
||||
void setDiffusivity(int diff_) CV_OVERRIDE { diffusivity = diff_; }
|
||||
int getDiffusivity() const CV_OVERRIDE { return diffusivity; }
|
||||
|
||||
// returns the descriptor size in bytes
|
||||
int descriptorSize() const CV_OVERRIDE
|
||||
{
|
||||
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 divUp(t, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We use the random bit selection length binary descriptor
|
||||
return divUp(descriptor_size, 8);
|
||||
}
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns the default norm type
|
||||
int AKAZE::defaultNorm() const
|
||||
{
|
||||
switch (descriptor)
|
||||
// returns the descriptor type
|
||||
int descriptorType() const CV_OVERRIDE
|
||||
{
|
||||
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;
|
||||
|
||||
AKAZEFeatures impl(options);
|
||||
impl.Create_Nonlinear_Scale_Space(img1_32);
|
||||
|
||||
if (!useProvidedKeypoints)
|
||||
// returns the default norm type
|
||||
int defaultNorm() const CV_OVERRIDE
|
||||
{
|
||||
impl.Feature_Detection(keypoints);
|
||||
switch (descriptor)
|
||||
{
|
||||
case DESCRIPTOR_KAZE:
|
||||
case DESCRIPTOR_KAZE_UPRIGHT:
|
||||
return NORM_L2;
|
||||
|
||||
case DESCRIPTOR_MLDB:
|
||||
case DESCRIPTOR_MLDB_UPRIGHT:
|
||||
return NORM_HAMMING;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mask.empty())
|
||||
void detectAndCompute(InputArray image, InputArray mask,
|
||||
std::vector<KeyPoint>& keypoints,
|
||||
OutputArray descriptors,
|
||||
bool useProvidedKeypoints) CV_OVERRIDE
|
||||
{
|
||||
cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat());
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CV_Assert( ! image.empty() );
|
||||
|
||||
AKAZEOptions options;
|
||||
options.descriptor = descriptor;
|
||||
options.descriptor_channels = descriptor_channels;
|
||||
options.descriptor_size = descriptor_size;
|
||||
options.img_width = image.cols();
|
||||
options.img_height = image.rows();
|
||||
options.dthreshold = threshold;
|
||||
options.omax = octaves;
|
||||
options.nsublevels = sublevels;
|
||||
options.diffusivity = diffusivity;
|
||||
|
||||
AKAZEFeatures impl(options);
|
||||
impl.Create_Nonlinear_Scale_Space(image);
|
||||
|
||||
if (!useProvidedKeypoints)
|
||||
{
|
||||
impl.Feature_Detection(keypoints);
|
||||
}
|
||||
|
||||
if (!mask.empty())
|
||||
{
|
||||
KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat());
|
||||
}
|
||||
|
||||
if(descriptors.needed())
|
||||
{
|
||||
impl.Compute_Descriptors(keypoints, descriptors);
|
||||
|
||||
CV_Assert((descriptors.empty() || descriptors.cols() == descriptorSize()));
|
||||
CV_Assert((descriptors.empty() || (descriptors.type() == descriptorType())));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
AKAZEFeatures impl(options);
|
||||
impl.Create_Nonlinear_Scale_Space(img1_32);
|
||||
impl.Feature_Detection(keypoints);
|
||||
|
||||
if (!mask.empty())
|
||||
void write(FileStorage& fs) const CV_OVERRIDE
|
||||
{
|
||||
cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat());
|
||||
writeFormat(fs);
|
||||
fs << "descriptor" << descriptor;
|
||||
fs << "descriptor_channels" << descriptor_channels;
|
||||
fs << "descriptor_size" << descriptor_size;
|
||||
fs << "threshold" << threshold;
|
||||
fs << "octaves" << octaves;
|
||||
fs << "sublevels" << sublevels;
|
||||
fs << "diffusivity" << diffusivity;
|
||||
}
|
||||
}
|
||||
|
||||
void AKAZE::computeImpl(InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const
|
||||
void read(const FileNode& fn) CV_OVERRIDE
|
||||
{
|
||||
descriptor = (int)fn["descriptor"];
|
||||
descriptor_channels = (int)fn["descriptor_channels"];
|
||||
descriptor_size = (int)fn["descriptor_size"];
|
||||
threshold = (float)fn["threshold"];
|
||||
octaves = (int)fn["octaves"];
|
||||
sublevels = (int)fn["sublevels"];
|
||||
diffusivity = (int)fn["diffusivity"];
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
String AKAZE::getDefaultName() const
|
||||
{
|
||||
return (Feature2D::getDefaultName() + ".AKAZE");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -89,13 +89,11 @@ BOWKMeansTrainer::BOWKMeansTrainer( int _clusterCount, const TermCriteria& _term
|
||||
|
||||
Mat BOWKMeansTrainer::cluster() const
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CV_Assert( !descriptors.empty() );
|
||||
|
||||
int descCount = 0;
|
||||
for( size_t i = 0; i < descriptors.size(); i++ )
|
||||
descCount += descriptors[i].rows;
|
||||
|
||||
Mat mergedDescriptors( descCount, descriptors[0].cols, descriptors[0].type() );
|
||||
Mat mergedDescriptors( descriptorsCount(), descriptors[0].cols, descriptors[0].type() );
|
||||
for( size_t i = 0, start = 0; i < descriptors.size(); i++ )
|
||||
{
|
||||
Mat submut = mergedDescriptors.rowRange((int)start, (int)(start + descriptors[i].rows));
|
||||
@@ -110,6 +108,8 @@ BOWKMeansTrainer::~BOWKMeansTrainer()
|
||||
|
||||
Mat BOWKMeansTrainer::cluster( const Mat& _descriptors ) const
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
Mat labels, vocabulary;
|
||||
kmeans( _descriptors, clusterCount, labels, termcrit, attempts, flags, vocabulary );
|
||||
return vocabulary;
|
||||
@@ -143,6 +143,8 @@ const Mat& BOWImgDescriptorExtractor::getVocabulary() const
|
||||
void BOWImgDescriptorExtractor::compute( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray imgDescriptor,
|
||||
std::vector<std::vector<int> >* pointIdxsOfClusters, Mat* descriptors )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
imgDescriptor.release();
|
||||
|
||||
if( keypoints.empty() )
|
||||
@@ -172,7 +174,10 @@ int BOWImgDescriptorExtractor::descriptorType() const
|
||||
|
||||
void BOWImgDescriptorExtractor::compute( InputArray keypointDescriptors, OutputArray _imgDescriptor, std::vector<std::vector<int> >* pointIdxsOfClusters )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CV_Assert( !vocabulary.empty() );
|
||||
CV_Assert(!keypointDescriptors.empty());
|
||||
|
||||
int clusterCount = descriptorSize(); // = vocabulary.rows
|
||||
|
||||
@@ -192,7 +197,7 @@ void BOWImgDescriptorExtractor::compute( InputArray keypointDescriptors, OutputA
|
||||
|
||||
Mat imgDescriptor = _imgDescriptor.getMat();
|
||||
|
||||
float *dptr = (float*)imgDescriptor.data;
|
||||
float *dptr = imgDescriptor.ptr<float>();
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
int queryIdx = matches[i].queryIdx;
|
||||
|
||||
@@ -44,18 +44,38 @@
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
|
||||
// Requires CMake flag: DEBUG_opencv_features2d=ON
|
||||
//#define DEBUG_BLOB_DETECTOR
|
||||
|
||||
#ifdef DEBUG_BLOB_DETECTOR
|
||||
# include "opencv2/opencv_modules.hpp"
|
||||
# ifdef HAVE_OPENCV_HIGHGUI
|
||||
# include "opencv2/highgui.hpp"
|
||||
# else
|
||||
# undef DEBUG_BLOB_DETECTOR
|
||||
# endif
|
||||
#include "opencv2/highgui.hpp"
|
||||
#endif
|
||||
|
||||
using namespace cv;
|
||||
namespace cv
|
||||
{
|
||||
|
||||
class CV_EXPORTS_W SimpleBlobDetectorImpl : public SimpleBlobDetector
|
||||
{
|
||||
public:
|
||||
|
||||
explicit SimpleBlobDetectorImpl(const SimpleBlobDetector::Params ¶meters = SimpleBlobDetector::Params());
|
||||
|
||||
virtual void read( const FileNode& fn ) CV_OVERRIDE;
|
||||
virtual void write( FileStorage& fs ) const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
struct CV_EXPORTS Center
|
||||
{
|
||||
Point2d location;
|
||||
double radius;
|
||||
double confidence;
|
||||
};
|
||||
|
||||
virtual void detect( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) CV_OVERRIDE;
|
||||
virtual void findBlobs(InputArray image, InputArray binaryImage, std::vector<Center> ¢ers) const;
|
||||
|
||||
Params params;
|
||||
};
|
||||
|
||||
/*
|
||||
* SimpleBlobDetector
|
||||
@@ -148,46 +168,48 @@ void SimpleBlobDetector::Params::write(cv::FileStorage& fs) 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
|
||||
{
|
||||
writeFormat(fs);
|
||||
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
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
Mat image = _image.getMat(), binaryImage = _binaryImage.getMat();
|
||||
(void)image;
|
||||
CV_UNUSED(image);
|
||||
centers.clear();
|
||||
|
||||
std::vector < std::vector<Point> > contours;
|
||||
Mat tmpBinaryImage = binaryImage.clone();
|
||||
findContours(tmpBinaryImage, contours, RETR_LIST, CHAIN_APPROX_NONE);
|
||||
findContours(binaryImage, contours, RETR_LIST, CHAIN_APPROX_NONE);
|
||||
|
||||
#ifdef DEBUG_BLOB_DETECTOR
|
||||
// Mat keypointsImage;
|
||||
// cvtColor( binaryImage, keypointsImage, CV_GRAY2RGB );
|
||||
//
|
||||
// Mat contoursImage;
|
||||
// cvtColor( binaryImage, contoursImage, CV_GRAY2RGB );
|
||||
// drawContours( contoursImage, contours, -1, Scalar(0,255,0) );
|
||||
// imshow("contours", contoursImage );
|
||||
Mat keypointsImage;
|
||||
cvtColor(binaryImage, keypointsImage, COLOR_GRAY2RGB);
|
||||
|
||||
Mat contoursImage;
|
||||
cvtColor(binaryImage, contoursImage, COLOR_GRAY2RGB);
|
||||
drawContours( contoursImage, contours, -1, Scalar(0,255,0) );
|
||||
imshow("contours", contoursImage );
|
||||
#endif
|
||||
|
||||
for (size_t contourIdx = 0; contourIdx < contours.size(); contourIdx++)
|
||||
{
|
||||
Center center;
|
||||
center.confidence = 1;
|
||||
Moments moms = moments(Mat(contours[contourIdx]));
|
||||
Moments moms = moments(contours[contourIdx]);
|
||||
if (params.filterByArea)
|
||||
{
|
||||
double area = moms.m00;
|
||||
@@ -198,7 +220,7 @@ void SimpleBlobDetector::findBlobs(InputArray _image, InputArray _binaryImage, s
|
||||
if (params.filterByCircularity)
|
||||
{
|
||||
double area = moms.m00;
|
||||
double perimeter = arcLength(Mat(contours[contourIdx]), true);
|
||||
double perimeter = arcLength(contours[contourIdx], true);
|
||||
double ratio = 4 * CV_PI * area / (perimeter * perimeter);
|
||||
if (ratio < params.minCircularity || ratio >= params.maxCircularity)
|
||||
continue;
|
||||
@@ -234,14 +256,18 @@ void SimpleBlobDetector::findBlobs(InputArray _image, InputArray _binaryImage, s
|
||||
if (params.filterByConvexity)
|
||||
{
|
||||
std::vector < Point > hull;
|
||||
convexHull(Mat(contours[contourIdx]), hull);
|
||||
double area = contourArea(Mat(contours[contourIdx]));
|
||||
double hullArea = contourArea(Mat(hull));
|
||||
convexHull(contours[contourIdx], hull);
|
||||
double area = contourArea(contours[contourIdx]);
|
||||
double hullArea = contourArea(hull);
|
||||
if (fabs(hullArea) < DBL_EPSILON)
|
||||
continue;
|
||||
double ratio = area / hullArea;
|
||||
if (ratio < params.minConvexity || ratio >= params.maxConvexity)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(moms.m00 == 0.0)
|
||||
continue;
|
||||
center.location = Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00);
|
||||
|
||||
if (params.filterByColor)
|
||||
@@ -262,31 +288,35 @@ void SimpleBlobDetector::findBlobs(InputArray _image, InputArray _binaryImage, s
|
||||
center.radius = (dists[(dists.size() - 1) / 2] + dists[dists.size() / 2]) / 2.;
|
||||
}
|
||||
|
||||
if(moms.m00 == 0.0)
|
||||
continue;
|
||||
centers.push_back(center);
|
||||
|
||||
|
||||
#ifdef DEBUG_BLOB_DETECTOR
|
||||
// circle( keypointsImage, center.location, 1, Scalar(0,0,255), 1 );
|
||||
circle( keypointsImage, center.location, 1, Scalar(0,0,255), 1 );
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_BLOB_DETECTOR
|
||||
// imshow("bk", keypointsImage );
|
||||
// waitKey();
|
||||
imshow("bk", keypointsImage );
|
||||
waitKey();
|
||||
#endif
|
||||
}
|
||||
|
||||
void SimpleBlobDetector::detectImpl(InputArray image, std::vector<cv::KeyPoint>& keypoints, InputArray) const
|
||||
void SimpleBlobDetectorImpl::detect(InputArray image, std::vector<cv::KeyPoint>& keypoints, InputArray mask)
|
||||
{
|
||||
//TODO: support mask
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
keypoints.clear();
|
||||
CV_Assert(params.minRepeatability != 0);
|
||||
Mat grayscaleImage;
|
||||
if (image.channels() == 3)
|
||||
if (image.channels() == 3 || image.channels() == 4)
|
||||
cvtColor(image, grayscaleImage, COLOR_BGR2GRAY);
|
||||
else
|
||||
grayscaleImage = image.getMat();
|
||||
|
||||
if (grayscaleImage.type() != CV_8UC1) {
|
||||
CV_Error(Error::StsUnsupportedFormat, "Blob detector only supports 8-bit images!");
|
||||
}
|
||||
|
||||
std::vector < std::vector<Center> > centers;
|
||||
for (double thresh = params.minThreshold; thresh < params.maxThreshold; thresh += params.thresholdStep)
|
||||
{
|
||||
@@ -308,7 +338,7 @@ void SimpleBlobDetector::detectImpl(InputArray image, std::vector<cv::KeyPoint>&
|
||||
centers[j].push_back(curCenters[i]);
|
||||
|
||||
size_t k = centers[j].size() - 1;
|
||||
while( k > 0 && centers[j][k].radius < centers[j][k-1].radius )
|
||||
while( k > 0 && curCenters[i].radius < centers[j][k-1].radius )
|
||||
{
|
||||
centers[j][k] = centers[j][k-1];
|
||||
k--;
|
||||
@@ -339,4 +369,21 @@ void SimpleBlobDetector::detectImpl(InputArray image, std::vector<cv::KeyPoint>&
|
||||
KeyPoint kpt(sumPoint, (float)(centers[i][centers[i].size() / 2].radius) * 2.0f);
|
||||
keypoints.push_back(kpt);
|
||||
}
|
||||
|
||||
if (!mask.empty())
|
||||
{
|
||||
KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat());
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<SimpleBlobDetector> SimpleBlobDetector::create(const SimpleBlobDetector::Params& params)
|
||||
{
|
||||
return makePtr<SimpleBlobDetectorImpl>(params);
|
||||
}
|
||||
|
||||
String SimpleBlobDetector::getDefaultName() const
|
||||
{
|
||||
return (Feature2D::getDefaultName() + ".SimpleBlobDetector");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009-2010, 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"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
inline int smoothedSum(const Mat& sum, const KeyPoint& pt, int y, int x)
|
||||
{
|
||||
static const int HALF_KERNEL = BriefDescriptorExtractor::KERNEL_SIZE / 2;
|
||||
|
||||
int img_y = (int)(pt.pt.y + 0.5) + y;
|
||||
int img_x = (int)(pt.pt.x + 0.5) + x;
|
||||
return sum.at<int>(img_y + HALF_KERNEL + 1, img_x + HALF_KERNEL + 1)
|
||||
- sum.at<int>(img_y + HALF_KERNEL + 1, img_x - HALF_KERNEL)
|
||||
- sum.at<int>(img_y - HALF_KERNEL, img_x + HALF_KERNEL + 1)
|
||||
+ sum.at<int>(img_y - HALF_KERNEL, img_x - HALF_KERNEL);
|
||||
}
|
||||
|
||||
static void pixelTests16(InputArray _sum, const std::vector<KeyPoint>& keypoints, OutputArray _descriptors)
|
||||
{
|
||||
Mat sum = _sum.getMat(), descriptors = _descriptors.getMat();
|
||||
for (int i = 0; i < (int)keypoints.size(); ++i)
|
||||
{
|
||||
uchar* desc = descriptors.ptr(i);
|
||||
const KeyPoint& pt = keypoints[i];
|
||||
#include "generated_16.i"
|
||||
}
|
||||
}
|
||||
|
||||
static void pixelTests32(InputArray _sum, const std::vector<KeyPoint>& keypoints, OutputArray _descriptors)
|
||||
{
|
||||
Mat sum = _sum.getMat(), descriptors = _descriptors.getMat();
|
||||
for (int i = 0; i < (int)keypoints.size(); ++i)
|
||||
{
|
||||
uchar* desc = descriptors.ptr(i);
|
||||
const KeyPoint& pt = keypoints[i];
|
||||
|
||||
#include "generated_32.i"
|
||||
}
|
||||
}
|
||||
|
||||
static void pixelTests64(InputArray _sum, const std::vector<KeyPoint>& keypoints, OutputArray _descriptors)
|
||||
{
|
||||
Mat sum = _sum.getMat(), descriptors = _descriptors.getMat();
|
||||
for (int i = 0; i < (int)keypoints.size(); ++i)
|
||||
{
|
||||
uchar* desc = descriptors.ptr(i);
|
||||
const KeyPoint& pt = keypoints[i];
|
||||
|
||||
#include "generated_64.i"
|
||||
}
|
||||
}
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
BriefDescriptorExtractor::BriefDescriptorExtractor(int bytes) :
|
||||
bytes_(bytes), test_fn_(NULL)
|
||||
{
|
||||
switch (bytes)
|
||||
{
|
||||
case 16:
|
||||
test_fn_ = pixelTests16;
|
||||
break;
|
||||
case 32:
|
||||
test_fn_ = pixelTests32;
|
||||
break;
|
||||
case 64:
|
||||
test_fn_ = pixelTests64;
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "bytes must be 16, 32, or 64");
|
||||
}
|
||||
}
|
||||
|
||||
int BriefDescriptorExtractor::descriptorSize() const
|
||||
{
|
||||
return bytes_;
|
||||
}
|
||||
|
||||
int BriefDescriptorExtractor::descriptorType() const
|
||||
{
|
||||
return CV_8UC1;
|
||||
}
|
||||
|
||||
int BriefDescriptorExtractor::defaultNorm() const
|
||||
{
|
||||
return NORM_HAMMING;
|
||||
}
|
||||
|
||||
void BriefDescriptorExtractor::read( const FileNode& fn)
|
||||
{
|
||||
int dSize = fn["descriptorSize"];
|
||||
switch (dSize)
|
||||
{
|
||||
case 16:
|
||||
test_fn_ = pixelTests16;
|
||||
break;
|
||||
case 32:
|
||||
test_fn_ = pixelTests32;
|
||||
break;
|
||||
case 64:
|
||||
test_fn_ = pixelTests64;
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "descriptorSize must be 16, 32, or 64");
|
||||
}
|
||||
bytes_ = dSize;
|
||||
}
|
||||
|
||||
void BriefDescriptorExtractor::write( FileStorage& fs) const
|
||||
{
|
||||
fs << "descriptorSize" << bytes_;
|
||||
}
|
||||
|
||||
void BriefDescriptorExtractor::computeImpl(InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const
|
||||
{
|
||||
// Construct integral image for fast smoothing (box filter)
|
||||
Mat sum;
|
||||
|
||||
Mat grayImage = image.getMat();
|
||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, COLOR_BGR2GRAY );
|
||||
|
||||
///TODO allow the user to pass in a precomputed integral image
|
||||
//if(image.type() == CV_32S)
|
||||
// sum = image;
|
||||
//else
|
||||
|
||||
integral( grayImage, sum, CV_32S);
|
||||
|
||||
//Remove keypoints very close to the border
|
||||
KeyPointsFilter::runByImageBorder(keypoints, image.size(), PATCH_SIZE/2 + KERNEL_SIZE/2);
|
||||
|
||||
descriptors.create((int)keypoints.size(), bytes_, CV_8U);
|
||||
descriptors.setTo(Scalar::all(0));
|
||||
test_fn_(sum, keypoints, descriptors);
|
||||
}
|
||||
|
||||
} // namespace cv
|
||||
@@ -42,23 +42,120 @@
|
||||
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>
|
||||
|
||||
#include "fast_score.hpp"
|
||||
#include "agast_score.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
class BRISK_Impl CV_FINAL : public BRISK
|
||||
{
|
||||
public:
|
||||
explicit BRISK_Impl(int thresh=30, int octaves=3, float patternScale=1.0f);
|
||||
// custom setup
|
||||
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>());
|
||||
|
||||
explicit BRISK_Impl(int thresh, int octaves, 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 CV_OVERRIDE
|
||||
{
|
||||
return strings_;
|
||||
}
|
||||
|
||||
int descriptorType() const CV_OVERRIDE
|
||||
{
|
||||
return CV_8U;
|
||||
}
|
||||
|
||||
int defaultNorm() const CV_OVERRIDE
|
||||
{
|
||||
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(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>());
|
||||
|
||||
void detectAndCompute( InputArray image, InputArray mask,
|
||||
CV_OUT std::vector<KeyPoint>& keypoints,
|
||||
OutputArray descriptors,
|
||||
bool useProvidedKeypoints ) CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
void computeKeypointsNoOrientation(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const;
|
||||
void computeDescriptorsAndOrOrientation(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints,
|
||||
OutputArray descriptors, bool doDescriptors, bool doOrientation,
|
||||
bool useProvidedKeypoints) const;
|
||||
|
||||
// Feature parameters
|
||||
CV_PROP_RW int threshold;
|
||||
CV_PROP_RW int octaves;
|
||||
|
||||
// some helper structures for the Brisk pattern representation
|
||||
struct BriskPatternPoint{
|
||||
float x; // x coordinate relative to center
|
||||
float y; // x coordinate relative to center
|
||||
float sigma; // Gaussian smoothing sigma
|
||||
};
|
||||
struct BriskShortPair{
|
||||
unsigned int i; // index of the first pattern point
|
||||
unsigned int j; // index of other pattern point
|
||||
};
|
||||
struct BriskLongPair{
|
||||
unsigned int i; // index of the first pattern point
|
||||
unsigned int j; // index of other pattern point
|
||||
int weighted_dx; // 1024.0/dx
|
||||
int weighted_dy; // 1024.0/dy
|
||||
};
|
||||
inline int 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;
|
||||
// pattern properties
|
||||
BriskPatternPoint* patternPoints_; //[i][rotation][scale]
|
||||
unsigned int points_; // total number of collocation points
|
||||
float* scaleList_; // lists the scaling per scale index [scale]
|
||||
unsigned int* sizeList_; // lists the total pattern size per scale index [scale]
|
||||
static const unsigned int scales_; // scales discretization
|
||||
static const float scalerange_; // span of sizes 40->4 Octaves - else, this needs to be adjusted...
|
||||
static const unsigned int n_rot_; // discretization of the rotation look-up
|
||||
|
||||
// pairs
|
||||
int strings_; // number of uchars the descriptor consists of
|
||||
float dMax_; // short pair maximum distance
|
||||
float dMin_; // long pair maximum distance
|
||||
BriskShortPair* shortPairs_; // d<_dMax
|
||||
BriskLongPair* longPairs_; // d>_dMin
|
||||
unsigned int noShortPairs_; // number of shortParis
|
||||
unsigned int noLongPairs_; // number of longParis
|
||||
|
||||
// general
|
||||
static const float basicSize_;
|
||||
|
||||
private:
|
||||
BRISK_Impl(const BRISK_Impl &); // copy disabled
|
||||
BRISK_Impl& operator=(const BRISK_Impl &); // assign disabled
|
||||
};
|
||||
|
||||
|
||||
// a layer in the Brisk detector pyramid
|
||||
class CV_EXPORTS BriskLayer
|
||||
class BriskLayer
|
||||
{
|
||||
public:
|
||||
// constructor arguments
|
||||
struct CV_EXPORTS CommonParams
|
||||
struct CommonParams
|
||||
{
|
||||
static const int HALFSAMPLE = 0;
|
||||
static const int TWOTHIRDSAMPLE = 1;
|
||||
@@ -68,7 +165,7 @@ public:
|
||||
// derive a layer
|
||||
BriskLayer(const BriskLayer& layer, int mode);
|
||||
|
||||
// Fast/Agast without non-max suppression
|
||||
// Agast without non-max suppression
|
||||
void
|
||||
getAgastPoints(int threshold, std::vector<cv::KeyPoint>& keypoints);
|
||||
|
||||
@@ -115,18 +212,18 @@ private:
|
||||
value(const cv::Mat& mat, float xf, float yf, float scale) const;
|
||||
// the image
|
||||
cv::Mat img_;
|
||||
// its Fast scores
|
||||
// its Agast scores
|
||||
cv::Mat_<uchar> scores_;
|
||||
// coordinate transformation
|
||||
float scale_;
|
||||
float offset_;
|
||||
// agast
|
||||
cv::Ptr<cv::FastFeatureDetector> fast_9_16_;
|
||||
cv::Ptr<cv::AgastFeatureDetector> oast_9_16_;
|
||||
int pixel_5_8_[25];
|
||||
int pixel_9_16_[25];
|
||||
};
|
||||
|
||||
class CV_EXPORTS BriskScaleSpace
|
||||
class BriskScaleSpace
|
||||
{
|
||||
public:
|
||||
// construct telling the octaves number:
|
||||
@@ -183,16 +280,16 @@ protected:
|
||||
static const float basicSize_;
|
||||
};
|
||||
|
||||
const float BRISK::basicSize_ = 12.0f;
|
||||
const unsigned int BRISK::scales_ = 64;
|
||||
const float BRISK::scalerange_ = 30.f; // 40->4 Octaves - else, this needs to be adjusted...
|
||||
const unsigned int BRISK::n_rot_ = 1024; // discretization of the rotation look-up
|
||||
const float BRISK_Impl::basicSize_ = 12.0f;
|
||||
const unsigned int BRISK_Impl::scales_ = 64;
|
||||
const float BRISK_Impl::scalerange_ = 30.f; // 40->4 Octaves - else, this needs to be adjusted...
|
||||
const unsigned int BRISK_Impl::n_rot_ = 1024; // discretization of the rotation look-up
|
||||
|
||||
const float BriskScaleSpace::safetyFactor_ = 1.0f;
|
||||
const float BriskScaleSpace::basicSize_ = 12.0f;
|
||||
|
||||
// constructors
|
||||
BRISK::BRISK(int thresh, int octaves_in, float patternScale)
|
||||
BRISK_Impl::BRISK_Impl(int thresh, int octaves_in, float patternScale)
|
||||
{
|
||||
threshold = thresh;
|
||||
octaves = octaves_in;
|
||||
@@ -218,21 +315,37 @@ BRISK::BRISK(int thresh, int octaves_in, float patternScale)
|
||||
nList[4] = 20;
|
||||
|
||||
generateKernel(rList, nList, (float)(5.85 * patternScale), (float)(8.2 * patternScale));
|
||||
|
||||
}
|
||||
BRISK::BRISK(std::vector<float> &radiusList, std::vector<int> &numberList, float dMax, float dMin,
|
||||
std::vector<int> indexChange)
|
||||
|
||||
BRISK_Impl::BRISK_Impl(const std::vector<float> &radiusList,
|
||||
const std::vector<int> &numberList,
|
||||
float dMax, float dMin,
|
||||
const std::vector<int> indexChange)
|
||||
{
|
||||
generateKernel(radiusList, numberList, dMax, dMin, indexChange);
|
||||
threshold = 20;
|
||||
octaves = 3;
|
||||
}
|
||||
|
||||
void
|
||||
BRISK::generateKernel(std::vector<float> &radiusList, std::vector<int> &numberList, float dMax,
|
||||
float dMin, std::vector<int> indexChange)
|
||||
BRISK_Impl::BRISK_Impl(int thresh,
|
||||
int octaves_in,
|
||||
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 = thresh;
|
||||
octaves = octaves_in;
|
||||
}
|
||||
|
||||
void
|
||||
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;
|
||||
|
||||
@@ -354,7 +467,7 @@ BRISK::generateKernel(std::vector<float> &radiusList, std::vector<int> &numberLi
|
||||
|
||||
// simple alternative:
|
||||
inline int
|
||||
BRISK::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const float key_x,
|
||||
BRISK_Impl::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const float key_x,
|
||||
const float key_y, const unsigned int scale, const unsigned int rot,
|
||||
const unsigned int point) const
|
||||
{
|
||||
@@ -393,6 +506,7 @@ BRISK::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const fl
|
||||
// scaling:
|
||||
const int scaling = (int)(4194304.0 / area);
|
||||
const int scaling2 = int(float(scaling) * area / 1024.0);
|
||||
CV_Assert(scaling2 != 0);
|
||||
|
||||
// the integral image is larger:
|
||||
const int integralcols = imagecols + 1;
|
||||
@@ -427,7 +541,7 @@ BRISK::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const fl
|
||||
if (dx + dy > 2)
|
||||
{
|
||||
// now the calculation:
|
||||
const uchar* ptr = image.data + x_left + imagecols * y_top;
|
||||
const uchar* ptr = image.ptr() + x_left + imagecols * y_top;
|
||||
// first the corners:
|
||||
ret_val = A * int(*ptr);
|
||||
ptr += dx + 1;
|
||||
@@ -438,7 +552,7 @@ BRISK::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const fl
|
||||
ret_val += D * int(*ptr);
|
||||
|
||||
// next the edges:
|
||||
int* ptr_integral = (int*) integral.data + x_left + integralcols * y_top + 1;
|
||||
const int* ptr_integral = integral.ptr<int>() + x_left + integralcols * y_top + 1;
|
||||
// find a simple path through the different surface corners
|
||||
const int tmp1 = (*ptr_integral);
|
||||
ptr_integral += dx;
|
||||
@@ -475,7 +589,7 @@ BRISK::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const fl
|
||||
}
|
||||
|
||||
// now the calculation:
|
||||
const uchar* ptr = image.data + x_left + imagecols * y_top;
|
||||
const uchar* ptr = image.ptr() + x_left + imagecols * y_top;
|
||||
// first row:
|
||||
ret_val = A * int(*ptr);
|
||||
ptr++;
|
||||
@@ -521,12 +635,10 @@ RoiPredicate(const float minX, const float minY, const float maxX, const float m
|
||||
|
||||
// computes the descriptor
|
||||
void
|
||||
BRISK::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
|
||||
OutputArray _descriptors, bool useProvidedKeypoints) const
|
||||
BRISK_Impl::detectAndCompute( InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
|
||||
OutputArray _descriptors, bool useProvidedKeypoints)
|
||||
{
|
||||
bool doOrientation=true;
|
||||
if (useProvidedKeypoints)
|
||||
doOrientation = false;
|
||||
|
||||
// If the user specified cv::noArray(), this will yield false. Otherwise it will return true.
|
||||
bool doDescriptors = _descriptors.needed();
|
||||
@@ -536,7 +648,7 @@ BRISK::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>& k
|
||||
}
|
||||
|
||||
void
|
||||
BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
|
||||
BRISK_Impl::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
|
||||
OutputArray _descriptors, bool doDescriptors, bool doOrientation,
|
||||
bool useProvidedKeypoints) const
|
||||
{
|
||||
@@ -607,12 +719,11 @@ BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, s
|
||||
int t2;
|
||||
|
||||
// the feature orientation
|
||||
const uchar* ptr = descriptors.data;
|
||||
const uchar* ptr = descriptors.ptr();
|
||||
for (size_t k = 0; k < ksize; k++)
|
||||
{
|
||||
cv::KeyPoint& kp = keypoints[k];
|
||||
const int& scale = kscales[k];
|
||||
int* pvalues = _values;
|
||||
const float& x = kp.pt.x;
|
||||
const float& y = kp.pt.y;
|
||||
|
||||
@@ -621,7 +732,7 @@ BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, s
|
||||
// get the gray values in the unrotated pattern
|
||||
for (unsigned int i = 0; i < points_; i++)
|
||||
{
|
||||
*(pvalues++) = smoothedIntensity(image, _integral, x, y, scale, 0, i);
|
||||
_values[i] = smoothedIntensity(image, _integral, x, y, scale, 0, i);
|
||||
}
|
||||
|
||||
int direction0 = 0;
|
||||
@@ -630,6 +741,7 @@ BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, s
|
||||
const BriskLongPair* max = longPairs_ + noLongPairs_;
|
||||
for (BriskLongPair* iter = longPairs_; iter < max; ++iter)
|
||||
{
|
||||
CV_Assert(iter->i < points_ && iter->j < points_);
|
||||
t1 = *(_values + iter->i);
|
||||
t2 = *(_values + iter->j);
|
||||
const int delta_t = (t1 - t2);
|
||||
@@ -640,8 +752,12 @@ BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, s
|
||||
direction1 += tmp1;
|
||||
}
|
||||
kp.angle = (float)(atan2((float) direction1, (float) direction0) / CV_PI * 180.0);
|
||||
if (kp.angle < 0)
|
||||
kp.angle += 360.f;
|
||||
|
||||
if (!doDescriptors)
|
||||
{
|
||||
if (kp.angle < 0)
|
||||
kp.angle += 360.f;
|
||||
}
|
||||
}
|
||||
|
||||
if (!doDescriptors)
|
||||
@@ -650,7 +766,7 @@ BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, s
|
||||
int theta;
|
||||
if (kp.angle==-1)
|
||||
{
|
||||
// don't compute the gradient direction, just assign a rotation of 0°
|
||||
// don't compute the gradient direction, just assign a rotation of 0
|
||||
theta = 0;
|
||||
}
|
||||
else
|
||||
@@ -662,16 +778,18 @@ BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, s
|
||||
theta -= n_rot_;
|
||||
}
|
||||
|
||||
if (kp.angle < 0)
|
||||
kp.angle += 360.f;
|
||||
|
||||
// now also extract the stuff for the actual direction:
|
||||
// let us compute the smoothed values
|
||||
int shifter = 0;
|
||||
|
||||
//unsigned int mean=0;
|
||||
pvalues = _values;
|
||||
// get the gray values in the rotated pattern
|
||||
for (unsigned int i = 0; i < points_; i++)
|
||||
{
|
||||
*(pvalues++) = smoothedIntensity(image, _integral, x, y, scale, theta, i);
|
||||
_values[i] = smoothedIntensity(image, _integral, x, y, scale, theta, i);
|
||||
}
|
||||
|
||||
// now iterate through all the pairings
|
||||
@@ -679,6 +797,7 @@ BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, s
|
||||
const BriskShortPair* max = shortPairs_ + noShortPairs_;
|
||||
for (BriskShortPair* iter = shortPairs_; iter < max; ++iter)
|
||||
{
|
||||
CV_Assert(iter->i < points_ && iter->j < points_);
|
||||
t1 = *(_values + iter->i);
|
||||
t2 = *(_values + iter->j);
|
||||
if (t1 > t2)
|
||||
@@ -702,25 +821,8 @@ BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, s
|
||||
delete[] _values;
|
||||
}
|
||||
|
||||
int
|
||||
BRISK::descriptorSize() const
|
||||
{
|
||||
return strings_;
|
||||
}
|
||||
|
||||
int
|
||||
BRISK::descriptorType() const
|
||||
{
|
||||
return CV_8U;
|
||||
}
|
||||
|
||||
int
|
||||
BRISK::defaultNorm() const
|
||||
{
|
||||
return NORM_HAMMING;
|
||||
}
|
||||
|
||||
BRISK::~BRISK()
|
||||
BRISK_Impl::~BRISK_Impl()
|
||||
{
|
||||
delete[] patternPoints_;
|
||||
delete[] shortPairs_;
|
||||
@@ -730,14 +832,7 @@ BRISK::~BRISK()
|
||||
}
|
||||
|
||||
void
|
||||
BRISK::operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const
|
||||
{
|
||||
computeKeypointsNoOrientation(image, mask, keypoints);
|
||||
computeDescriptorsAndOrOrientation(image, mask, keypoints, cv::noArray(), false, true, true);
|
||||
}
|
||||
|
||||
void
|
||||
BRISK::computeKeypointsNoOrientation(InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints) const
|
||||
BRISK_Impl::computeKeypointsNoOrientation(InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints) const
|
||||
{
|
||||
Mat image = _image.getMat(), mask = _mask.getMat();
|
||||
if( image.type() != CV_8UC1 )
|
||||
@@ -748,20 +843,7 @@ BRISK::computeKeypointsNoOrientation(InputArray _image, InputArray _mask, std::v
|
||||
briskScaleSpace.getKeypoints(threshold, keypoints);
|
||||
|
||||
// remove invalid points
|
||||
removeInvalidPoints(mask, keypoints);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BRISK::detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const
|
||||
{
|
||||
(*this)(image.getMat(), mask.getMat(), keypoints);
|
||||
}
|
||||
|
||||
void
|
||||
BRISK::computeImpl( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const
|
||||
{
|
||||
(*this)(image, Mat(), keypoints, descriptors, true);
|
||||
KeyPointsFilter::runByPixelsMask(keypoints, mask);
|
||||
}
|
||||
|
||||
// construct telling the octaves number:
|
||||
@@ -811,7 +893,7 @@ BriskScaleSpace::getKeypoints(const int threshold_, std::vector<cv::KeyPoint>& k
|
||||
std::vector<std::vector<cv::KeyPoint> > agastPoints;
|
||||
agastPoints.resize(layers_);
|
||||
|
||||
// go through the octaves and intra layers and calculate fast corner scores:
|
||||
// go through the octaves and intra layers and calculate agast corner scores:
|
||||
for (int i = 0; i < layers_; i++)
|
||||
{
|
||||
// call OAST16_9 without nms
|
||||
@@ -1070,7 +1152,7 @@ BriskScaleSpace::isMax2D(const int layer, const int x_layer, const int y_layer)
|
||||
{
|
||||
const cv::Mat& scores = pyramid_[layer].scores();
|
||||
const int scorescols = scores.cols;
|
||||
const uchar* data = scores.data + y_layer * scorescols + x_layer;
|
||||
const uchar* data = scores.ptr() + y_layer * scorescols + x_layer;
|
||||
// decision tree:
|
||||
const uchar center = (*data);
|
||||
data--;
|
||||
@@ -1154,11 +1236,10 @@ BriskScaleSpace::isMax2D(const int layer, const int x_layer, const int y_layer)
|
||||
{
|
||||
// in this case, we have to analyze the situation more carefully:
|
||||
// the values are gaussian blurred and then we really decide
|
||||
data = scores.data + y_layer * scorescols + x_layer;
|
||||
int smoothedcenter = 4 * center + 2 * (s_10 + s10 + s0_1 + s01) + s_1_1 + s1_1 + s_11 + s11;
|
||||
for (unsigned int i = 0; i < deltasize; i += 2)
|
||||
{
|
||||
data = scores.data + (y_layer - 1 + delta[i + 1]) * scorescols + x_layer + delta[i] - 1;
|
||||
data = scores.ptr() + (y_layer - 1 + delta[i + 1]) * scorescols + x_layer + delta[i] - 1;
|
||||
int othercenter = *data;
|
||||
data++;
|
||||
othercenter += 2 * (*data);
|
||||
@@ -1230,8 +1311,7 @@ BriskScaleSpace::refine3D(const int layer, const int x_layer, const int y_layer,
|
||||
int s_2_2 = l.getAgastScore_5_8(x_layer + 1, y_layer + 1, 1);
|
||||
max_below = std::max(s_2_2, max_below);
|
||||
|
||||
max_below_float = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x_below,
|
||||
delta_y_below);
|
||||
subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x_below, delta_y_below);
|
||||
max_below_float = (float)max_below;
|
||||
}
|
||||
else
|
||||
@@ -1985,13 +2065,13 @@ BriskScaleSpace::subpixel2D(const int s_0_0, const int s_0_1, const int s_0_2, c
|
||||
if (max1 > max2)
|
||||
{
|
||||
delta_x = delta_x1;
|
||||
delta_y = delta_x1;
|
||||
delta_y = delta_y1;
|
||||
return max1;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta_x = delta_x2;
|
||||
delta_y = delta_x2;
|
||||
delta_y = delta_y2;
|
||||
return max2;
|
||||
}
|
||||
}
|
||||
@@ -2011,9 +2091,9 @@ BriskLayer::BriskLayer(const cv::Mat& img_in, float scale_in, float offset_in)
|
||||
scale_ = scale_in;
|
||||
offset_ = offset_in;
|
||||
// create an agast detector
|
||||
fast_9_16_ = makePtr<FastFeatureDetector>(1, true, FastFeatureDetector::TYPE_9_16);
|
||||
makeOffsets(pixel_5_8_, (int)img_.step, 8);
|
||||
makeOffsets(pixel_9_16_, (int)img_.step, 16);
|
||||
oast_9_16_ = AgastFeatureDetector::create(1, false, AgastFeatureDetector::OAST_9_16);
|
||||
makeAgastOffsets(pixel_5_8_, (int)img_.step, AgastFeatureDetector::AGAST_5_8);
|
||||
makeAgastOffsets(pixel_9_16_, (int)img_.step, AgastFeatureDetector::OAST_9_16);
|
||||
}
|
||||
// derive a layer
|
||||
BriskLayer::BriskLayer(const BriskLayer& layer, int mode)
|
||||
@@ -2033,18 +2113,18 @@ BriskLayer::BriskLayer(const BriskLayer& layer, int mode)
|
||||
offset_ = 0.5f * scale_ - 0.5f;
|
||||
}
|
||||
scores_ = cv::Mat::zeros(img_.rows, img_.cols, CV_8U);
|
||||
fast_9_16_ = makePtr<FastFeatureDetector>(1, false, FastFeatureDetector::TYPE_9_16);
|
||||
makeOffsets(pixel_5_8_, (int)img_.step, 8);
|
||||
makeOffsets(pixel_9_16_, (int)img_.step, 16);
|
||||
oast_9_16_ = AgastFeatureDetector::create(1, false, AgastFeatureDetector::OAST_9_16);
|
||||
makeAgastOffsets(pixel_5_8_, (int)img_.step, AgastFeatureDetector::AGAST_5_8);
|
||||
makeAgastOffsets(pixel_9_16_, (int)img_.step, AgastFeatureDetector::OAST_9_16);
|
||||
}
|
||||
|
||||
// Fast/Agast
|
||||
// Agast
|
||||
// wraps the agast class
|
||||
void
|
||||
BriskLayer::getAgastPoints(int threshold, std::vector<KeyPoint>& keypoints)
|
||||
{
|
||||
fast_9_16_->set("threshold", threshold);
|
||||
fast_9_16_->detect(img_, keypoints);
|
||||
oast_9_16_->setThreshold(threshold);
|
||||
oast_9_16_->detect(img_, keypoints);
|
||||
|
||||
// also write scores
|
||||
const size_t num = keypoints.size();
|
||||
@@ -2065,7 +2145,7 @@ BriskLayer::getAgastScore(int x, int y, int threshold) const
|
||||
{
|
||||
return score;
|
||||
}
|
||||
score = (uchar)cornerScore<16>(&img_.at<uchar>(y, x), pixel_9_16_, threshold - 1);
|
||||
score = (uchar)agast_cornerScore<AgastFeatureDetector::OAST_9_16>(&img_.at<uchar>(y, x), pixel_9_16_, threshold - 1);
|
||||
if (score < threshold)
|
||||
score = 0;
|
||||
return score;
|
||||
@@ -2078,7 +2158,7 @@ BriskLayer::getAgastScore_5_8(int x, int y, int threshold) const
|
||||
return 0;
|
||||
if (x >= img_.cols - 2 || y >= img_.rows - 2)
|
||||
return 0;
|
||||
int score = cornerScore<8>(&img_.at<uchar>(y, x), pixel_5_8_, threshold - 1);
|
||||
int score = agast_cornerScore<AgastFeatureDetector::AGAST_5_8>(&img_.at<uchar>(y, x), pixel_5_8_, threshold - 1);
|
||||
if (score < threshold)
|
||||
score = 0;
|
||||
return score;
|
||||
@@ -2140,7 +2220,7 @@ BriskLayer::value(const cv::Mat& mat, float xf, float yf, float scale_in) const
|
||||
const int r_y = (int)((yf - y) * 1024);
|
||||
const int r_x_1 = (1024 - r_x);
|
||||
const int r_y_1 = (1024 - r_y);
|
||||
const uchar* ptr = image.data + x + y * imagecols;
|
||||
const uchar* ptr = image.ptr() + x + y * imagecols;
|
||||
// just interpolate:
|
||||
ret_val = (r_x_1 * r_y_1 * int(*ptr));
|
||||
ptr++;
|
||||
@@ -2157,6 +2237,7 @@ BriskLayer::value(const cv::Mat& mat, float xf, float yf, float scale_in) const
|
||||
// scaling:
|
||||
const int scaling = (int)(4194304.0f / area);
|
||||
const int scaling2 = (int)(float(scaling) * area / 1024.0f);
|
||||
CV_Assert(scaling2 != 0);
|
||||
|
||||
// calculate borders
|
||||
const float x_1 = xf - sigma_half;
|
||||
@@ -2186,7 +2267,7 @@ BriskLayer::value(const cv::Mat& mat, float xf, float yf, float scale_in) const
|
||||
const int r_y1_i = (int)(r_y1 * scaling);
|
||||
|
||||
// now the calculation:
|
||||
const uchar* ptr = image.data + x_left + imagecols * y_top;
|
||||
const uchar* ptr = image.ptr() + x_left + imagecols * y_top;
|
||||
// first row:
|
||||
ret_val = A * int(*ptr);
|
||||
ptr++;
|
||||
@@ -2245,4 +2326,28 @@ BriskLayer::twothirdsample(const cv::Mat& srcimg, cv::Mat& dstimg)
|
||||
resize(srcimg, dstimg, dstimg.size(), 0, 0, INTER_AREA);
|
||||
}
|
||||
|
||||
Ptr<BRISK> BRISK::create(int thresh, int octaves, float patternScale)
|
||||
{
|
||||
return makePtr<BRISK_Impl>(thresh, octaves, patternScale);
|
||||
}
|
||||
|
||||
// custom setup
|
||||
Ptr<BRISK> BRISK::create(const std::vector<float> &radiusList, const std::vector<int> &numberList,
|
||||
float dMax, float dMin, const std::vector<int>& indexChange)
|
||||
{
|
||||
return makePtr<BRISK_Impl>(radiusList, numberList, dMax, dMin, indexChange);
|
||||
}
|
||||
|
||||
Ptr<BRISK> BRISK::create(int thresh, int octaves, const std::vector<float> &radiusList,
|
||||
const std::vector<int> &numberList, float dMax, float dMin,
|
||||
const std::vector<int>& indexChange)
|
||||
{
|
||||
return makePtr<BRISK_Impl>(thresh, octaves, radiusList, numberList, dMax, dMin, indexChange);
|
||||
}
|
||||
|
||||
String BRISK::getDefaultName() const
|
||||
{
|
||||
return (Feature2D::getDefaultName() + ".BRISK");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, 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 Intel Corporation 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"
|
||||
#include <limits>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/****************************************************************************************\
|
||||
* DescriptorExtractor *
|
||||
\****************************************************************************************/
|
||||
/*
|
||||
* DescriptorExtractor
|
||||
*/
|
||||
DescriptorExtractor::~DescriptorExtractor()
|
||||
{}
|
||||
|
||||
void DescriptorExtractor::compute( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const
|
||||
{
|
||||
if( image.empty() || keypoints.empty() )
|
||||
{
|
||||
descriptors.release();
|
||||
return;
|
||||
}
|
||||
|
||||
KeyPointsFilter::runByImageBorder( keypoints, image.size(), 0 );
|
||||
KeyPointsFilter::runByKeypointSize( keypoints, std::numeric_limits<float>::epsilon() );
|
||||
|
||||
computeImpl( image, keypoints, descriptors );
|
||||
}
|
||||
|
||||
void DescriptorExtractor::compute( InputArrayOfArrays _imageCollection, std::vector<std::vector<KeyPoint> >& pointCollection, OutputArrayOfArrays _descCollection ) const
|
||||
{
|
||||
std::vector<Mat> imageCollection, descCollection;
|
||||
_imageCollection.getMatVector(imageCollection);
|
||||
_descCollection.getMatVector(descCollection);
|
||||
CV_Assert( imageCollection.size() == pointCollection.size() );
|
||||
descCollection.resize( imageCollection.size() );
|
||||
for( size_t i = 0; i < imageCollection.size(); i++ )
|
||||
compute( imageCollection[i], pointCollection[i], descCollection[i] );
|
||||
}
|
||||
|
||||
/*void DescriptorExtractor::read( const FileNode& )
|
||||
{}
|
||||
|
||||
void DescriptorExtractor::write( FileStorage& ) const
|
||||
{}*/
|
||||
|
||||
bool DescriptorExtractor::empty() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void DescriptorExtractor::removeBorderKeypoints( std::vector<KeyPoint>& keypoints,
|
||||
Size imageSize, int borderSize )
|
||||
{
|
||||
KeyPointsFilter::runByImageBorder( keypoints, imageSize, borderSize );
|
||||
}
|
||||
|
||||
Ptr<DescriptorExtractor> DescriptorExtractor::create(const String& descriptorExtractorType)
|
||||
{
|
||||
if( descriptorExtractorType.find("Opponent") == 0 )
|
||||
{
|
||||
size_t pos = String("Opponent").size();
|
||||
String type = descriptorExtractorType.substr(pos);
|
||||
return makePtr<OpponentColorDescriptorExtractor>(DescriptorExtractor::create(type));
|
||||
}
|
||||
|
||||
return Algorithm::create<DescriptorExtractor>("Feature2D." + descriptorExtractorType);
|
||||
}
|
||||
|
||||
|
||||
CV_WRAP void Feature2D::compute( InputArray image, CV_OUT CV_IN_OUT std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const
|
||||
{
|
||||
DescriptorExtractor::compute(image, keypoints, descriptors);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/****************************************************************************************\
|
||||
* OpponentColorDescriptorExtractor *
|
||||
\****************************************************************************************/
|
||||
OpponentColorDescriptorExtractor::OpponentColorDescriptorExtractor( const Ptr<DescriptorExtractor>& _descriptorExtractor ) :
|
||||
descriptorExtractor(_descriptorExtractor)
|
||||
{
|
||||
CV_Assert( descriptorExtractor );
|
||||
}
|
||||
|
||||
static void convertBGRImageToOpponentColorSpace( const Mat& bgrImage, std::vector<Mat>& opponentChannels )
|
||||
{
|
||||
if( bgrImage.type() != CV_8UC3 )
|
||||
CV_Error( Error::StsBadArg, "input image must be an BGR image of type CV_8UC3" );
|
||||
|
||||
// Prepare opponent color space storage matrices.
|
||||
opponentChannels.resize( 3 );
|
||||
opponentChannels[0] = cv::Mat(bgrImage.size(), CV_8UC1); // R-G RED-GREEN
|
||||
opponentChannels[1] = cv::Mat(bgrImage.size(), CV_8UC1); // R+G-2B YELLOW-BLUE
|
||||
opponentChannels[2] = cv::Mat(bgrImage.size(), CV_8UC1); // R+G+B
|
||||
|
||||
for(int y = 0; y < bgrImage.rows; ++y)
|
||||
for(int x = 0; x < bgrImage.cols; ++x)
|
||||
{
|
||||
Vec3b v = bgrImage.at<Vec3b>(y, x);
|
||||
uchar& b = v[0];
|
||||
uchar& g = v[1];
|
||||
uchar& r = v[2];
|
||||
|
||||
opponentChannels[0].at<uchar>(y, x) = saturate_cast<uchar>(0.5f * (255 + g - r)); // (R - G)/sqrt(2), but converted to the destination data type
|
||||
opponentChannels[1].at<uchar>(y, x) = saturate_cast<uchar>(0.25f * (510 + r + g - 2*b)); // (R + G - 2B)/sqrt(6), but converted to the destination data type
|
||||
opponentChannels[2].at<uchar>(y, x) = saturate_cast<uchar>(1.f/3.f * (r + g + b)); // (R + G + B)/sqrt(3), but converted to the destination data type
|
||||
}
|
||||
}
|
||||
|
||||
struct KP_LessThan
|
||||
{
|
||||
KP_LessThan(const std::vector<KeyPoint>& _kp) : kp(&_kp) {}
|
||||
bool operator()(int i, int j) const
|
||||
{
|
||||
return (*kp)[i].class_id < (*kp)[j].class_id;
|
||||
}
|
||||
const std::vector<KeyPoint>* kp;
|
||||
};
|
||||
|
||||
void OpponentColorDescriptorExtractor::computeImpl( InputArray _bgrImage, std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const
|
||||
{
|
||||
Mat bgrImage = _bgrImage.getMat();
|
||||
std::vector<Mat> opponentChannels;
|
||||
convertBGRImageToOpponentColorSpace( bgrImage, opponentChannels );
|
||||
|
||||
const int N = 3; // channels count
|
||||
std::vector<KeyPoint> channelKeypoints[N];
|
||||
Mat channelDescriptors[N];
|
||||
std::vector<int> idxs[N];
|
||||
|
||||
// Compute descriptors three times, once for each Opponent channel to concatenate into a single color descriptor
|
||||
int maxKeypointsCount = 0;
|
||||
for( int ci = 0; ci < N; ci++ )
|
||||
{
|
||||
channelKeypoints[ci].insert( channelKeypoints[ci].begin(), keypoints.begin(), keypoints.end() );
|
||||
// Use class_id member to get indices into initial keypoints vector
|
||||
for( size_t ki = 0; ki < channelKeypoints[ci].size(); ki++ )
|
||||
channelKeypoints[ci][ki].class_id = (int)ki;
|
||||
|
||||
descriptorExtractor->compute( opponentChannels[ci], channelKeypoints[ci], channelDescriptors[ci] );
|
||||
idxs[ci].resize( channelKeypoints[ci].size() );
|
||||
for( size_t ki = 0; ki < channelKeypoints[ci].size(); ki++ )
|
||||
{
|
||||
idxs[ci][ki] = (int)ki;
|
||||
}
|
||||
std::sort( idxs[ci].begin(), idxs[ci].end(), KP_LessThan(channelKeypoints[ci]) );
|
||||
maxKeypointsCount = std::max( maxKeypointsCount, (int)channelKeypoints[ci].size());
|
||||
}
|
||||
|
||||
std::vector<KeyPoint> outKeypoints;
|
||||
outKeypoints.reserve( keypoints.size() );
|
||||
|
||||
int dSize = descriptorExtractor->descriptorSize();
|
||||
Mat mergedDescriptors( maxKeypointsCount, 3*dSize, descriptorExtractor->descriptorType() );
|
||||
int mergedCount = 0;
|
||||
// cp - current channel position
|
||||
size_t cp[] = {0, 0, 0};
|
||||
while( cp[0] < channelKeypoints[0].size() &&
|
||||
cp[1] < channelKeypoints[1].size() &&
|
||||
cp[2] < channelKeypoints[2].size() )
|
||||
{
|
||||
const int maxInitIdx = std::max( 0, std::max( channelKeypoints[0][idxs[0][cp[0]]].class_id,
|
||||
std::max( channelKeypoints[1][idxs[1][cp[1]]].class_id,
|
||||
channelKeypoints[2][idxs[2][cp[2]]].class_id ) ) );
|
||||
|
||||
while( channelKeypoints[0][idxs[0][cp[0]]].class_id < maxInitIdx && cp[0] < channelKeypoints[0].size() ) { cp[0]++; }
|
||||
while( channelKeypoints[1][idxs[1][cp[1]]].class_id < maxInitIdx && cp[1] < channelKeypoints[1].size() ) { cp[1]++; }
|
||||
while( channelKeypoints[2][idxs[2][cp[2]]].class_id < maxInitIdx && cp[2] < channelKeypoints[2].size() ) { cp[2]++; }
|
||||
if( cp[0] >= channelKeypoints[0].size() || cp[1] >= channelKeypoints[1].size() || cp[2] >= channelKeypoints[2].size() )
|
||||
break;
|
||||
|
||||
if( channelKeypoints[0][idxs[0][cp[0]]].class_id == maxInitIdx &&
|
||||
channelKeypoints[1][idxs[1][cp[1]]].class_id == maxInitIdx &&
|
||||
channelKeypoints[2][idxs[2][cp[2]]].class_id == maxInitIdx )
|
||||
{
|
||||
outKeypoints.push_back( keypoints[maxInitIdx] );
|
||||
// merge descriptors
|
||||
for( int ci = 0; ci < N; ci++ )
|
||||
{
|
||||
Mat dst = mergedDescriptors(Range(mergedCount, mergedCount+1), Range(ci*dSize, (ci+1)*dSize));
|
||||
channelDescriptors[ci].row( idxs[ci][cp[ci]] ).copyTo( dst );
|
||||
cp[ci]++;
|
||||
}
|
||||
mergedCount++;
|
||||
}
|
||||
}
|
||||
mergedDescriptors.rowRange(0, mergedCount).copyTo( descriptors );
|
||||
std::swap( outKeypoints, keypoints );
|
||||
}
|
||||
|
||||
void OpponentColorDescriptorExtractor::read( const FileNode& fn )
|
||||
{
|
||||
descriptorExtractor->read(fn);
|
||||
}
|
||||
|
||||
void OpponentColorDescriptorExtractor::write( FileStorage& fs ) const
|
||||
{
|
||||
descriptorExtractor->write(fs);
|
||||
}
|
||||
|
||||
int OpponentColorDescriptorExtractor::descriptorSize() const
|
||||
{
|
||||
return 3*descriptorExtractor->descriptorSize();
|
||||
}
|
||||
|
||||
int OpponentColorDescriptorExtractor::descriptorType() const
|
||||
{
|
||||
return descriptorExtractor->descriptorType();
|
||||
}
|
||||
|
||||
int OpponentColorDescriptorExtractor::defaultNorm() const
|
||||
{
|
||||
return descriptorExtractor->defaultNorm();
|
||||
}
|
||||
|
||||
bool OpponentColorDescriptorExtractor::empty() const
|
||||
{
|
||||
return !descriptorExtractor || descriptorExtractor->empty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,387 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, 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 Intel Corporation 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
|
||||
{
|
||||
|
||||
/*
|
||||
* FeatureDetector
|
||||
*/
|
||||
|
||||
FeatureDetector::~FeatureDetector()
|
||||
{}
|
||||
|
||||
void FeatureDetector::detect( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask ) const
|
||||
{
|
||||
keypoints.clear();
|
||||
|
||||
if( image.empty() )
|
||||
return;
|
||||
|
||||
CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) );
|
||||
|
||||
detectImpl( image, keypoints, mask );
|
||||
}
|
||||
|
||||
void FeatureDetector::detect(InputArrayOfArrays _imageCollection, std::vector<std::vector<KeyPoint> >& pointCollection,
|
||||
InputArrayOfArrays _masks ) const
|
||||
{
|
||||
if (_imageCollection.isUMatVector())
|
||||
{
|
||||
std::vector<UMat> uimageCollection, umasks;
|
||||
_imageCollection.getUMatVector(uimageCollection);
|
||||
_masks.getUMatVector(umasks);
|
||||
|
||||
pointCollection.resize( uimageCollection.size() );
|
||||
for( size_t i = 0; i < uimageCollection.size(); i++ )
|
||||
detect( uimageCollection[i], pointCollection[i], umasks.empty() ? noArray() : umasks[i] );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Mat> imageCollection, masks;
|
||||
_imageCollection.getMatVector(imageCollection);
|
||||
_masks.getMatVector(masks);
|
||||
|
||||
pointCollection.resize( imageCollection.size() );
|
||||
for( size_t i = 0; i < imageCollection.size(); i++ )
|
||||
detect( imageCollection[i], pointCollection[i], masks.empty() ? noArray() : masks[i] );
|
||||
}
|
||||
|
||||
/*void FeatureDetector::read( const FileNode& )
|
||||
{}
|
||||
|
||||
void FeatureDetector::write( FileStorage& ) const
|
||||
{}*/
|
||||
|
||||
bool FeatureDetector::empty() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void FeatureDetector::removeInvalidPoints( const Mat& mask, std::vector<KeyPoint>& keypoints )
|
||||
{
|
||||
KeyPointsFilter::runByPixelsMask( keypoints, mask );
|
||||
}
|
||||
|
||||
Ptr<FeatureDetector> FeatureDetector::create( const String& detectorType )
|
||||
{
|
||||
if( detectorType.find("Grid") == 0 )
|
||||
{
|
||||
return makePtr<GridAdaptedFeatureDetector>(FeatureDetector::create(
|
||||
detectorType.substr(strlen("Grid"))));
|
||||
}
|
||||
|
||||
if( detectorType.find("Pyramid") == 0 )
|
||||
{
|
||||
return makePtr<PyramidAdaptedFeatureDetector>(FeatureDetector::create(
|
||||
detectorType.substr(strlen("Pyramid"))));
|
||||
}
|
||||
|
||||
if( detectorType.find("Dynamic") == 0 )
|
||||
{
|
||||
return makePtr<DynamicAdaptedFeatureDetector>(AdjusterAdapter::create(
|
||||
detectorType.substr(strlen("Dynamic"))));
|
||||
}
|
||||
|
||||
if( detectorType.compare( "HARRIS" ) == 0 )
|
||||
{
|
||||
Ptr<FeatureDetector> fd = FeatureDetector::create("GFTT");
|
||||
fd->set("useHarrisDetector", true);
|
||||
return fd;
|
||||
}
|
||||
|
||||
return Algorithm::create<FeatureDetector>("Feature2D." + detectorType);
|
||||
}
|
||||
|
||||
|
||||
GFTTDetector::GFTTDetector( int _nfeatures, double _qualityLevel,
|
||||
double _minDistance, int _blockSize,
|
||||
bool _useHarrisDetector, double _k )
|
||||
: nfeatures(_nfeatures), qualityLevel(_qualityLevel), minDistance(_minDistance),
|
||||
blockSize(_blockSize), useHarrisDetector(_useHarrisDetector), k(_k)
|
||||
{
|
||||
}
|
||||
|
||||
void GFTTDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask) const
|
||||
{
|
||||
std::vector<Point2f> corners;
|
||||
|
||||
if (_image.isUMat())
|
||||
{
|
||||
UMat ugrayImage;
|
||||
if( _image.type() != CV_8U )
|
||||
cvtColor( _image, ugrayImage, COLOR_BGR2GRAY );
|
||||
else
|
||||
ugrayImage = _image.getUMat();
|
||||
|
||||
goodFeaturesToTrack( ugrayImage, corners, nfeatures, qualityLevel, minDistance, _mask,
|
||||
blockSize, useHarrisDetector, k );
|
||||
}
|
||||
else
|
||||
{
|
||||
Mat image = _image.getMat(), grayImage = image;
|
||||
if( image.type() != CV_8U )
|
||||
cvtColor( image, grayImage, COLOR_BGR2GRAY );
|
||||
|
||||
goodFeaturesToTrack( grayImage, corners, nfeatures, qualityLevel, minDistance, _mask,
|
||||
blockSize, useHarrisDetector, k );
|
||||
}
|
||||
|
||||
keypoints.resize(corners.size());
|
||||
std::vector<Point2f>::const_iterator corner_it = corners.begin();
|
||||
std::vector<KeyPoint>::iterator keypoint_it = keypoints.begin();
|
||||
for( ; corner_it != corners.end(); ++corner_it, ++keypoint_it )
|
||||
*keypoint_it = KeyPoint( *corner_it, (float)blockSize );
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* DenseFeatureDetector
|
||||
*/
|
||||
DenseFeatureDetector::DenseFeatureDetector( float _initFeatureScale, int _featureScaleLevels,
|
||||
float _featureScaleMul, int _initXyStep,
|
||||
int _initImgBound, bool _varyXyStepWithScale,
|
||||
bool _varyImgBoundWithScale ) :
|
||||
initFeatureScale(_initFeatureScale), featureScaleLevels(_featureScaleLevels),
|
||||
featureScaleMul(_featureScaleMul), initXyStep(_initXyStep), initImgBound(_initImgBound),
|
||||
varyXyStepWithScale(_varyXyStepWithScale), varyImgBoundWithScale(_varyImgBoundWithScale)
|
||||
{}
|
||||
|
||||
|
||||
void DenseFeatureDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) const
|
||||
{
|
||||
Mat image = _image.getMat(), mask = _mask.getMat();
|
||||
|
||||
float curScale = static_cast<float>(initFeatureScale);
|
||||
int curStep = initXyStep;
|
||||
int curBound = initImgBound;
|
||||
for( int curLevel = 0; curLevel < featureScaleLevels; curLevel++ )
|
||||
{
|
||||
for( int x = curBound; x < image.cols - curBound; x += curStep )
|
||||
{
|
||||
for( int y = curBound; y < image.rows - curBound; y += curStep )
|
||||
{
|
||||
keypoints.push_back( KeyPoint(static_cast<float>(x), static_cast<float>(y), curScale) );
|
||||
}
|
||||
}
|
||||
|
||||
curScale = static_cast<float>(curScale * featureScaleMul);
|
||||
if( varyXyStepWithScale ) curStep = static_cast<int>( curStep * featureScaleMul + 0.5f );
|
||||
if( varyImgBoundWithScale ) curBound = static_cast<int>( curBound * featureScaleMul + 0.5f );
|
||||
}
|
||||
|
||||
KeyPointsFilter::runByPixelsMask( keypoints, mask );
|
||||
}
|
||||
|
||||
/*
|
||||
* GridAdaptedFeatureDetector
|
||||
*/
|
||||
GridAdaptedFeatureDetector::GridAdaptedFeatureDetector( const Ptr<FeatureDetector>& _detector,
|
||||
int _maxTotalKeypoints, int _gridRows, int _gridCols )
|
||||
: detector(_detector), maxTotalKeypoints(_maxTotalKeypoints), gridRows(_gridRows), gridCols(_gridCols)
|
||||
{}
|
||||
|
||||
bool GridAdaptedFeatureDetector::empty() const
|
||||
{
|
||||
return !detector || detector->empty();
|
||||
}
|
||||
|
||||
struct ResponseComparator
|
||||
{
|
||||
bool operator() (const KeyPoint& a, const KeyPoint& b)
|
||||
{
|
||||
return std::abs(a.response) > std::abs(b.response);
|
||||
}
|
||||
};
|
||||
|
||||
static void keepStrongest( int N, std::vector<KeyPoint>& keypoints )
|
||||
{
|
||||
if( (int)keypoints.size() > N )
|
||||
{
|
||||
std::vector<KeyPoint>::iterator nth = keypoints.begin() + N;
|
||||
std::nth_element( keypoints.begin(), nth, keypoints.end(), ResponseComparator() );
|
||||
keypoints.erase( nth, keypoints.end() );
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class GridAdaptedFeatureDetectorInvoker : public ParallelLoopBody
|
||||
{
|
||||
private:
|
||||
int gridRows_, gridCols_;
|
||||
int maxPerCell_;
|
||||
std::vector<KeyPoint>& keypoints_;
|
||||
const Mat& image_;
|
||||
const Mat& mask_;
|
||||
const Ptr<FeatureDetector>& detector_;
|
||||
Mutex* kptLock_;
|
||||
|
||||
GridAdaptedFeatureDetectorInvoker& operator=(const GridAdaptedFeatureDetectorInvoker&); // to quiet MSVC
|
||||
|
||||
public:
|
||||
|
||||
GridAdaptedFeatureDetectorInvoker(const Ptr<FeatureDetector>& detector, const Mat& image, const Mat& mask,
|
||||
std::vector<KeyPoint>& keypoints, int maxPerCell, int gridRows, int gridCols,
|
||||
cv::Mutex* kptLock)
|
||||
: gridRows_(gridRows), gridCols_(gridCols), maxPerCell_(maxPerCell),
|
||||
keypoints_(keypoints), image_(image), mask_(mask), detector_(detector),
|
||||
kptLock_(kptLock)
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (const Range& range) const
|
||||
{
|
||||
for (int i = range.start; i < range.end; ++i)
|
||||
{
|
||||
int celly = i / gridCols_;
|
||||
int cellx = i - celly * gridCols_;
|
||||
|
||||
Range row_range((celly*image_.rows)/gridRows_, ((celly+1)*image_.rows)/gridRows_);
|
||||
Range col_range((cellx*image_.cols)/gridCols_, ((cellx+1)*image_.cols)/gridCols_);
|
||||
|
||||
Mat sub_image = image_(row_range, col_range);
|
||||
Mat sub_mask;
|
||||
if (!mask_.empty()) sub_mask = mask_(row_range, col_range);
|
||||
|
||||
std::vector<KeyPoint> sub_keypoints;
|
||||
sub_keypoints.reserve(maxPerCell_);
|
||||
|
||||
detector_->detect( sub_image, sub_keypoints, sub_mask );
|
||||
keepStrongest( maxPerCell_, sub_keypoints );
|
||||
|
||||
std::vector<cv::KeyPoint>::iterator it = sub_keypoints.begin(),
|
||||
end = sub_keypoints.end();
|
||||
for( ; it != end; ++it )
|
||||
{
|
||||
it->pt.x += col_range.start;
|
||||
it->pt.y += row_range.start;
|
||||
}
|
||||
|
||||
cv::AutoLock join_keypoints(*kptLock_);
|
||||
keypoints_.insert( keypoints_.end(), sub_keypoints.begin(), sub_keypoints.end() );
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namepace
|
||||
|
||||
void GridAdaptedFeatureDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) const
|
||||
{
|
||||
if (_image.empty() || maxTotalKeypoints < gridRows * gridCols)
|
||||
{
|
||||
keypoints.clear();
|
||||
return;
|
||||
}
|
||||
keypoints.reserve(maxTotalKeypoints);
|
||||
int maxPerCell = maxTotalKeypoints / (gridRows * gridCols);
|
||||
|
||||
Mat image = _image.getMat(), mask = _mask.getMat();
|
||||
|
||||
cv::Mutex kptLock;
|
||||
cv::parallel_for_(cv::Range(0, gridRows * gridCols),
|
||||
GridAdaptedFeatureDetectorInvoker(detector, image, mask, keypoints, maxPerCell, gridRows, gridCols, &kptLock));
|
||||
}
|
||||
|
||||
/*
|
||||
* PyramidAdaptedFeatureDetector
|
||||
*/
|
||||
PyramidAdaptedFeatureDetector::PyramidAdaptedFeatureDetector( const Ptr<FeatureDetector>& _detector, int _maxLevel )
|
||||
: detector(_detector), maxLevel(_maxLevel)
|
||||
{}
|
||||
|
||||
bool PyramidAdaptedFeatureDetector::empty() const
|
||||
{
|
||||
return !detector || detector->empty();
|
||||
}
|
||||
|
||||
void PyramidAdaptedFeatureDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) const
|
||||
{
|
||||
Mat image = _image.getMat(), mask = _mask.getMat();
|
||||
Mat src = image;
|
||||
Mat src_mask = mask;
|
||||
|
||||
Mat dilated_mask;
|
||||
if( !mask.empty() )
|
||||
{
|
||||
dilate( mask, dilated_mask, Mat() );
|
||||
Mat mask255( mask.size(), CV_8UC1, Scalar(0) );
|
||||
mask255.setTo( Scalar(255), dilated_mask != 0 );
|
||||
dilated_mask = mask255;
|
||||
}
|
||||
|
||||
for( int l = 0, multiplier = 1; l <= maxLevel; ++l, multiplier *= 2 )
|
||||
{
|
||||
// Detect on current level of the pyramid
|
||||
std::vector<KeyPoint> new_pts;
|
||||
detector->detect( src, new_pts, src_mask );
|
||||
std::vector<KeyPoint>::iterator it = new_pts.begin(),
|
||||
end = new_pts.end();
|
||||
for( ; it != end; ++it)
|
||||
{
|
||||
it->pt.x *= multiplier;
|
||||
it->pt.y *= multiplier;
|
||||
it->size *= multiplier;
|
||||
it->octave = l;
|
||||
}
|
||||
keypoints.insert( keypoints.end(), new_pts.begin(), new_pts.end() );
|
||||
|
||||
// Downsample
|
||||
if( l < maxLevel )
|
||||
{
|
||||
Mat dst;
|
||||
pyrDown( src, dst );
|
||||
src = dst;
|
||||
|
||||
if( !mask.empty() )
|
||||
resize( dilated_mask, src_mask, src.size(), 0, 0, INTER_AREA );
|
||||
}
|
||||
}
|
||||
|
||||
if( !mask.empty() )
|
||||
KeyPointsFilter::runByPixelsMask( keypoints, mask );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -91,11 +91,13 @@ static inline void _drawKeypoint( InputOutputArray img, const KeyPoint& p, const
|
||||
void drawKeypoints( InputArray image, const std::vector<KeyPoint>& keypoints, InputOutputArray outImage,
|
||||
const Scalar& _color, int flags )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
if( !(flags & DrawMatchesFlags::DRAW_OVER_OUTIMG) )
|
||||
{
|
||||
if( image.type() == CV_8UC3 )
|
||||
if (image.type() == CV_8UC3 || image.type() == CV_8UC4)
|
||||
{
|
||||
image.copyTo( outImage );
|
||||
image.copyTo(outImage);
|
||||
}
|
||||
else if( image.type() == CV_8UC1 )
|
||||
{
|
||||
@@ -103,7 +105,7 @@ void drawKeypoints( InputArray image, const std::vector<KeyPoint>& keypoints, In
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Error( Error::StsBadArg, "Incorrect type of input image.\n" );
|
||||
CV_Error( Error::StsBadArg, "Incorrect type of input image: " + typeToString(image.type()) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,11 +117,30 @@ void drawKeypoints( InputArray image, const std::vector<KeyPoint>& keypoints, In
|
||||
end = keypoints.end();
|
||||
for( ; it != end; ++it )
|
||||
{
|
||||
Scalar color = isRandColor ? Scalar(rng(256), rng(256), rng(256)) : _color;
|
||||
Scalar color = isRandColor ? Scalar( rng(256), rng(256), rng(256), 255 ) : _color;
|
||||
_drawKeypoint( outImage, *it, color, flags );
|
||||
}
|
||||
}
|
||||
|
||||
static void _prepareImage(InputArray src, const Mat& dst)
|
||||
{
|
||||
CV_CheckType(src.type(), src.type() == CV_8UC1 || src.type() == CV_8UC3 || src.type() == CV_8UC4, "Unsupported source image");
|
||||
CV_CheckType(dst.type(), dst.type() == CV_8UC3 || dst.type() == CV_8UC4, "Unsupported destination image");
|
||||
const int src_cn = src.channels();
|
||||
const int dst_cn = dst.channels();
|
||||
|
||||
if (src_cn == dst_cn)
|
||||
src.copyTo(dst);
|
||||
else if (src_cn == 1)
|
||||
cvtColor(src, dst, dst_cn == 3 ? COLOR_GRAY2BGR : COLOR_GRAY2BGRA);
|
||||
else if (src_cn == 3 && dst_cn == 4)
|
||||
cvtColor(src, dst, COLOR_BGR2BGRA);
|
||||
else if (src_cn == 4 && dst_cn == 3)
|
||||
cvtColor(src, dst, COLOR_BGRA2BGR);
|
||||
else
|
||||
CV_Error(Error::StsInternal, "");
|
||||
}
|
||||
|
||||
static void _prepareImgAndDrawKeypoints( InputArray img1, const std::vector<KeyPoint>& keypoints1,
|
||||
InputArray img2, const std::vector<KeyPoint>& keypoints2,
|
||||
InputOutputArray _outImg, Mat& outImg1, Mat& outImg2,
|
||||
@@ -138,31 +159,26 @@ static void _prepareImgAndDrawKeypoints( InputArray img1, const std::vector<KeyP
|
||||
}
|
||||
else
|
||||
{
|
||||
_outImg.create( size, CV_MAKETYPE(img1.depth(), 3) );
|
||||
const int cn1 = img1.channels(), cn2 = img2.channels();
|
||||
const int out_cn = std::max(3, std::max(cn1, cn2));
|
||||
_outImg.create(size, CV_MAKETYPE(img1.depth(), out_cn));
|
||||
outImg = _outImg.getMat();
|
||||
outImg = Scalar::all(0);
|
||||
outImg1 = outImg( Rect(0, 0, img1size.width, img1size.height) );
|
||||
outImg2 = outImg( Rect(img1size.width, 0, img2size.width, img2size.height) );
|
||||
|
||||
if( img1.type() == CV_8U )
|
||||
cvtColor( img1, outImg1, COLOR_GRAY2BGR );
|
||||
else
|
||||
img1.copyTo( outImg1 );
|
||||
|
||||
if( img2.type() == CV_8U )
|
||||
cvtColor( img2, outImg2, COLOR_GRAY2BGR );
|
||||
else
|
||||
img2.copyTo( outImg2 );
|
||||
_prepareImage(img1, outImg1);
|
||||
_prepareImage(img2, outImg2);
|
||||
}
|
||||
|
||||
// draw keypoints
|
||||
if( !(flags & DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS) )
|
||||
{
|
||||
Mat _outImg1 = outImg( Rect(0, 0, img1size.width, img1size.height) );
|
||||
drawKeypoints( _outImg1, keypoints1, _outImg1, singlePointColor, flags + DrawMatchesFlags::DRAW_OVER_OUTIMG );
|
||||
drawKeypoints( _outImg1, keypoints1, _outImg1, singlePointColor, flags | DrawMatchesFlags::DRAW_OVER_OUTIMG );
|
||||
|
||||
Mat _outImg2 = outImg( Rect(img1size.width, 0, img2size.width, img2size.height) );
|
||||
drawKeypoints( _outImg2, keypoints2, _outImg2, singlePointColor, flags + DrawMatchesFlags::DRAW_OVER_OUTIMG );
|
||||
drawKeypoints( _outImg2, keypoints2, _outImg2, singlePointColor, flags | DrawMatchesFlags::DRAW_OVER_OUTIMG );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +187,7 @@ static inline void _drawMatch( InputOutputArray outImg, InputOutputArray outImg1
|
||||
{
|
||||
RNG& rng = theRNG();
|
||||
bool isRandMatchColor = matchColor == Scalar::all(-1);
|
||||
Scalar color = isRandMatchColor ? Scalar( rng(256), rng(256), rng(256) ) : matchColor;
|
||||
Scalar color = isRandMatchColor ? Scalar( rng(256), rng(256), rng(256), 255 ) : matchColor;
|
||||
|
||||
_drawKeypoint( outImg1, kp1, color, flags );
|
||||
_drawKeypoint( outImg2, kp2, color, flags );
|
||||
|
||||
@@ -44,181 +44,4 @@
|
||||
namespace cv
|
||||
{
|
||||
|
||||
DynamicAdaptedFeatureDetector::DynamicAdaptedFeatureDetector(const Ptr<AdjusterAdapter>& a,
|
||||
int min_features, int max_features, int max_iters ) :
|
||||
escape_iters_(max_iters), min_features_(min_features), max_features_(max_features), adjuster_(a)
|
||||
{}
|
||||
|
||||
bool DynamicAdaptedFeatureDetector::empty() const
|
||||
{
|
||||
return !adjuster_ || adjuster_->empty();
|
||||
}
|
||||
|
||||
void DynamicAdaptedFeatureDetector::detectImpl(InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask) const
|
||||
{
|
||||
Mat image = _image.getMat(), mask = _mask.getMat();
|
||||
|
||||
//for oscillation testing
|
||||
bool down = false;
|
||||
bool up = false;
|
||||
|
||||
//flag for whether the correct threshhold has been reached
|
||||
bool thresh_good = false;
|
||||
|
||||
Ptr<AdjusterAdapter> adjuster = adjuster_->clone();
|
||||
|
||||
//break if the desired number hasn't been reached.
|
||||
int iter_count = escape_iters_;
|
||||
|
||||
while( iter_count > 0 && !(down && up) && !thresh_good && adjuster->good() )
|
||||
{
|
||||
keypoints.clear();
|
||||
|
||||
//the adjuster takes care of calling the detector with updated parameters
|
||||
adjuster->detect(image, keypoints,mask);
|
||||
|
||||
if( int(keypoints.size()) < min_features_ )
|
||||
{
|
||||
down = true;
|
||||
adjuster->tooFew(min_features_, (int)keypoints.size());
|
||||
}
|
||||
else if( int(keypoints.size()) > max_features_ )
|
||||
{
|
||||
up = true;
|
||||
adjuster->tooMany(max_features_, (int)keypoints.size());
|
||||
}
|
||||
else
|
||||
thresh_good = true;
|
||||
|
||||
iter_count--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FastAdjuster::FastAdjuster( int init_thresh, bool nonmax, int min_thresh, int max_thresh ) :
|
||||
thresh_(init_thresh), nonmax_(nonmax), init_thresh_(init_thresh),
|
||||
min_thresh_(min_thresh), max_thresh_(max_thresh)
|
||||
{}
|
||||
|
||||
void FastAdjuster::detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const
|
||||
{
|
||||
FastFeatureDetector(thresh_, nonmax_).detect(image, keypoints, mask);
|
||||
}
|
||||
|
||||
void FastAdjuster::tooFew(int, int)
|
||||
{
|
||||
//fast is easy to adjust
|
||||
thresh_--;
|
||||
}
|
||||
|
||||
void FastAdjuster::tooMany(int, int)
|
||||
{
|
||||
//fast is easy to adjust
|
||||
thresh_++;
|
||||
}
|
||||
|
||||
//return whether or not the threshhold is beyond
|
||||
//a useful point
|
||||
bool FastAdjuster::good() const
|
||||
{
|
||||
return (thresh_ > min_thresh_) && (thresh_ < max_thresh_);
|
||||
}
|
||||
|
||||
Ptr<AdjusterAdapter> FastAdjuster::clone() const
|
||||
{
|
||||
Ptr<AdjusterAdapter> cloned_obj(new FastAdjuster( init_thresh_, nonmax_, min_thresh_, max_thresh_ ));
|
||||
return cloned_obj;
|
||||
}
|
||||
|
||||
StarAdjuster::StarAdjuster(double initial_thresh, double min_thresh, double max_thresh) :
|
||||
thresh_(initial_thresh), init_thresh_(initial_thresh),
|
||||
min_thresh_(min_thresh), max_thresh_(max_thresh)
|
||||
{}
|
||||
|
||||
void StarAdjuster::detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const
|
||||
{
|
||||
StarFeatureDetector detector_tmp(16, cvRound(thresh_), 10, 8, 3);
|
||||
detector_tmp.detect(image, keypoints, mask);
|
||||
}
|
||||
|
||||
void StarAdjuster::tooFew(int, int)
|
||||
{
|
||||
thresh_ *= 0.9;
|
||||
if (thresh_ < 1.1)
|
||||
thresh_ = 1.1;
|
||||
}
|
||||
|
||||
void StarAdjuster::tooMany(int, int)
|
||||
{
|
||||
thresh_ *= 1.1;
|
||||
}
|
||||
|
||||
bool StarAdjuster::good() const
|
||||
{
|
||||
return (thresh_ > min_thresh_) && (thresh_ < max_thresh_);
|
||||
}
|
||||
|
||||
Ptr<AdjusterAdapter> StarAdjuster::clone() const
|
||||
{
|
||||
Ptr<AdjusterAdapter> cloned_obj(new StarAdjuster( init_thresh_, min_thresh_, max_thresh_ ));
|
||||
return cloned_obj;
|
||||
}
|
||||
|
||||
SurfAdjuster::SurfAdjuster( double initial_thresh, double min_thresh, double max_thresh ) :
|
||||
thresh_(initial_thresh), init_thresh_(initial_thresh),
|
||||
min_thresh_(min_thresh), max_thresh_(max_thresh)
|
||||
{}
|
||||
|
||||
void SurfAdjuster::detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const
|
||||
{
|
||||
Ptr<FeatureDetector> surf = FeatureDetector::create("SURF");
|
||||
surf->set("hessianThreshold", thresh_);
|
||||
surf->detect(image, keypoints, mask);
|
||||
}
|
||||
|
||||
void SurfAdjuster::tooFew(int, int)
|
||||
{
|
||||
thresh_ *= 0.9;
|
||||
if (thresh_ < 1.1)
|
||||
thresh_ = 1.1;
|
||||
}
|
||||
|
||||
void SurfAdjuster::tooMany(int, int)
|
||||
{
|
||||
thresh_ *= 1.1;
|
||||
}
|
||||
|
||||
//return whether or not the threshhold is beyond
|
||||
//a useful point
|
||||
bool SurfAdjuster::good() const
|
||||
{
|
||||
return (thresh_ > min_thresh_) && (thresh_ < max_thresh_);
|
||||
}
|
||||
|
||||
Ptr<AdjusterAdapter> SurfAdjuster::clone() const
|
||||
{
|
||||
Ptr<AdjusterAdapter> cloned_obj(new SurfAdjuster( init_thresh_, min_thresh_, max_thresh_ ));
|
||||
return cloned_obj;
|
||||
}
|
||||
|
||||
Ptr<AdjusterAdapter> AdjusterAdapter::create( const String& detectorType )
|
||||
{
|
||||
Ptr<AdjusterAdapter> adapter;
|
||||
|
||||
if( !detectorType.compare( "FAST" ) )
|
||||
{
|
||||
adapter = makePtr<FastAdjuster>();
|
||||
}
|
||||
else if( !detectorType.compare( "STAR" ) )
|
||||
{
|
||||
adapter = makePtr<StarAdjuster>();
|
||||
}
|
||||
else if( !detectorType.compare( "SURF" ) )
|
||||
{
|
||||
adapter = makePtr<SurfAdjuster>();
|
||||
}
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -179,6 +179,8 @@ void EllipticKeyPoint::calcProjection( const Mat_<double>& H, EllipticKeyPoint&
|
||||
|
||||
void EllipticKeyPoint::convert( const std::vector<KeyPoint>& src, std::vector<EllipticKeyPoint>& dst )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
if( !src.empty() )
|
||||
{
|
||||
dst.resize(src.size());
|
||||
@@ -194,6 +196,8 @@ void EllipticKeyPoint::convert( const std::vector<KeyPoint>& src, std::vector<El
|
||||
|
||||
void EllipticKeyPoint::convert( const std::vector<EllipticKeyPoint>& src, std::vector<KeyPoint>& dst )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
if( !src.empty() )
|
||||
{
|
||||
dst.resize(src.size());
|
||||
@@ -214,7 +218,7 @@ void EllipticKeyPoint::calcProjection( const std::vector<EllipticKeyPoint>& src,
|
||||
dst.resize(src.size());
|
||||
std::vector<EllipticKeyPoint>::const_iterator srcIt = src.begin();
|
||||
std::vector<EllipticKeyPoint>::iterator dstIt = dst.begin();
|
||||
for( ; srcIt != src.end(); ++srcIt, ++dstIt )
|
||||
for( ; srcIt != src.end() && dstIt != dst.end(); ++srcIt, ++dstIt )
|
||||
srcIt->calcProjection(H, *dstIt);
|
||||
}
|
||||
}
|
||||
@@ -456,6 +460,8 @@ void cv::evaluateFeatureDetector( const Mat& img1, const Mat& img2, const Mat& H
|
||||
float& repeatability, int& correspCount,
|
||||
const Ptr<FeatureDetector>& _fdetector )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
Ptr<FeatureDetector> fdetector(_fdetector);
|
||||
std::vector<KeyPoint> *keypoints1, *keypoints2, buf1, buf2;
|
||||
keypoints1 = _keypoints1 != 0 ? _keypoints1 : &buf1;
|
||||
@@ -475,7 +481,7 @@ void cv::evaluateFeatureDetector( const Mat& img1, const Mat& img2, const Mat& H
|
||||
struct DMatchForEvaluation : public DMatch
|
||||
{
|
||||
uchar isCorrect;
|
||||
DMatchForEvaluation( const DMatch &dm ) : DMatch( dm ) {}
|
||||
DMatchForEvaluation( const DMatch &dm ) : DMatch( dm ), isCorrect(0) {}
|
||||
};
|
||||
|
||||
static inline float recall( int correctMatchCount, int correspondenceCount )
|
||||
@@ -492,6 +498,8 @@ void cv::computeRecallPrecisionCurve( const std::vector<std::vector<DMatch> >& m
|
||||
const std::vector<std::vector<uchar> >& correctMatches1to2Mask,
|
||||
std::vector<Point2f>& recallPrecisionCurve )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CV_Assert( matches1to2.size() == correctMatches1to2Mask.size() );
|
||||
|
||||
std::vector<DMatchForEvaluation> allMatches;
|
||||
@@ -526,6 +534,8 @@ void cv::computeRecallPrecisionCurve( const std::vector<std::vector<DMatch> >& m
|
||||
|
||||
float cv::getRecall( const std::vector<Point2f>& recallPrecisionCurve, float l_precision )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
int nearestPointIndex = getNearestPoint( recallPrecisionCurve, l_precision );
|
||||
|
||||
float recall = -1.f;
|
||||
@@ -538,6 +548,8 @@ float cv::getRecall( const std::vector<Point2f>& recallPrecisionCurve, float l_p
|
||||
|
||||
int cv::getNearestPoint( const std::vector<Point2f>& recallPrecisionCurve, float l_precision )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
int nearestPointIndex = -1;
|
||||
|
||||
if( l_precision >= 0 && l_precision <= 1 )
|
||||
@@ -556,56 +568,3 @@ int cv::getNearestPoint( const std::vector<Point2f>& recallPrecisionCurve, float
|
||||
|
||||
return nearestPointIndex;
|
||||
}
|
||||
|
||||
void cv::evaluateGenericDescriptorMatcher( const Mat& img1, const Mat& img2, const Mat& H1to2,
|
||||
std::vector<KeyPoint>& keypoints1, std::vector<KeyPoint>& keypoints2,
|
||||
std::vector<std::vector<DMatch> >* _matches1to2, std::vector<std::vector<uchar> >* _correctMatches1to2Mask,
|
||||
std::vector<Point2f>& recallPrecisionCurve,
|
||||
const Ptr<GenericDescriptorMatcher>& _dmatcher )
|
||||
{
|
||||
Ptr<GenericDescriptorMatcher> dmatcher = _dmatcher;
|
||||
dmatcher->clear();
|
||||
|
||||
std::vector<std::vector<DMatch> > *matches1to2, buf1;
|
||||
matches1to2 = _matches1to2 != 0 ? _matches1to2 : &buf1;
|
||||
|
||||
std::vector<std::vector<uchar> > *correctMatches1to2Mask, buf2;
|
||||
correctMatches1to2Mask = _correctMatches1to2Mask != 0 ? _correctMatches1to2Mask : &buf2;
|
||||
|
||||
if( keypoints1.empty() )
|
||||
CV_Error( Error::StsBadArg, "keypoints1 must not be empty" );
|
||||
|
||||
if( matches1to2->empty() && !dmatcher )
|
||||
CV_Error( Error::StsBadArg, "dmatch must not be empty when matches1to2 is empty" );
|
||||
|
||||
bool computeKeypoints2ByPrj = keypoints2.empty();
|
||||
if( computeKeypoints2ByPrj )
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "");
|
||||
// TODO: add computing keypoints2 from keypoints1 using H1to2
|
||||
}
|
||||
|
||||
if( matches1to2->empty() || computeKeypoints2ByPrj )
|
||||
{
|
||||
dmatcher->clear();
|
||||
dmatcher->radiusMatch( img1, keypoints1, img2, keypoints2, *matches1to2, std::numeric_limits<float>::max() );
|
||||
}
|
||||
float repeatability;
|
||||
int correspCount;
|
||||
Mat thresholdedOverlapMask; // thresholded allOverlapErrors
|
||||
calculateRepeatability( img1, img2, H1to2, keypoints1, keypoints2, repeatability, correspCount, &thresholdedOverlapMask );
|
||||
|
||||
correctMatches1to2Mask->resize(matches1to2->size());
|
||||
for( size_t i = 0; i < matches1to2->size(); i++ )
|
||||
{
|
||||
(*correctMatches1to2Mask)[i].resize((*matches1to2)[i].size());
|
||||
for( size_t j = 0;j < (*matches1to2)[i].size(); j++ )
|
||||
{
|
||||
int indexQuery = (*matches1to2)[i][j].queryIdx;
|
||||
int indexTrain = (*matches1to2)[i][j].trainIdx;
|
||||
(*correctMatches1to2Mask)[i][j] = thresholdedOverlapMask.at<uchar>( indexQuery, indexTrain );
|
||||
}
|
||||
}
|
||||
|
||||
computeRecallPrecisionCurve( *matches1to2, *correctMatches1to2Mask, recallPrecisionCurve );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/* This is FAST corner detector, contributed to OpenCV by the author, Edward Rosten.
|
||||
Below is the original copyright and the references */
|
||||
|
||||
/*
|
||||
Copyright (c) 2006, 2008 Edward Rosten
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
*Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
*Redistributions 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.
|
||||
|
||||
*Neither the name of the University of Cambridge nor the names of
|
||||
its contributors may 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 COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
The references are:
|
||||
* Machine learning for high-speed corner detection,
|
||||
E. Rosten and T. Drummond, ECCV 2006
|
||||
* Faster and better: A machine learning approach to corner detection
|
||||
E. Rosten, R. Porter and T. Drummond, PAMI, 2009
|
||||
*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "fast.hpp"
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace opt_AVX2
|
||||
{
|
||||
|
||||
class FAST_t_patternSize16_AVX2_Impl CV_FINAL: public FAST_t_patternSize16_AVX2
|
||||
{
|
||||
public:
|
||||
FAST_t_patternSize16_AVX2_Impl(int _cols, int _threshold, bool _nonmax_suppression, const int* _pixel):
|
||||
cols(_cols), nonmax_suppression(_nonmax_suppression), pixel(_pixel)
|
||||
{
|
||||
//patternSize = 16
|
||||
t256c = (char)_threshold;
|
||||
threshold = std::min(std::max(_threshold, 0), 255);
|
||||
}
|
||||
|
||||
virtual void process(int &j, const uchar* &ptr, uchar* curr, int* cornerpos, int &ncorners) CV_OVERRIDE
|
||||
{
|
||||
static const __m256i delta256 = _mm256_broadcastsi128_si256(_mm_set1_epi8((char)(-128))), K16_256 = _mm256_broadcastsi128_si256(_mm_set1_epi8((char)8));
|
||||
const __m256i t256 = _mm256_broadcastsi128_si256(_mm_set1_epi8(t256c));
|
||||
for (; j < cols - 32 - 3; j += 32, ptr += 32)
|
||||
{
|
||||
__m256i m0, m1;
|
||||
__m256i v0 = _mm256_loadu_si256((const __m256i*)ptr);
|
||||
|
||||
__m256i v1 = _mm256_xor_si256(_mm256_subs_epu8(v0, t256), delta256);
|
||||
v0 = _mm256_xor_si256(_mm256_adds_epu8(v0, t256), delta256);
|
||||
|
||||
__m256i x0 = _mm256_sub_epi8(_mm256_loadu_si256((const __m256i*)(ptr + pixel[0])), delta256);
|
||||
__m256i x1 = _mm256_sub_epi8(_mm256_loadu_si256((const __m256i*)(ptr + pixel[4])), delta256);
|
||||
__m256i x2 = _mm256_sub_epi8(_mm256_loadu_si256((const __m256i*)(ptr + pixel[8])), delta256);
|
||||
__m256i x3 = _mm256_sub_epi8(_mm256_loadu_si256((const __m256i*)(ptr + pixel[12])), delta256);
|
||||
|
||||
m0 = _mm256_and_si256(_mm256_cmpgt_epi8(x0, v0), _mm256_cmpgt_epi8(x1, v0));
|
||||
m1 = _mm256_and_si256(_mm256_cmpgt_epi8(v1, x0), _mm256_cmpgt_epi8(v1, x1));
|
||||
m0 = _mm256_or_si256(m0, _mm256_and_si256(_mm256_cmpgt_epi8(x1, v0), _mm256_cmpgt_epi8(x2, v0)));
|
||||
m1 = _mm256_or_si256(m1, _mm256_and_si256(_mm256_cmpgt_epi8(v1, x1), _mm256_cmpgt_epi8(v1, x2)));
|
||||
m0 = _mm256_or_si256(m0, _mm256_and_si256(_mm256_cmpgt_epi8(x2, v0), _mm256_cmpgt_epi8(x3, v0)));
|
||||
m1 = _mm256_or_si256(m1, _mm256_and_si256(_mm256_cmpgt_epi8(v1, x2), _mm256_cmpgt_epi8(v1, x3)));
|
||||
m0 = _mm256_or_si256(m0, _mm256_and_si256(_mm256_cmpgt_epi8(x3, v0), _mm256_cmpgt_epi8(x0, v0)));
|
||||
m1 = _mm256_or_si256(m1, _mm256_and_si256(_mm256_cmpgt_epi8(v1, x3), _mm256_cmpgt_epi8(v1, x0)));
|
||||
m0 = _mm256_or_si256(m0, m1);
|
||||
|
||||
unsigned int mask = _mm256_movemask_epi8(m0); //unsigned is important!
|
||||
if (mask == 0){
|
||||
continue;
|
||||
}
|
||||
if ((mask & 0xffff) == 0)
|
||||
{
|
||||
j -= 16;
|
||||
ptr -= 16;
|
||||
continue;
|
||||
}
|
||||
|
||||
__m256i c0 = _mm256_setzero_si256(), c1 = c0, max0 = c0, max1 = c0;
|
||||
for (int k = 0; k < 25; k++)
|
||||
{
|
||||
__m256i x = _mm256_xor_si256(_mm256_loadu_si256((const __m256i*)(ptr + pixel[k])), delta256);
|
||||
m0 = _mm256_cmpgt_epi8(x, v0);
|
||||
m1 = _mm256_cmpgt_epi8(v1, x);
|
||||
|
||||
c0 = _mm256_and_si256(_mm256_sub_epi8(c0, m0), m0);
|
||||
c1 = _mm256_and_si256(_mm256_sub_epi8(c1, m1), m1);
|
||||
|
||||
max0 = _mm256_max_epu8(max0, c0);
|
||||
max1 = _mm256_max_epu8(max1, c1);
|
||||
}
|
||||
|
||||
max0 = _mm256_max_epu8(max0, max1);
|
||||
unsigned int m = _mm256_movemask_epi8(_mm256_cmpgt_epi8(max0, K16_256));
|
||||
|
||||
for (int k = 0; m > 0 && k < 32; k++, m >>= 1)
|
||||
if (m & 1)
|
||||
{
|
||||
cornerpos[ncorners++] = j + k;
|
||||
if (nonmax_suppression)
|
||||
{
|
||||
short d[25];
|
||||
for (int q = 0; q < 25; q++)
|
||||
d[q] = (short)(ptr[k] - ptr[k + pixel[q]]);
|
||||
v_int16x8 q0 = v_setall_s16(-1000), q1 = v_setall_s16(1000);
|
||||
for (int q = 0; q < 16; q += 8)
|
||||
{
|
||||
v_int16x8 v0_ = v_load(d + q + 1);
|
||||
v_int16x8 v1_ = v_load(d + q + 2);
|
||||
v_int16x8 a = v_min(v0_, v1_);
|
||||
v_int16x8 b = v_max(v0_, v1_);
|
||||
v0_ = v_load(d + q + 3);
|
||||
a = v_min(a, v0_);
|
||||
b = v_max(b, v0_);
|
||||
v0_ = v_load(d + q + 4);
|
||||
a = v_min(a, v0_);
|
||||
b = v_max(b, v0_);
|
||||
v0_ = v_load(d + q + 5);
|
||||
a = v_min(a, v0_);
|
||||
b = v_max(b, v0_);
|
||||
v0_ = v_load(d + q + 6);
|
||||
a = v_min(a, v0_);
|
||||
b = v_max(b, v0_);
|
||||
v0_ = v_load(d + q + 7);
|
||||
a = v_min(a, v0_);
|
||||
b = v_max(b, v0_);
|
||||
v0_ = v_load(d + q + 8);
|
||||
a = v_min(a, v0_);
|
||||
b = v_max(b, v0_);
|
||||
v0_ = v_load(d + q);
|
||||
q0 = v_max(q0, v_min(a, v0_));
|
||||
q1 = v_min(q1, v_max(b, v0_));
|
||||
v0_ = v_load(d + q + 9);
|
||||
q0 = v_max(q0, v_min(a, v0_));
|
||||
q1 = v_min(q1, v_max(b, v0_));
|
||||
}
|
||||
q0 = v_max(q0, v_setzero_s16() - q1);
|
||||
curr[j + k] = (uchar)(v_reduce_max(q0) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
_mm256_zeroupper();
|
||||
}
|
||||
|
||||
virtual ~FAST_t_patternSize16_AVX2_Impl() CV_OVERRIDE {};
|
||||
|
||||
private:
|
||||
int cols;
|
||||
char t256c;
|
||||
int threshold;
|
||||
bool nonmax_suppression;
|
||||
const int* pixel;
|
||||
};
|
||||
|
||||
Ptr<FAST_t_patternSize16_AVX2> FAST_t_patternSize16_AVX2::getImpl(int _cols, int _threshold, bool _nonmax_suppression, const int* _pixel)
|
||||
{
|
||||
return Ptr<FAST_t_patternSize16_AVX2>(new FAST_t_patternSize16_AVX2_Impl(_cols, _threshold, _nonmax_suppression, _pixel));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+342
-110
@@ -42,12 +42,14 @@ The references are:
|
||||
*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "fast.hpp"
|
||||
#include "fast_score.hpp"
|
||||
#include "opencl_kernels_features2d.hpp"
|
||||
#include "hal_replacement.hpp"
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
#include "opencv2/core/utils/buffer_area.private.hpp"
|
||||
|
||||
#if defined _MSC_VER
|
||||
# pragma warning( disable : 4127)
|
||||
#endif
|
||||
#include "opencv2/core/openvx/ovx_defs.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
@@ -57,107 +59,146 @@ void FAST_t(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bo
|
||||
{
|
||||
Mat img = _img.getMat();
|
||||
const int K = patternSize/2, N = patternSize + K + 1;
|
||||
#if CV_SSE2
|
||||
const int quarterPatternSize = patternSize/4;
|
||||
(void)quarterPatternSize;
|
||||
#endif
|
||||
int i, j, k, pixel[25];
|
||||
makeOffsets(pixel, (int)img.step, patternSize);
|
||||
|
||||
#if CV_SIMD128
|
||||
const int quarterPatternSize = patternSize/4;
|
||||
v_uint8x16 delta = v_setall_u8(0x80), t = v_setall_u8((char)threshold), K16 = v_setall_u8((char)K);
|
||||
#if CV_TRY_AVX2
|
||||
Ptr<opt_AVX2::FAST_t_patternSize16_AVX2> fast_t_impl_avx2;
|
||||
if(CV_CPU_HAS_SUPPORT_AVX2)
|
||||
fast_t_impl_avx2 = opt_AVX2::FAST_t_patternSize16_AVX2::getImpl(img.cols, threshold, nonmax_suppression, pixel);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
keypoints.clear();
|
||||
|
||||
threshold = std::min(std::max(threshold, 0), 255);
|
||||
|
||||
#if CV_SSE2
|
||||
__m128i delta = _mm_set1_epi8(-128), t = _mm_set1_epi8((char)threshold), K16 = _mm_set1_epi8((char)K);
|
||||
(void)K16;
|
||||
(void)delta;
|
||||
(void)t;
|
||||
#endif
|
||||
uchar threshold_tab[512];
|
||||
for( i = -255; i <= 255; i++ )
|
||||
threshold_tab[i+255] = (uchar)(i < -threshold ? 1 : i > threshold ? 2 : 0);
|
||||
|
||||
AutoBuffer<uchar> _buf((img.cols+16)*3*(sizeof(int) + sizeof(uchar)) + 128);
|
||||
uchar* buf[3];
|
||||
buf[0] = _buf; buf[1] = buf[0] + img.cols; buf[2] = buf[1] + img.cols;
|
||||
int* cpbuf[3];
|
||||
cpbuf[0] = (int*)alignPtr(buf[2] + img.cols, sizeof(int)) + 1;
|
||||
cpbuf[1] = cpbuf[0] + img.cols + 1;
|
||||
cpbuf[2] = cpbuf[1] + img.cols + 1;
|
||||
memset(buf[0], 0, img.cols*3);
|
||||
uchar* buf[3] = { 0 };
|
||||
int* cpbuf[3] = { 0 };
|
||||
utils::BufferArea area;
|
||||
for (unsigned idx = 0; idx < 3; ++idx)
|
||||
{
|
||||
area.allocate(buf[idx], img.cols);
|
||||
area.allocate(cpbuf[idx], img.cols + 1);
|
||||
}
|
||||
area.commit();
|
||||
|
||||
for (unsigned idx = 0; idx < 3; ++idx)
|
||||
{
|
||||
memset(buf[idx], 0, img.cols);
|
||||
}
|
||||
|
||||
for(i = 3; i < img.rows-2; i++)
|
||||
{
|
||||
const uchar* ptr = img.ptr<uchar>(i) + 3;
|
||||
uchar* curr = buf[(i - 3)%3];
|
||||
int* cornerpos = cpbuf[(i - 3)%3];
|
||||
int* cornerpos = cpbuf[(i - 3)%3] + 1; // cornerpos[-1] is used to store a value
|
||||
memset(curr, 0, img.cols);
|
||||
int ncorners = 0;
|
||||
|
||||
if( i < img.rows - 3 )
|
||||
{
|
||||
j = 3;
|
||||
#if CV_SSE2
|
||||
if( patternSize == 16 )
|
||||
#if CV_SIMD128
|
||||
{
|
||||
for(; j < img.cols - 16 - 3; j += 16, ptr += 16)
|
||||
if( patternSize == 16 )
|
||||
{
|
||||
__m128i m0, m1;
|
||||
__m128i v0 = _mm_loadu_si128((const __m128i*)ptr);
|
||||
__m128i v1 = _mm_xor_si128(_mm_subs_epu8(v0, t), delta);
|
||||
v0 = _mm_xor_si128(_mm_adds_epu8(v0, t), delta);
|
||||
|
||||
__m128i x0 = _mm_sub_epi8(_mm_loadu_si128((const __m128i*)(ptr + pixel[0])), delta);
|
||||
__m128i x1 = _mm_sub_epi8(_mm_loadu_si128((const __m128i*)(ptr + pixel[quarterPatternSize])), delta);
|
||||
__m128i x2 = _mm_sub_epi8(_mm_loadu_si128((const __m128i*)(ptr + pixel[2*quarterPatternSize])), delta);
|
||||
__m128i x3 = _mm_sub_epi8(_mm_loadu_si128((const __m128i*)(ptr + pixel[3*quarterPatternSize])), delta);
|
||||
m0 = _mm_and_si128(_mm_cmpgt_epi8(x0, v0), _mm_cmpgt_epi8(x1, v0));
|
||||
m1 = _mm_and_si128(_mm_cmpgt_epi8(v1, x0), _mm_cmpgt_epi8(v1, x1));
|
||||
m0 = _mm_or_si128(m0, _mm_and_si128(_mm_cmpgt_epi8(x1, v0), _mm_cmpgt_epi8(x2, v0)));
|
||||
m1 = _mm_or_si128(m1, _mm_and_si128(_mm_cmpgt_epi8(v1, x1), _mm_cmpgt_epi8(v1, x2)));
|
||||
m0 = _mm_or_si128(m0, _mm_and_si128(_mm_cmpgt_epi8(x2, v0), _mm_cmpgt_epi8(x3, v0)));
|
||||
m1 = _mm_or_si128(m1, _mm_and_si128(_mm_cmpgt_epi8(v1, x2), _mm_cmpgt_epi8(v1, x3)));
|
||||
m0 = _mm_or_si128(m0, _mm_and_si128(_mm_cmpgt_epi8(x3, v0), _mm_cmpgt_epi8(x0, v0)));
|
||||
m1 = _mm_or_si128(m1, _mm_and_si128(_mm_cmpgt_epi8(v1, x3), _mm_cmpgt_epi8(v1, x0)));
|
||||
m0 = _mm_or_si128(m0, m1);
|
||||
int mask = _mm_movemask_epi8(m0);
|
||||
if( mask == 0 )
|
||||
continue;
|
||||
if( (mask & 255) == 0 )
|
||||
#if CV_TRY_AVX2
|
||||
if (fast_t_impl_avx2)
|
||||
fast_t_impl_avx2->process(j, ptr, curr, cornerpos, ncorners);
|
||||
#endif
|
||||
//vz if (j <= (img.cols - 27)) //it doesn't make sense using vectors for less than 8 elements
|
||||
{
|
||||
j -= 8;
|
||||
ptr -= 8;
|
||||
continue;
|
||||
}
|
||||
|
||||
__m128i c0 = _mm_setzero_si128(), c1 = c0, max0 = c0, max1 = c0;
|
||||
for( k = 0; k < N; k++ )
|
||||
{
|
||||
__m128i x = _mm_xor_si128(_mm_loadu_si128((const __m128i*)(ptr + pixel[k])), delta);
|
||||
m0 = _mm_cmpgt_epi8(x, v0);
|
||||
m1 = _mm_cmpgt_epi8(v1, x);
|
||||
|
||||
c0 = _mm_and_si128(_mm_sub_epi8(c0, m0), m0);
|
||||
c1 = _mm_and_si128(_mm_sub_epi8(c1, m1), m1);
|
||||
|
||||
max0 = _mm_max_epu8(max0, c0);
|
||||
max1 = _mm_max_epu8(max1, c1);
|
||||
}
|
||||
|
||||
max0 = _mm_max_epu8(max0, max1);
|
||||
int m = _mm_movemask_epi8(_mm_cmpgt_epi8(max0, K16));
|
||||
|
||||
for( k = 0; m > 0 && k < 16; k++, m >>= 1 )
|
||||
if(m & 1)
|
||||
for (; j < img.cols - 16 - 3; j += 16, ptr += 16)
|
||||
{
|
||||
cornerpos[ncorners++] = j+k;
|
||||
if(nonmax_suppression)
|
||||
curr[j+k] = (uchar)cornerScore<patternSize>(ptr+k, pixel, threshold);
|
||||
v_uint8x16 v = v_load(ptr);
|
||||
v_int8x16 v0 = v_reinterpret_as_s8((v + t) ^ delta);
|
||||
v_int8x16 v1 = v_reinterpret_as_s8((v - t) ^ delta);
|
||||
|
||||
v_int8x16 x0 = v_reinterpret_as_s8(v_sub_wrap(v_load(ptr + pixel[0]), delta));
|
||||
v_int8x16 x1 = v_reinterpret_as_s8(v_sub_wrap(v_load(ptr + pixel[quarterPatternSize]), delta));
|
||||
v_int8x16 x2 = v_reinterpret_as_s8(v_sub_wrap(v_load(ptr + pixel[2*quarterPatternSize]), delta));
|
||||
v_int8x16 x3 = v_reinterpret_as_s8(v_sub_wrap(v_load(ptr + pixel[3*quarterPatternSize]), delta));
|
||||
|
||||
v_int8x16 m0, m1;
|
||||
m0 = (v0 < x0) & (v0 < x1);
|
||||
m1 = (x0 < v1) & (x1 < v1);
|
||||
m0 = m0 | ((v0 < x1) & (v0 < x2));
|
||||
m1 = m1 | ((x1 < v1) & (x2 < v1));
|
||||
m0 = m0 | ((v0 < x2) & (v0 < x3));
|
||||
m1 = m1 | ((x2 < v1) & (x3 < v1));
|
||||
m0 = m0 | ((v0 < x3) & (v0 < x0));
|
||||
m1 = m1 | ((x3 < v1) & (x0 < v1));
|
||||
m0 = m0 | m1;
|
||||
|
||||
if( !v_check_any(m0) )
|
||||
continue;
|
||||
if( !v_check_any(v_combine_low(m0, m0)) )
|
||||
{
|
||||
j -= 8;
|
||||
ptr -= 8;
|
||||
continue;
|
||||
}
|
||||
|
||||
v_int8x16 c0 = v_setzero_s8();
|
||||
v_int8x16 c1 = v_setzero_s8();
|
||||
v_uint8x16 max0 = v_setzero_u8();
|
||||
v_uint8x16 max1 = v_setzero_u8();
|
||||
for( k = 0; k < N; k++ )
|
||||
{
|
||||
v_int8x16 x = v_reinterpret_as_s8(v_load((ptr + pixel[k])) ^ delta);
|
||||
m0 = v0 < x;
|
||||
m1 = x < v1;
|
||||
|
||||
c0 = v_sub_wrap(c0, m0) & m0;
|
||||
c1 = v_sub_wrap(c1, m1) & m1;
|
||||
|
||||
max0 = v_max(max0, v_reinterpret_as_u8(c0));
|
||||
max1 = v_max(max1, v_reinterpret_as_u8(c1));
|
||||
}
|
||||
|
||||
max0 = K16 < v_max(max0, max1);
|
||||
unsigned int m = v_signmask(v_reinterpret_as_s8(max0));
|
||||
|
||||
for( k = 0; m > 0 && k < 16; k++, m >>= 1 )
|
||||
{
|
||||
if( m & 1 )
|
||||
{
|
||||
cornerpos[ncorners++] = j+k;
|
||||
if(nonmax_suppression)
|
||||
{
|
||||
short d[25];
|
||||
for (int _k = 0; _k < 25; _k++)
|
||||
d[_k] = (short)(ptr[k] - ptr[k + pixel[_k]]);
|
||||
|
||||
v_int16x8 a0, b0, a1, b1;
|
||||
a0 = b0 = a1 = b1 = v_load(d + 8);
|
||||
for(int shift = 0; shift < 8; ++shift)
|
||||
{
|
||||
v_int16x8 v_nms = v_load(d + shift);
|
||||
a0 = v_min(a0, v_nms);
|
||||
b0 = v_max(b0, v_nms);
|
||||
v_nms = v_load(d + 9 + shift);
|
||||
a1 = v_min(a1, v_nms);
|
||||
b1 = v_max(b1, v_nms);
|
||||
}
|
||||
curr[j + k] = (uchar)(v_reduce_max(v_max(v_max(a0, a1), v_setzero_s16() - v_min(b0, b1))) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
for( ; j < img.cols - 3; j++, ptr++ )
|
||||
{
|
||||
int v = ptr[0];
|
||||
@@ -232,7 +273,7 @@ void FAST_t(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bo
|
||||
|
||||
const uchar* prev = buf[(i - 4 + 3)%3];
|
||||
const uchar* pprev = buf[(i - 5 + 3)%3];
|
||||
cornerpos = cpbuf[(i - 4 + 3)%3];
|
||||
cornerpos = cpbuf[(i - 4 + 3)%3] + 1; // cornerpos[-1] is used to store a value
|
||||
ncorners = cornerpos[-1];
|
||||
|
||||
for( k = 0; k < ncorners; k++ )
|
||||
@@ -250,6 +291,7 @@ void FAST_t(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bo
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
template<typename pt>
|
||||
struct cmp_pt
|
||||
{
|
||||
@@ -262,7 +304,7 @@ static bool ocl_FAST( InputArray _img, std::vector<KeyPoint>& keypoints,
|
||||
UMat img = _img.getUMat();
|
||||
if( img.cols < 7 || img.rows < 7 )
|
||||
return false;
|
||||
size_t globalsize[] = { img.cols-6, img.rows-6 };
|
||||
size_t globalsize[] = { (size_t)img.cols-6, (size_t)img.rows-6 };
|
||||
|
||||
ocl::Kernel fastKptKernel("FAST_findKeypoints", ocl::features2d::fast_oclsrc);
|
||||
if (fastKptKernel.empty())
|
||||
@@ -306,7 +348,7 @@ static bool ocl_FAST( InputArray _img, std::vector<KeyPoint>& keypoints,
|
||||
if (fastNMSKernel.empty())
|
||||
return false;
|
||||
|
||||
size_t globalsize_nms[] = { counter };
|
||||
size_t globalsize_nms[] = { (size_t)counter };
|
||||
if( !fastNMSKernel.args(ocl::KernelArg::PtrReadOnly(kp1),
|
||||
ocl::KernelArg::PtrReadWrite(kp2),
|
||||
ocl::KernelArg::ReadOnly(img),
|
||||
@@ -326,60 +368,250 @@ static bool ocl_FAST( InputArray _img, std::vector<KeyPoint>& keypoints,
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_OPENVX
|
||||
namespace ovx {
|
||||
template <> inline bool skipSmallImages<VX_KERNEL_FAST_CORNERS>(int w, int h) { return w*h < 800 * 600; }
|
||||
}
|
||||
static bool openvx_FAST(InputArray _img, std::vector<KeyPoint>& keypoints,
|
||||
int _threshold, bool nonmaxSuppression, int type)
|
||||
{
|
||||
using namespace ivx;
|
||||
|
||||
// Nonmax suppression is done differently in OpenCV than in OpenVX
|
||||
// 9/16 is the only supported mode in OpenVX
|
||||
if(nonmaxSuppression || type != FastFeatureDetector::TYPE_9_16)
|
||||
return false;
|
||||
|
||||
Mat imgMat = _img.getMat();
|
||||
if(imgMat.empty() || imgMat.type() != CV_8UC1)
|
||||
return false;
|
||||
|
||||
if (ovx::skipSmallImages<VX_KERNEL_FAST_CORNERS>(imgMat.cols, imgMat.rows))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
Context context = ovx::getOpenVXContext();
|
||||
Image img = Image::createFromHandle(context, Image::matTypeToFormat(imgMat.type()),
|
||||
Image::createAddressing(imgMat), (void*)imgMat.data);
|
||||
ivx::Scalar threshold = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, _threshold);
|
||||
vx_size capacity = imgMat.cols * imgMat.rows;
|
||||
Array corners = Array::create(context, VX_TYPE_KEYPOINT, capacity);
|
||||
|
||||
ivx::Scalar numCorners = ivx::Scalar::create<VX_TYPE_SIZE>(context, 0);
|
||||
|
||||
IVX_CHECK_STATUS(vxuFastCorners(context, img, threshold, (vx_bool)nonmaxSuppression, corners, numCorners));
|
||||
|
||||
size_t nPoints = numCorners.getValue<vx_size>();
|
||||
keypoints.clear(); keypoints.reserve(nPoints);
|
||||
std::vector<vx_keypoint_t> vxCorners;
|
||||
corners.copyTo(vxCorners);
|
||||
for(size_t i = 0; i < nPoints; i++)
|
||||
{
|
||||
vx_keypoint_t kp = vxCorners[i];
|
||||
//if nonmaxSuppression is false, kp.strength is undefined
|
||||
keypoints.push_back(KeyPoint((float)kp.x, (float)kp.y, 7.f, -1, kp.strength));
|
||||
}
|
||||
|
||||
#ifdef VX_VERSION_1_1
|
||||
//we should take user memory back before release
|
||||
//(it's not done automatically according to standard)
|
||||
img.swapHandle();
|
||||
#endif
|
||||
}
|
||||
catch (const RuntimeError & e)
|
||||
{
|
||||
VX_DbgThrow(e.what());
|
||||
}
|
||||
catch (const WrapperError & e)
|
||||
{
|
||||
VX_DbgThrow(e.what());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline int hal_FAST(cv::Mat& src, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression, int type)
|
||||
{
|
||||
if (threshold > 20)
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
cv::Mat scores(src.size(), src.type());
|
||||
|
||||
int error = cv_hal_FAST_dense(src.data, src.step, scores.data, scores.step, src.cols, src.rows, type);
|
||||
|
||||
if (error != CV_HAL_ERROR_OK)
|
||||
return error;
|
||||
|
||||
cv::Mat suppressedScores(src.size(), src.type());
|
||||
|
||||
if (nonmax_suppression)
|
||||
{
|
||||
error = cv_hal_FAST_NMS(scores.data, scores.step, suppressedScores.data, suppressedScores.step, scores.cols, scores.rows);
|
||||
|
||||
if (error != CV_HAL_ERROR_OK)
|
||||
return error;
|
||||
}
|
||||
else
|
||||
{
|
||||
suppressedScores = scores;
|
||||
}
|
||||
|
||||
if (!threshold && nonmax_suppression) threshold = 1;
|
||||
|
||||
cv::KeyPoint kpt(0, 0, 7.f, -1, 0);
|
||||
|
||||
unsigned uthreshold = (unsigned) threshold;
|
||||
|
||||
int ofs = 3;
|
||||
|
||||
int stride = (int)suppressedScores.step;
|
||||
const unsigned char* pscore = suppressedScores.data;
|
||||
|
||||
keypoints.clear();
|
||||
|
||||
for (int y = ofs; y + ofs < suppressedScores.rows; ++y)
|
||||
{
|
||||
kpt.pt.y = (float)(y);
|
||||
for (int x = ofs; x + ofs < suppressedScores.cols; ++x)
|
||||
{
|
||||
unsigned score = pscore[y * stride + x];
|
||||
if (score > uthreshold)
|
||||
{
|
||||
kpt.pt.x = (float)(x);
|
||||
kpt.response = (nonmax_suppression != 0) ? (float)((int)score - 1) : 0.f;
|
||||
keypoints.push_back(kpt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression, int type)
|
||||
{
|
||||
if( ocl::useOpenCL() && _img.isUMat() && type == FastFeatureDetector::TYPE_9_16 &&
|
||||
ocl_FAST(_img, keypoints, threshold, nonmax_suppression, 10000))
|
||||
return;
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
switch(type) {
|
||||
CV_OCL_RUN(_img.isUMat() && type == FastFeatureDetector::TYPE_9_16,
|
||||
ocl_FAST(_img, keypoints, threshold, nonmax_suppression, 10000));
|
||||
|
||||
cv::Mat img = _img.getMat();
|
||||
CALL_HAL(fast_dense, hal_FAST, img, keypoints, threshold, nonmax_suppression, type);
|
||||
|
||||
size_t keypoints_count;
|
||||
CALL_HAL(fast, cv_hal_FAST, img.data, img.step, img.cols, img.rows,
|
||||
(uchar*)(keypoints.data()), &keypoints_count, threshold, nonmax_suppression, type);
|
||||
|
||||
CV_OVX_RUN(true,
|
||||
openvx_FAST(_img, keypoints, threshold, nonmax_suppression, type))
|
||||
|
||||
switch(type) {
|
||||
case FastFeatureDetector::TYPE_5_8:
|
||||
FAST_t<8>(_img, keypoints, threshold, nonmax_suppression);
|
||||
break;
|
||||
FAST_t<8>(_img, keypoints, threshold, nonmax_suppression);
|
||||
break;
|
||||
case FastFeatureDetector::TYPE_7_12:
|
||||
FAST_t<12>(_img, keypoints, threshold, nonmax_suppression);
|
||||
break;
|
||||
FAST_t<12>(_img, keypoints, threshold, nonmax_suppression);
|
||||
break;
|
||||
case FastFeatureDetector::TYPE_9_16:
|
||||
#ifdef HAVE_TEGRA_OPTIMIZATION
|
||||
if(tegra::FAST(_img, keypoints, threshold, nonmax_suppression))
|
||||
break;
|
||||
if(tegra::useTegra() && tegra::FAST(_img, keypoints, threshold, nonmax_suppression))
|
||||
break;
|
||||
#endif
|
||||
FAST_t<16>(_img, keypoints, threshold, nonmax_suppression);
|
||||
break;
|
||||
}
|
||||
FAST_t<16>(_img, keypoints, threshold, nonmax_suppression);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
FAST(_img, keypoints, threshold, nonmax_suppression, FastFeatureDetector::TYPE_9_16);
|
||||
}
|
||||
/*
|
||||
* FastFeatureDetector
|
||||
*/
|
||||
FastFeatureDetector::FastFeatureDetector( int _threshold, bool _nonmaxSuppression )
|
||||
: threshold(_threshold), nonmaxSuppression(_nonmaxSuppression), type(FastFeatureDetector::TYPE_9_16)
|
||||
{}
|
||||
|
||||
FastFeatureDetector::FastFeatureDetector( int _threshold, bool _nonmaxSuppression, int _type )
|
||||
: threshold(_threshold), nonmaxSuppression(_nonmaxSuppression), type((short)_type)
|
||||
{}
|
||||
|
||||
void FastFeatureDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) const
|
||||
class FastFeatureDetector_Impl CV_FINAL : public FastFeatureDetector
|
||||
{
|
||||
Mat mask = _mask.getMat(), grayImage;
|
||||
UMat ugrayImage;
|
||||
_InputArray gray = _image;
|
||||
if( _image.type() != CV_8U )
|
||||
public:
|
||||
FastFeatureDetector_Impl( int _threshold, bool _nonmaxSuppression, int _type )
|
||||
: threshold(_threshold), nonmaxSuppression(_nonmaxSuppression), type((short)_type)
|
||||
{}
|
||||
|
||||
void detect( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) CV_OVERRIDE
|
||||
{
|
||||
_OutputArray ogray = _image.isUMat() ? _OutputArray(ugrayImage) : _OutputArray(grayImage);
|
||||
cvtColor( _image, ogray, COLOR_BGR2GRAY );
|
||||
gray = ogray;
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
if(_image.empty())
|
||||
{
|
||||
keypoints.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
Mat mask = _mask.getMat(), grayImage;
|
||||
UMat ugrayImage;
|
||||
_InputArray gray = _image;
|
||||
if( _image.type() != CV_8U )
|
||||
{
|
||||
_OutputArray ogray = _image.isUMat() ? _OutputArray(ugrayImage) : _OutputArray(grayImage);
|
||||
cvtColor( _image, ogray, COLOR_BGR2GRAY );
|
||||
gray = ogray;
|
||||
}
|
||||
FAST( gray, keypoints, threshold, nonmaxSuppression, type );
|
||||
KeyPointsFilter::runByPixelsMask( keypoints, mask );
|
||||
}
|
||||
FAST( gray, keypoints, threshold, nonmaxSuppression, type );
|
||||
KeyPointsFilter::runByPixelsMask( keypoints, mask );
|
||||
|
||||
void set(int prop, double value)
|
||||
{
|
||||
if(prop == THRESHOLD)
|
||||
threshold = cvRound(value);
|
||||
else if(prop == NONMAX_SUPPRESSION)
|
||||
nonmaxSuppression = value != 0;
|
||||
else if(prop == FAST_N)
|
||||
type = cvRound(value);
|
||||
else
|
||||
CV_Error(Error::StsBadArg, "");
|
||||
}
|
||||
|
||||
double get(int prop) const
|
||||
{
|
||||
if(prop == THRESHOLD)
|
||||
return threshold;
|
||||
if(prop == NONMAX_SUPPRESSION)
|
||||
return nonmaxSuppression;
|
||||
if(prop == FAST_N)
|
||||
return type;
|
||||
CV_Error(Error::StsBadArg, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setThreshold(int threshold_) CV_OVERRIDE { threshold = threshold_; }
|
||||
int getThreshold() const CV_OVERRIDE { return threshold; }
|
||||
|
||||
void setNonmaxSuppression(bool f) CV_OVERRIDE { nonmaxSuppression = f; }
|
||||
bool getNonmaxSuppression() const CV_OVERRIDE { return nonmaxSuppression; }
|
||||
|
||||
void setType(int type_) CV_OVERRIDE { type = type_; }
|
||||
int getType() const CV_OVERRIDE { return type; }
|
||||
|
||||
int threshold;
|
||||
bool nonmaxSuppression;
|
||||
int type;
|
||||
};
|
||||
|
||||
Ptr<FastFeatureDetector> FastFeatureDetector::create( int threshold, bool nonmaxSuppression, int type )
|
||||
{
|
||||
return makePtr<FastFeatureDetector_Impl>(threshold, nonmaxSuppression, type);
|
||||
}
|
||||
|
||||
String FastFeatureDetector::getDefaultName() const
|
||||
{
|
||||
return (Feature2D::getDefaultName() + ".FastFeatureDetector");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/* This is FAST corner detector, contributed to OpenCV by the author, Edward Rosten.
|
||||
Below is the original copyright and the references */
|
||||
|
||||
/*
|
||||
Copyright (c) 2006, 2008 Edward Rosten
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
*Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
*Redistributions 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.
|
||||
|
||||
*Neither the name of the University of Cambridge nor the names of
|
||||
its contributors may 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 COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
The references are:
|
||||
* Machine learning for high-speed corner detection,
|
||||
E. Rosten and T. Drummond, ECCV 2006
|
||||
* Faster and better: A machine learning approach to corner detection
|
||||
E. Rosten, R. Porter and T. Drummond, PAMI, 2009
|
||||
*/
|
||||
|
||||
#ifndef OPENCV_FEATURES2D_FAST_HPP
|
||||
#define OPENCV_FEATURES2D_FAST_HPP
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace opt_AVX2
|
||||
{
|
||||
#if CV_TRY_AVX2
|
||||
class FAST_t_patternSize16_AVX2
|
||||
{
|
||||
public:
|
||||
static Ptr<FAST_t_patternSize16_AVX2> getImpl(int _cols, int _threshold, bool _nonmax_suppression, const int* _pixel);
|
||||
virtual void process(int &j, const uchar* &ptr, uchar* curr, int* cornerpos, int &ncorners) = 0;
|
||||
virtual ~FAST_t_patternSize16_AVX2() {};
|
||||
};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -42,7 +42,7 @@ The references are:
|
||||
*/
|
||||
|
||||
#include "fast_score.hpp"
|
||||
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
#define VERIFY_CORNERS 0
|
||||
|
||||
namespace cv {
|
||||
@@ -125,80 +125,83 @@ int cornerScore<16>(const uchar* ptr, const int pixel[], int threshold)
|
||||
for( k = 0; k < N; k++ )
|
||||
d[k] = (short)(v - ptr[pixel[k]]);
|
||||
|
||||
#if CV_SSE2
|
||||
__m128i q0 = _mm_set1_epi16(-1000), q1 = _mm_set1_epi16(1000);
|
||||
for( k = 0; k < 16; k += 8 )
|
||||
#if CV_SIMD128
|
||||
if (true)
|
||||
{
|
||||
__m128i v0 = _mm_loadu_si128((__m128i*)(d+k+1));
|
||||
__m128i v1 = _mm_loadu_si128((__m128i*)(d+k+2));
|
||||
__m128i a = _mm_min_epi16(v0, v1);
|
||||
__m128i b = _mm_max_epi16(v0, v1);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+3));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+4));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+5));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+6));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+7));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+8));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k));
|
||||
q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
|
||||
q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+9));
|
||||
q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
|
||||
q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
|
||||
v_int16x8 q0 = v_setall_s16(-1000), q1 = v_setall_s16(1000);
|
||||
for (k = 0; k < 16; k += 8)
|
||||
{
|
||||
v_int16x8 v0 = v_load(d + k + 1);
|
||||
v_int16x8 v1 = v_load(d + k + 2);
|
||||
v_int16x8 a = v_min(v0, v1);
|
||||
v_int16x8 b = v_max(v0, v1);
|
||||
v0 = v_load(d + k + 3);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d + k + 4);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d + k + 5);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d + k + 6);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d + k + 7);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d + k + 8);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d + k);
|
||||
q0 = v_max(q0, v_min(a, v0));
|
||||
q1 = v_min(q1, v_max(b, v0));
|
||||
v0 = v_load(d + k + 9);
|
||||
q0 = v_max(q0, v_min(a, v0));
|
||||
q1 = v_min(q1, v_max(b, v0));
|
||||
}
|
||||
q0 = v_max(q0, v_setzero_s16() - q1);
|
||||
threshold = v_reduce_max(q0) - 1;
|
||||
}
|
||||
q0 = _mm_max_epi16(q0, _mm_sub_epi16(_mm_setzero_si128(), q1));
|
||||
q0 = _mm_max_epi16(q0, _mm_unpackhi_epi64(q0, q0));
|
||||
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 4));
|
||||
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 2));
|
||||
threshold = (short)_mm_cvtsi128_si32(q0) - 1;
|
||||
#else
|
||||
int a0 = threshold;
|
||||
for( k = 0; k < 16; k += 2 )
|
||||
{
|
||||
int a = std::min((int)d[k+1], (int)d[k+2]);
|
||||
a = std::min(a, (int)d[k+3]);
|
||||
if( a <= a0 )
|
||||
continue;
|
||||
a = std::min(a, (int)d[k+4]);
|
||||
a = std::min(a, (int)d[k+5]);
|
||||
a = std::min(a, (int)d[k+6]);
|
||||
a = std::min(a, (int)d[k+7]);
|
||||
a = std::min(a, (int)d[k+8]);
|
||||
a0 = std::max(a0, std::min(a, (int)d[k]));
|
||||
a0 = std::max(a0, std::min(a, (int)d[k+9]));
|
||||
}
|
||||
|
||||
int b0 = -a0;
|
||||
for( k = 0; k < 16; k += 2 )
|
||||
{
|
||||
int b = std::max((int)d[k+1], (int)d[k+2]);
|
||||
b = std::max(b, (int)d[k+3]);
|
||||
b = std::max(b, (int)d[k+4]);
|
||||
b = std::max(b, (int)d[k+5]);
|
||||
if( b >= b0 )
|
||||
continue;
|
||||
b = std::max(b, (int)d[k+6]);
|
||||
b = std::max(b, (int)d[k+7]);
|
||||
b = std::max(b, (int)d[k+8]);
|
||||
|
||||
b0 = std::min(b0, std::max(b, (int)d[k]));
|
||||
b0 = std::min(b0, std::max(b, (int)d[k+9]));
|
||||
}
|
||||
|
||||
threshold = -b0-1;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
|
||||
int a0 = threshold;
|
||||
for( k = 0; k < 16; k += 2 )
|
||||
{
|
||||
int a = std::min((int)d[k+1], (int)d[k+2]);
|
||||
a = std::min(a, (int)d[k+3]);
|
||||
if( a <= a0 )
|
||||
continue;
|
||||
a = std::min(a, (int)d[k+4]);
|
||||
a = std::min(a, (int)d[k+5]);
|
||||
a = std::min(a, (int)d[k+6]);
|
||||
a = std::min(a, (int)d[k+7]);
|
||||
a = std::min(a, (int)d[k+8]);
|
||||
a0 = std::max(a0, std::min(a, (int)d[k]));
|
||||
a0 = std::max(a0, std::min(a, (int)d[k+9]));
|
||||
}
|
||||
|
||||
int b0 = -a0;
|
||||
for( k = 0; k < 16; k += 2 )
|
||||
{
|
||||
int b = std::max((int)d[k+1], (int)d[k+2]);
|
||||
b = std::max(b, (int)d[k+3]);
|
||||
b = std::max(b, (int)d[k+4]);
|
||||
b = std::max(b, (int)d[k+5]);
|
||||
if( b >= b0 )
|
||||
continue;
|
||||
b = std::max(b, (int)d[k+6]);
|
||||
b = std::max(b, (int)d[k+7]);
|
||||
b = std::max(b, (int)d[k+8]);
|
||||
|
||||
b0 = std::min(b0, std::max(b, (int)d[k]));
|
||||
b0 = std::min(b0, std::max(b, (int)d[k+9]));
|
||||
}
|
||||
|
||||
threshold = -b0 - 1;
|
||||
}
|
||||
|
||||
#if VERIFY_CORNERS
|
||||
testCorner(ptr, pixel, K, N, threshold);
|
||||
@@ -214,76 +217,77 @@ int cornerScore<12>(const uchar* ptr, const int pixel[], int threshold)
|
||||
short d[N + 4];
|
||||
for( k = 0; k < N; k++ )
|
||||
d[k] = (short)(v - ptr[pixel[k]]);
|
||||
#if CV_SSE2
|
||||
#if CV_SIMD128
|
||||
for( k = 0; k < 4; k++ )
|
||||
d[N+k] = d[k];
|
||||
#endif
|
||||
|
||||
#if CV_SSE2
|
||||
__m128i q0 = _mm_set1_epi16(-1000), q1 = _mm_set1_epi16(1000);
|
||||
for( k = 0; k < 16; k += 8 )
|
||||
#if CV_SIMD128
|
||||
if (true)
|
||||
{
|
||||
__m128i v0 = _mm_loadu_si128((__m128i*)(d+k+1));
|
||||
__m128i v1 = _mm_loadu_si128((__m128i*)(d+k+2));
|
||||
__m128i a = _mm_min_epi16(v0, v1);
|
||||
__m128i b = _mm_max_epi16(v0, v1);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+3));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+4));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+5));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+6));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k));
|
||||
q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
|
||||
q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+k+7));
|
||||
q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
|
||||
q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
|
||||
v_int16x8 q0 = v_setall_s16(-1000), q1 = v_setall_s16(1000);
|
||||
for (k = 0; k < 16; k += 8)
|
||||
{
|
||||
v_int16x8 v0 = v_load(d + k + 1);
|
||||
v_int16x8 v1 = v_load(d + k + 2);
|
||||
v_int16x8 a = v_min(v0, v1);
|
||||
v_int16x8 b = v_max(v0, v1);
|
||||
v0 = v_load(d + k + 3);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d + k + 4);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d + k + 5);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d + k + 6);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d + k);
|
||||
q0 = v_max(q0, v_min(a, v0));
|
||||
q1 = v_min(q1, v_max(b, v0));
|
||||
v0 = v_load(d + k + 7);
|
||||
q0 = v_max(q0, v_min(a, v0));
|
||||
q1 = v_min(q1, v_max(b, v0));
|
||||
}
|
||||
q0 = v_max(q0, v_setzero_s16() - q1);
|
||||
threshold = v_reduce_max(q0) - 1;
|
||||
}
|
||||
q0 = _mm_max_epi16(q0, _mm_sub_epi16(_mm_setzero_si128(), q1));
|
||||
q0 = _mm_max_epi16(q0, _mm_unpackhi_epi64(q0, q0));
|
||||
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 4));
|
||||
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 2));
|
||||
threshold = (short)_mm_cvtsi128_si32(q0) - 1;
|
||||
#else
|
||||
int a0 = threshold;
|
||||
for( k = 0; k < 12; k += 2 )
|
||||
{
|
||||
int a = std::min((int)d[k+1], (int)d[k+2]);
|
||||
if( a <= a0 )
|
||||
continue;
|
||||
a = std::min(a, (int)d[k+3]);
|
||||
a = std::min(a, (int)d[k+4]);
|
||||
a = std::min(a, (int)d[k+5]);
|
||||
a = std::min(a, (int)d[k+6]);
|
||||
a0 = std::max(a0, std::min(a, (int)d[k]));
|
||||
a0 = std::max(a0, std::min(a, (int)d[k+7]));
|
||||
}
|
||||
|
||||
int b0 = -a0;
|
||||
for( k = 0; k < 12; k += 2 )
|
||||
{
|
||||
int b = std::max((int)d[k+1], (int)d[k+2]);
|
||||
b = std::max(b, (int)d[k+3]);
|
||||
b = std::max(b, (int)d[k+4]);
|
||||
if( b >= b0 )
|
||||
continue;
|
||||
b = std::max(b, (int)d[k+5]);
|
||||
b = std::max(b, (int)d[k+6]);
|
||||
|
||||
b0 = std::min(b0, std::max(b, (int)d[k]));
|
||||
b0 = std::min(b0, std::max(b, (int)d[k+7]));
|
||||
}
|
||||
|
||||
threshold = -b0-1;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int a0 = threshold;
|
||||
for( k = 0; k < 12; k += 2 )
|
||||
{
|
||||
int a = std::min((int)d[k+1], (int)d[k+2]);
|
||||
if( a <= a0 )
|
||||
continue;
|
||||
a = std::min(a, (int)d[k+3]);
|
||||
a = std::min(a, (int)d[k+4]);
|
||||
a = std::min(a, (int)d[k+5]);
|
||||
a = std::min(a, (int)d[k+6]);
|
||||
a0 = std::max(a0, std::min(a, (int)d[k]));
|
||||
a0 = std::max(a0, std::min(a, (int)d[k+7]));
|
||||
}
|
||||
|
||||
int b0 = -a0;
|
||||
for( k = 0; k < 12; k += 2 )
|
||||
{
|
||||
int b = std::max((int)d[k+1], (int)d[k+2]);
|
||||
b = std::max(b, (int)d[k+3]);
|
||||
b = std::max(b, (int)d[k+4]);
|
||||
if( b >= b0 )
|
||||
continue;
|
||||
b = std::max(b, (int)d[k+5]);
|
||||
b = std::max(b, (int)d[k+6]);
|
||||
|
||||
b0 = std::min(b0, std::max(b, (int)d[k]));
|
||||
b0 = std::min(b0, std::max(b, (int)d[k+7]));
|
||||
}
|
||||
|
||||
threshold = -b0-1;
|
||||
}
|
||||
#if VERIFY_CORNERS
|
||||
testCorner(ptr, pixel, K, N, threshold);
|
||||
#endif
|
||||
@@ -293,62 +297,65 @@ int cornerScore<12>(const uchar* ptr, const int pixel[], int threshold)
|
||||
template<>
|
||||
int cornerScore<8>(const uchar* ptr, const int pixel[], int threshold)
|
||||
{
|
||||
const int K = 4, N = K*3 + 1;
|
||||
const int K = 4, N = K * 3 + 1;
|
||||
int k, v = ptr[0];
|
||||
short d[N];
|
||||
for( k = 0; k < N; k++ )
|
||||
for (k = 0; k < N; k++)
|
||||
d[k] = (short)(v - ptr[pixel[k]]);
|
||||
|
||||
#if CV_SSE2
|
||||
__m128i v0 = _mm_loadu_si128((__m128i*)(d+1));
|
||||
__m128i v1 = _mm_loadu_si128((__m128i*)(d+2));
|
||||
__m128i a = _mm_min_epi16(v0, v1);
|
||||
__m128i b = _mm_max_epi16(v0, v1);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+3));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+4));
|
||||
a = _mm_min_epi16(a, v0);
|
||||
b = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d));
|
||||
__m128i q0 = _mm_min_epi16(a, v0);
|
||||
__m128i q1 = _mm_max_epi16(b, v0);
|
||||
v0 = _mm_loadu_si128((__m128i*)(d+5));
|
||||
q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
|
||||
q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
|
||||
q0 = _mm_max_epi16(q0, _mm_sub_epi16(_mm_setzero_si128(), q1));
|
||||
q0 = _mm_max_epi16(q0, _mm_unpackhi_epi64(q0, q0));
|
||||
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 4));
|
||||
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 2));
|
||||
threshold = (short)_mm_cvtsi128_si32(q0) - 1;
|
||||
#else
|
||||
int a0 = threshold;
|
||||
for( k = 0; k < 8; k += 2 )
|
||||
#if CV_SIMD128 \
|
||||
&& (!defined(CV_SIMD128_CPP) || (!defined(__GNUC__) || __GNUC__ != 5)) // "movdqa" bug on "v_load(d + 1)" line (Ubuntu 16.04 + GCC 5.4)
|
||||
if (true)
|
||||
{
|
||||
int a = std::min((int)d[k+1], (int)d[k+2]);
|
||||
if( a <= a0 )
|
||||
continue;
|
||||
a = std::min(a, (int)d[k+3]);
|
||||
a = std::min(a, (int)d[k+4]);
|
||||
a0 = std::max(a0, std::min(a, (int)d[k]));
|
||||
a0 = std::max(a0, std::min(a, (int)d[k+5]));
|
||||
v_int16x8 v0 = v_load(d + 1);
|
||||
v_int16x8 v1 = v_load(d + 2);
|
||||
v_int16x8 a = v_min(v0, v1);
|
||||
v_int16x8 b = v_max(v0, v1);
|
||||
v0 = v_load(d + 3);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d + 4);
|
||||
a = v_min(a, v0);
|
||||
b = v_max(b, v0);
|
||||
v0 = v_load(d);
|
||||
v_int16x8 q0 = v_min(a, v0);
|
||||
v_int16x8 q1 = v_max(b, v0);
|
||||
v0 = v_load(d + 5);
|
||||
q0 = v_max(q0, v_min(a, v0));
|
||||
q1 = v_min(q1, v_max(b, v0));
|
||||
q0 = v_max(q0, v_setzero_s16() - q1);
|
||||
threshold = v_reduce_max(q0) - 1;
|
||||
}
|
||||
|
||||
int b0 = -a0;
|
||||
for( k = 0; k < 8; k += 2 )
|
||||
{
|
||||
int b = std::max((int)d[k+1], (int)d[k+2]);
|
||||
b = std::max(b, (int)d[k+3]);
|
||||
if( b >= b0 )
|
||||
continue;
|
||||
b = std::max(b, (int)d[k+4]);
|
||||
|
||||
b0 = std::min(b0, std::max(b, (int)d[k]));
|
||||
b0 = std::min(b0, std::max(b, (int)d[k+5]));
|
||||
}
|
||||
|
||||
threshold = -b0-1;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int a0 = threshold;
|
||||
for( k = 0; k < 8; k += 2 )
|
||||
{
|
||||
int a = std::min((int)d[k+1], (int)d[k+2]);
|
||||
if( a <= a0 )
|
||||
continue;
|
||||
a = std::min(a, (int)d[k+3]);
|
||||
a = std::min(a, (int)d[k+4]);
|
||||
a0 = std::max(a0, std::min(a, (int)d[k]));
|
||||
a0 = std::max(a0, std::min(a, (int)d[k+5]));
|
||||
}
|
||||
|
||||
int b0 = -a0;
|
||||
for( k = 0; k < 8; k += 2 )
|
||||
{
|
||||
int b = std::max((int)d[k+1], (int)d[k+2]);
|
||||
b = std::max(b, (int)d[k+3]);
|
||||
if( b >= b0 )
|
||||
continue;
|
||||
b = std::max(b, (int)d[k+4]);
|
||||
|
||||
b0 = std::min(b0, std::max(b, (int)d[k]));
|
||||
b0 = std::min(b0, std::max(b, (int)d[k+5]));
|
||||
}
|
||||
|
||||
threshold = -b0-1;
|
||||
}
|
||||
|
||||
#if VERIFY_CORNERS
|
||||
testCorner(ptr, pixel, K, N, threshold);
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/*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 )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
if( image.empty() )
|
||||
{
|
||||
keypoints.clear();
|
||||
return;
|
||||
}
|
||||
detectAndCompute(image, mask, keypoints, noArray(), false);
|
||||
}
|
||||
|
||||
|
||||
void Feature2D::detect( InputArrayOfArrays _images,
|
||||
std::vector<std::vector<KeyPoint> >& keypoints,
|
||||
InputArrayOfArrays _masks )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
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 )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
if( image.empty() )
|
||||
{
|
||||
descriptors.release();
|
||||
return;
|
||||
}
|
||||
detectAndCompute(image, noArray(), keypoints, descriptors, true);
|
||||
}
|
||||
|
||||
void Feature2D::compute( InputArrayOfArrays _images,
|
||||
std::vector<std::vector<KeyPoint> >& keypoints,
|
||||
OutputArrayOfArrays _descriptors )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
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_INSTRUMENT_REGION();
|
||||
|
||||
CV_Error(Error::StsNotImplemented, "");
|
||||
}
|
||||
|
||||
void Feature2D::write( const String& fileName ) const
|
||||
{
|
||||
FileStorage fs(fileName, FileStorage::WRITE);
|
||||
write(fs);
|
||||
}
|
||||
|
||||
void Feature2D::read( const String& fileName )
|
||||
{
|
||||
FileStorage fs(fileName, FileStorage::READ);
|
||||
read(fs.root());
|
||||
}
|
||||
|
||||
void Feature2D::write( FileStorage&) const
|
||||
{
|
||||
}
|
||||
|
||||
void Feature2D::read( const FileNode&)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
String Feature2D::getDefaultName() const
|
||||
{
|
||||
return "Feature2D";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
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(BriefDescriptorExtractor, "Feature2D.BRIEF",
|
||||
obj.info()->addParam(obj, "bytes", obj.bytes_))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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(StarDetector, "Feature2D.STAR",
|
||||
obj.info()->addParam(obj, "maxSize", obj.maxSize);
|
||||
obj.info()->addParam(obj, "responseThreshold", obj.responseThreshold);
|
||||
obj.info()->addParam(obj, "lineThresholdProjected", obj.lineThresholdProjected);
|
||||
obj.info()->addParam(obj, "lineThresholdBinarized", obj.lineThresholdBinarized);
|
||||
obj.info()->addParam(obj, "suppressNonmaxSize", obj.suppressNonmaxSize))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CV_INIT_ALGORITHM(FREAK, "Feature2D.FREAK",
|
||||
obj.info()->addParam(obj, "orientationNormalized", obj.orientationNormalized);
|
||||
obj.info()->addParam(obj, "scaleNormalized", obj.scaleNormalized);
|
||||
obj.info()->addParam(obj, "patternScale", obj.patternScale);
|
||||
obj.info()->addParam(obj, "nbOctave", obj.nOctaves))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CV_INIT_ALGORITHM(AKAZE, "Feature2D.AKAZE",
|
||||
obj.info()->addParam(obj, "descriptor_channels", obj.descriptor_channels);
|
||||
obj.info()->addParam(obj, "descriptor", obj.descriptor);
|
||||
obj.info()->addParam(obj, "descriptor_size", obj.descriptor_size))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
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(DenseFeatureDetector, "Feature2D.Dense",
|
||||
obj.info()->addParam(obj, "initFeatureScale", obj.initFeatureScale);
|
||||
obj.info()->addParam(obj, "featureScaleLevels", obj.featureScaleLevels);
|
||||
obj.info()->addParam(obj, "featureScaleMul", obj.featureScaleMul);
|
||||
obj.info()->addParam(obj, "initXyStep", obj.initXyStep);
|
||||
obj.info()->addParam(obj, "initImgBound", obj.initImgBound);
|
||||
obj.info()->addParam(obj, "varyXyStepWithScale", obj.varyXyStepWithScale);
|
||||
obj.info()->addParam(obj, "varyImgBoundWithScale", obj.varyImgBoundWithScale))
|
||||
|
||||
CV_INIT_ALGORITHM(GridAdaptedFeatureDetector, "Feature2D.Grid",
|
||||
obj.info()->addParam<FeatureDetector>(obj, "detector", obj.detector, false, 0, 0); // Extra params added to avoid VS2013 fatal error in opencv2/core.hpp (decl. of addParam)
|
||||
obj.info()->addParam(obj, "maxTotalKeypoints", obj.maxTotalKeypoints);
|
||||
obj.info()->addParam(obj, "gridRows", obj.gridRows);
|
||||
obj.info()->addParam(obj, "gridCols", obj.gridCols))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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 &= !BriefDescriptorExtractor_info_auto.name().empty();
|
||||
all &= !BRISK_info_auto.name().empty();
|
||||
all &= !FastFeatureDetector_info_auto.name().empty();
|
||||
all &= !StarDetector_info_auto.name().empty();
|
||||
all &= !MSER_info_auto.name().empty();
|
||||
all &= !FREAK_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 &= !DenseFeatureDetector_info_auto.name().empty();
|
||||
all &= !GridAdaptedFeatureDetector_info_auto.name().empty();
|
||||
all &= !BFMatcher_info_auto.name().empty();
|
||||
all &= !FlannBasedMatcher_info_auto.name().empty();
|
||||
|
||||
return all;
|
||||
}
|
||||
@@ -1,733 +0,0 @@
|
||||
// freak.cpp
|
||||
//
|
||||
// Copyright (C) 2011-2012 Signal processing laboratory 2, EPFL,
|
||||
// Kirell Benzi (kirell.benzi@epfl.ch),
|
||||
// Raphael Ortiz (raphael.ortiz@a3.epfl.ch)
|
||||
// Alexandre Alahi (alexandre.alahi@epfl.ch)
|
||||
// and Pierre Vandergheynst (pierre.vandergheynst@epfl.ch)
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include <fstream>
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <string.h>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
static const double FREAK_SQRT2 = 1.4142135623731;
|
||||
static const double FREAK_LOG2 = 0.693147180559945;
|
||||
static const int FREAK_NB_ORIENTATION = 256;
|
||||
static const int FREAK_NB_POINTS = 43;
|
||||
static const int FREAK_SMALLEST_KP_SIZE = 7; // smallest size of keypoints
|
||||
static const int FREAK_NB_SCALES = FREAK::NB_SCALES;
|
||||
static const int FREAK_NB_PAIRS = FREAK::NB_PAIRS;
|
||||
static const int FREAK_NB_ORIENPAIRS = FREAK::NB_ORIENPAIRS;
|
||||
|
||||
// default pairs
|
||||
static const int FREAK_DEF_PAIRS[FREAK::NB_PAIRS] =
|
||||
{
|
||||
404,431,818,511,181,52,311,874,774,543,719,230,417,205,11,
|
||||
560,149,265,39,306,165,857,250,8,61,15,55,717,44,412,
|
||||
592,134,761,695,660,782,625,487,549,516,271,665,762,392,178,
|
||||
796,773,31,672,845,548,794,677,654,241,831,225,238,849,83,
|
||||
691,484,826,707,122,517,583,731,328,339,571,475,394,472,580,
|
||||
381,137,93,380,327,619,729,808,218,213,459,141,806,341,95,
|
||||
382,568,124,750,193,749,706,843,79,199,317,329,768,198,100,
|
||||
466,613,78,562,783,689,136,838,94,142,164,679,219,419,366,
|
||||
418,423,77,89,523,259,683,312,555,20,470,684,123,458,453,833,
|
||||
72,113,253,108,313,25,153,648,411,607,618,128,305,232,301,84,
|
||||
56,264,371,46,407,360,38,99,176,710,114,578,66,372,653,
|
||||
129,359,424,159,821,10,323,393,5,340,891,9,790,47,0,175,346,
|
||||
236,26,172,147,574,561,32,294,429,724,755,398,787,288,299,
|
||||
769,565,767,722,757,224,465,723,498,467,235,127,802,446,233,
|
||||
544,482,800,318,16,532,801,441,554,173,60,530,713,469,30,
|
||||
212,630,899,170,266,799,88,49,512,399,23,500,107,524,90,
|
||||
194,143,135,192,206,345,148,71,119,101,563,870,158,254,214,
|
||||
276,464,332,725,188,385,24,476,40,231,620,171,258,67,109,
|
||||
844,244,187,388,701,690,50,7,850,479,48,522,22,154,12,659,
|
||||
736,655,577,737,830,811,174,21,237,335,353,234,53,270,62,
|
||||
182,45,177,245,812,673,355,556,612,166,204,54,248,365,226,
|
||||
242,452,700,685,573,14,842,481,468,781,564,416,179,405,35,
|
||||
819,608,624,367,98,643,448,2,460,676,440,240,130,146,184,
|
||||
185,430,65,807,377,82,121,708,239,310,138,596,730,575,477,
|
||||
851,797,247,27,85,586,307,779,326,494,856,324,827,96,748,
|
||||
13,397,125,688,702,92,293,716,277,140,112,4,80,855,839,1,
|
||||
413,347,584,493,289,696,19,751,379,76,73,115,6,590,183,734,
|
||||
197,483,217,344,330,400,186,243,587,220,780,200,793,246,824,
|
||||
41,735,579,81,703,322,760,720,139,480,490,91,814,813,163,
|
||||
152,488,763,263,425,410,576,120,319,668,150,160,302,491,515,
|
||||
260,145,428,97,251,395,272,252,18,106,358,854,485,144,550,
|
||||
131,133,378,68,102,104,58,361,275,209,697,582,338,742,589,
|
||||
325,408,229,28,304,191,189,110,126,486,211,547,533,70,215,
|
||||
670,249,36,581,389,605,331,518,442,822
|
||||
};
|
||||
|
||||
// used to sort pairs during pairs selection
|
||||
struct PairStat
|
||||
{
|
||||
double mean;
|
||||
int idx;
|
||||
};
|
||||
|
||||
struct sortMean
|
||||
{
|
||||
bool operator()( const PairStat& a, const PairStat& b ) const
|
||||
{
|
||||
return a.mean < b.mean;
|
||||
}
|
||||
};
|
||||
|
||||
void FREAK::buildPattern()
|
||||
{
|
||||
if( patternScale == patternScale0 && nOctaves == nOctaves0 && !patternLookup.empty() )
|
||||
return;
|
||||
|
||||
nOctaves0 = nOctaves;
|
||||
patternScale0 = patternScale;
|
||||
|
||||
patternLookup.resize(FREAK_NB_SCALES*FREAK_NB_ORIENTATION*FREAK_NB_POINTS);
|
||||
double scaleStep = std::pow(2.0, (double)(nOctaves)/FREAK_NB_SCALES ); // 2 ^ ( (nOctaves-1) /nbScales)
|
||||
double scalingFactor, alpha, beta, theta = 0;
|
||||
|
||||
// pattern definition, radius normalized to 1.0 (outer point position+sigma=1.0)
|
||||
const int n[8] = {6,6,6,6,6,6,6,1}; // number of points on each concentric circle (from outer to inner)
|
||||
const double bigR(2.0/3.0); // bigger radius
|
||||
const double smallR(2.0/24.0); // smaller radius
|
||||
const double unitSpace( (bigR-smallR)/21.0 ); // define spaces between concentric circles (from center to outer: 1,2,3,4,5,6)
|
||||
// radii of the concentric cirles (from outer to inner)
|
||||
const double radius[8] = {bigR, bigR-6*unitSpace, bigR-11*unitSpace, bigR-15*unitSpace, bigR-18*unitSpace, bigR-20*unitSpace, smallR, 0.0};
|
||||
// sigma of pattern points (each group of 6 points on a concentric cirle has the same sigma)
|
||||
const double sigma[8] = {radius[0]/2.0, radius[1]/2.0, radius[2]/2.0,
|
||||
radius[3]/2.0, radius[4]/2.0, radius[5]/2.0,
|
||||
radius[6]/2.0, radius[6]/2.0
|
||||
};
|
||||
// fill the lookup table
|
||||
for( int scaleIdx=0; scaleIdx < FREAK_NB_SCALES; ++scaleIdx )
|
||||
{
|
||||
patternSizes[scaleIdx] = 0; // proper initialization
|
||||
scalingFactor = std::pow(scaleStep,scaleIdx); //scale of the pattern, scaleStep ^ scaleIdx
|
||||
|
||||
for( int orientationIdx = 0; orientationIdx < FREAK_NB_ORIENTATION; ++orientationIdx )
|
||||
{
|
||||
theta = double(orientationIdx)* 2*CV_PI/double(FREAK_NB_ORIENTATION); // orientation of the pattern
|
||||
int pointIdx = 0;
|
||||
|
||||
PatternPoint* patternLookupPtr = &patternLookup[0];
|
||||
for( size_t i = 0; i < 8; ++i )
|
||||
{
|
||||
for( int k = 0 ; k < n[i]; ++k )
|
||||
{
|
||||
beta = CV_PI/n[i] * (i%2); // orientation offset so that groups of points on each circles are staggered
|
||||
alpha = double(k)* 2*CV_PI/double(n[i])+beta+theta;
|
||||
|
||||
// add the point to the look-up table
|
||||
PatternPoint& point = patternLookupPtr[ scaleIdx*FREAK_NB_ORIENTATION*FREAK_NB_POINTS+orientationIdx*FREAK_NB_POINTS+pointIdx ];
|
||||
point.x = static_cast<float>(radius[i] * cos(alpha) * scalingFactor * patternScale);
|
||||
point.y = static_cast<float>(radius[i] * sin(alpha) * scalingFactor * patternScale);
|
||||
point.sigma = static_cast<float>(sigma[i] * scalingFactor * patternScale);
|
||||
|
||||
// adapt the sizeList if necessary
|
||||
const int sizeMax = static_cast<int>(ceil((radius[i]+sigma[i])*scalingFactor*patternScale)) + 1;
|
||||
if( patternSizes[scaleIdx] < sizeMax )
|
||||
patternSizes[scaleIdx] = sizeMax;
|
||||
|
||||
++pointIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build the list of orientation pairs
|
||||
orientationPairs[0].i=0; orientationPairs[0].j=3; orientationPairs[1].i=1; orientationPairs[1].j=4; orientationPairs[2].i=2; orientationPairs[2].j=5;
|
||||
orientationPairs[3].i=0; orientationPairs[3].j=2; orientationPairs[4].i=1; orientationPairs[4].j=3; orientationPairs[5].i=2; orientationPairs[5].j=4;
|
||||
orientationPairs[6].i=3; orientationPairs[6].j=5; orientationPairs[7].i=4; orientationPairs[7].j=0; orientationPairs[8].i=5; orientationPairs[8].j=1;
|
||||
|
||||
orientationPairs[9].i=6; orientationPairs[9].j=9; orientationPairs[10].i=7; orientationPairs[10].j=10; orientationPairs[11].i=8; orientationPairs[11].j=11;
|
||||
orientationPairs[12].i=6; orientationPairs[12].j=8; orientationPairs[13].i=7; orientationPairs[13].j=9; orientationPairs[14].i=8; orientationPairs[14].j=10;
|
||||
orientationPairs[15].i=9; orientationPairs[15].j=11; orientationPairs[16].i=10; orientationPairs[16].j=6; orientationPairs[17].i=11; orientationPairs[17].j=7;
|
||||
|
||||
orientationPairs[18].i=12; orientationPairs[18].j=15; orientationPairs[19].i=13; orientationPairs[19].j=16; orientationPairs[20].i=14; orientationPairs[20].j=17;
|
||||
orientationPairs[21].i=12; orientationPairs[21].j=14; orientationPairs[22].i=13; orientationPairs[22].j=15; orientationPairs[23].i=14; orientationPairs[23].j=16;
|
||||
orientationPairs[24].i=15; orientationPairs[24].j=17; orientationPairs[25].i=16; orientationPairs[25].j=12; orientationPairs[26].i=17; orientationPairs[26].j=13;
|
||||
|
||||
orientationPairs[27].i=18; orientationPairs[27].j=21; orientationPairs[28].i=19; orientationPairs[28].j=22; orientationPairs[29].i=20; orientationPairs[29].j=23;
|
||||
orientationPairs[30].i=18; orientationPairs[30].j=20; orientationPairs[31].i=19; orientationPairs[31].j=21; orientationPairs[32].i=20; orientationPairs[32].j=22;
|
||||
orientationPairs[33].i=21; orientationPairs[33].j=23; orientationPairs[34].i=22; orientationPairs[34].j=18; orientationPairs[35].i=23; orientationPairs[35].j=19;
|
||||
|
||||
orientationPairs[36].i=24; orientationPairs[36].j=27; orientationPairs[37].i=25; orientationPairs[37].j=28; orientationPairs[38].i=26; orientationPairs[38].j=29;
|
||||
orientationPairs[39].i=30; orientationPairs[39].j=33; orientationPairs[40].i=31; orientationPairs[40].j=34; orientationPairs[41].i=32; orientationPairs[41].j=35;
|
||||
orientationPairs[42].i=36; orientationPairs[42].j=39; orientationPairs[43].i=37; orientationPairs[43].j=40; orientationPairs[44].i=38; orientationPairs[44].j=41;
|
||||
|
||||
for( unsigned m = FREAK_NB_ORIENPAIRS; m--; )
|
||||
{
|
||||
const float dx = patternLookup[orientationPairs[m].i].x-patternLookup[orientationPairs[m].j].x;
|
||||
const float dy = patternLookup[orientationPairs[m].i].y-patternLookup[orientationPairs[m].j].y;
|
||||
const float norm_sq = (dx*dx+dy*dy);
|
||||
orientationPairs[m].weight_dx = int((dx/(norm_sq))*4096.0+0.5);
|
||||
orientationPairs[m].weight_dy = int((dy/(norm_sq))*4096.0+0.5);
|
||||
}
|
||||
|
||||
// build the list of description pairs
|
||||
std::vector<DescriptionPair> allPairs;
|
||||
for( unsigned int i = 1; i < (unsigned int)FREAK_NB_POINTS; ++i )
|
||||
{
|
||||
// (generate all the pairs)
|
||||
for( unsigned int j = 0; (unsigned int)j < i; ++j )
|
||||
{
|
||||
DescriptionPair pair = {(uchar)i,(uchar)j};
|
||||
allPairs.push_back(pair);
|
||||
}
|
||||
}
|
||||
// Input vector provided
|
||||
if( !selectedPairs0.empty() )
|
||||
{
|
||||
if( (int)selectedPairs0.size() == FREAK_NB_PAIRS )
|
||||
{
|
||||
for( int i = 0; i < FREAK_NB_PAIRS; ++i )
|
||||
descriptionPairs[i] = allPairs[selectedPairs0.at(i)];
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Error(Error::StsVecLengthErr, "Input vector does not match the required size");
|
||||
}
|
||||
}
|
||||
else // default selected pairs
|
||||
{
|
||||
for( int i = 0; i < FREAK_NB_PAIRS; ++i )
|
||||
descriptionPairs[i] = allPairs[FREAK_DEF_PAIRS[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void FREAK::computeImpl( InputArray _image, std::vector<KeyPoint>& keypoints, OutputArray _descriptors ) const
|
||||
{
|
||||
Mat image = _image.getMat();
|
||||
if( image.empty() )
|
||||
return;
|
||||
if( keypoints.empty() )
|
||||
return;
|
||||
|
||||
((FREAK*)this)->buildPattern();
|
||||
|
||||
// Convert to gray if not already
|
||||
Mat grayImage = image;
|
||||
// if( image.channels() > 1 )
|
||||
// cvtColor( image, grayImage, COLOR_BGR2GRAY );
|
||||
|
||||
// Use 32-bit integers if we won't overflow in the integral image
|
||||
if ((image.depth() == CV_8U || image.depth() == CV_8S) &&
|
||||
(image.rows * image.cols) < 8388608 ) // 8388608 = 2 ^ (32 - 8(bit depth) - 1(sign bit))
|
||||
{
|
||||
// Create the integral image appropriate for our type & usage
|
||||
if (image.depth() == CV_8U)
|
||||
computeDescriptors<uchar, int>(grayImage, keypoints, _descriptors);
|
||||
else if (image.depth() == CV_8S)
|
||||
computeDescriptors<char, int>(grayImage, keypoints, _descriptors);
|
||||
else
|
||||
CV_Error( Error::StsUnsupportedFormat, "" );
|
||||
} else {
|
||||
// Create the integral image appropriate for our type & usage
|
||||
if ( image.depth() == CV_8U )
|
||||
computeDescriptors<uchar, double>(grayImage, keypoints, _descriptors);
|
||||
else if ( image.depth() == CV_8S )
|
||||
computeDescriptors<char, double>(grayImage, keypoints, _descriptors);
|
||||
else if ( image.depth() == CV_16U )
|
||||
computeDescriptors<ushort, double>(grayImage, keypoints, _descriptors);
|
||||
else if ( image.depth() == CV_16S )
|
||||
computeDescriptors<short, double>(grayImage, keypoints, _descriptors);
|
||||
else
|
||||
CV_Error( Error::StsUnsupportedFormat, "" );
|
||||
}
|
||||
}
|
||||
|
||||
template <typename srcMatType>
|
||||
void FREAK::extractDescriptor(srcMatType *pointsValue, void ** ptr) const
|
||||
{
|
||||
std::bitset<FREAK_NB_PAIRS>** ptrScalar = (std::bitset<FREAK_NB_PAIRS>**) ptr;
|
||||
|
||||
// extracting descriptor preserving the order of SSE version
|
||||
int cnt = 0;
|
||||
for( int n = 7; n < FREAK_NB_PAIRS; n += 128)
|
||||
{
|
||||
for( int m = 8; m--; )
|
||||
{
|
||||
int nm = n-m;
|
||||
for(int kk = nm+15*8; kk >= nm; kk-=8, ++cnt)
|
||||
{
|
||||
(*ptrScalar)->set(kk, pointsValue[descriptionPairs[cnt].i] >= pointsValue[descriptionPairs[cnt].j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
--(*ptrScalar);
|
||||
}
|
||||
|
||||
#if CV_SSE2
|
||||
template <>
|
||||
void FREAK::extractDescriptor(uchar *pointsValue, void ** ptr) const
|
||||
{
|
||||
__m128i** ptrSSE = (__m128i**) ptr;
|
||||
|
||||
// note that comparisons order is modified in each block (but first 128 comparisons remain globally the same-->does not affect the 128,384 bits segmanted matching strategy)
|
||||
int cnt = 0;
|
||||
for( int n = FREAK_NB_PAIRS/128; n-- ; )
|
||||
{
|
||||
__m128i result128 = _mm_setzero_si128();
|
||||
for( int m = 128/16; m--; cnt += 16 )
|
||||
{
|
||||
__m128i operand1 = _mm_set_epi8(pointsValue[descriptionPairs[cnt+0].i],
|
||||
pointsValue[descriptionPairs[cnt+1].i],
|
||||
pointsValue[descriptionPairs[cnt+2].i],
|
||||
pointsValue[descriptionPairs[cnt+3].i],
|
||||
pointsValue[descriptionPairs[cnt+4].i],
|
||||
pointsValue[descriptionPairs[cnt+5].i],
|
||||
pointsValue[descriptionPairs[cnt+6].i],
|
||||
pointsValue[descriptionPairs[cnt+7].i],
|
||||
pointsValue[descriptionPairs[cnt+8].i],
|
||||
pointsValue[descriptionPairs[cnt+9].i],
|
||||
pointsValue[descriptionPairs[cnt+10].i],
|
||||
pointsValue[descriptionPairs[cnt+11].i],
|
||||
pointsValue[descriptionPairs[cnt+12].i],
|
||||
pointsValue[descriptionPairs[cnt+13].i],
|
||||
pointsValue[descriptionPairs[cnt+14].i],
|
||||
pointsValue[descriptionPairs[cnt+15].i]);
|
||||
|
||||
__m128i operand2 = _mm_set_epi8(pointsValue[descriptionPairs[cnt+0].j],
|
||||
pointsValue[descriptionPairs[cnt+1].j],
|
||||
pointsValue[descriptionPairs[cnt+2].j],
|
||||
pointsValue[descriptionPairs[cnt+3].j],
|
||||
pointsValue[descriptionPairs[cnt+4].j],
|
||||
pointsValue[descriptionPairs[cnt+5].j],
|
||||
pointsValue[descriptionPairs[cnt+6].j],
|
||||
pointsValue[descriptionPairs[cnt+7].j],
|
||||
pointsValue[descriptionPairs[cnt+8].j],
|
||||
pointsValue[descriptionPairs[cnt+9].j],
|
||||
pointsValue[descriptionPairs[cnt+10].j],
|
||||
pointsValue[descriptionPairs[cnt+11].j],
|
||||
pointsValue[descriptionPairs[cnt+12].j],
|
||||
pointsValue[descriptionPairs[cnt+13].j],
|
||||
pointsValue[descriptionPairs[cnt+14].j],
|
||||
pointsValue[descriptionPairs[cnt+15].j]);
|
||||
|
||||
__m128i workReg = _mm_min_epu8(operand1, operand2); // emulated "not less than" for 8-bit UNSIGNED integers
|
||||
workReg = _mm_cmpeq_epi8(workReg, operand2); // emulated "not less than" for 8-bit UNSIGNED integers
|
||||
|
||||
workReg = _mm_and_si128(_mm_set1_epi16(short(0x8080 >> m)), workReg); // merge the last 16 bits with the 128bits std::vector until full
|
||||
result128 = _mm_or_si128(result128, workReg);
|
||||
}
|
||||
(**ptrSSE) = result128;
|
||||
++(*ptrSSE);
|
||||
}
|
||||
(*ptrSSE) -= 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename srcMatType, typename iiMatType>
|
||||
void FREAK::computeDescriptors( InputArray _image, std::vector<KeyPoint>& keypoints, OutputArray _descriptors ) const {
|
||||
|
||||
Mat image = _image.getMat();
|
||||
Mat imgIntegral;
|
||||
integral(image, imgIntegral, DataType<iiMatType>::type);
|
||||
std::vector<int> kpScaleIdx(keypoints.size()); // used to save pattern scale index corresponding to each keypoints
|
||||
const std::vector<int>::iterator ScaleIdxBegin = kpScaleIdx.begin(); // used in std::vector erase function
|
||||
const std::vector<cv::KeyPoint>::iterator kpBegin = keypoints.begin(); // used in std::vector erase function
|
||||
const float sizeCst = static_cast<float>(FREAK_NB_SCALES/(FREAK_LOG2* nOctaves));
|
||||
srcMatType pointsValue[FREAK_NB_POINTS];
|
||||
int thetaIdx = 0;
|
||||
int direction0;
|
||||
int direction1;
|
||||
|
||||
// compute the scale index corresponding to the keypoint size and remove keypoints close to the border
|
||||
if( scaleNormalized )
|
||||
{
|
||||
for( size_t k = keypoints.size(); k--; )
|
||||
{
|
||||
//Is k non-zero? If so, decrement it and continue"
|
||||
kpScaleIdx[k] = std::max( (int)(std::log(keypoints[k].size/FREAK_SMALLEST_KP_SIZE)*sizeCst+0.5) ,0);
|
||||
if( kpScaleIdx[k] >= FREAK_NB_SCALES )
|
||||
kpScaleIdx[k] = FREAK_NB_SCALES-1;
|
||||
|
||||
if( keypoints[k].pt.x <= patternSizes[kpScaleIdx[k]] || //check if the description at this specific position and scale fits inside the image
|
||||
keypoints[k].pt.y <= patternSizes[kpScaleIdx[k]] ||
|
||||
keypoints[k].pt.x >= image.cols-patternSizes[kpScaleIdx[k]] ||
|
||||
keypoints[k].pt.y >= image.rows-patternSizes[kpScaleIdx[k]]
|
||||
)
|
||||
{
|
||||
keypoints.erase(kpBegin+k);
|
||||
kpScaleIdx.erase(ScaleIdxBegin+k);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int scIdx = std::max( (int)(1.0986122886681*sizeCst+0.5) ,0);
|
||||
for( size_t k = keypoints.size(); k--; )
|
||||
{
|
||||
kpScaleIdx[k] = scIdx; // equivalent to the formule when the scale is normalized with a constant size of keypoints[k].size=3*SMALLEST_KP_SIZE
|
||||
if( kpScaleIdx[k] >= FREAK_NB_SCALES )
|
||||
{
|
||||
kpScaleIdx[k] = FREAK_NB_SCALES-1;
|
||||
}
|
||||
if( keypoints[k].pt.x <= patternSizes[kpScaleIdx[k]] ||
|
||||
keypoints[k].pt.y <= patternSizes[kpScaleIdx[k]] ||
|
||||
keypoints[k].pt.x >= image.cols-patternSizes[kpScaleIdx[k]] ||
|
||||
keypoints[k].pt.y >= image.rows-patternSizes[kpScaleIdx[k]]
|
||||
)
|
||||
{
|
||||
keypoints.erase(kpBegin+k);
|
||||
kpScaleIdx.erase(ScaleIdxBegin+k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// allocate descriptor memory, estimate orientations, extract descriptors
|
||||
if( !extAll )
|
||||
{
|
||||
// extract the best comparisons only
|
||||
_descriptors.create((int)keypoints.size(), FREAK_NB_PAIRS/8, CV_8U);
|
||||
_descriptors.setTo(Scalar::all(0));
|
||||
Mat descriptors = _descriptors.getMat();
|
||||
|
||||
void *ptr = descriptors.data+(keypoints.size()-1)*descriptors.step[0];
|
||||
|
||||
for( size_t k = keypoints.size(); k--; ) {
|
||||
// estimate orientation (gradient)
|
||||
if( !orientationNormalized )
|
||||
{
|
||||
thetaIdx = 0; // assign 0° to all keypoints
|
||||
keypoints[k].angle = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the points intensity value in the un-rotated pattern
|
||||
for( int i = FREAK_NB_POINTS; i--; ) {
|
||||
pointsValue[i] = meanIntensity<srcMatType, iiMatType>(image, imgIntegral,
|
||||
keypoints[k].pt.x, keypoints[k].pt.y,
|
||||
kpScaleIdx[k], 0, i);
|
||||
}
|
||||
direction0 = 0;
|
||||
direction1 = 0;
|
||||
for( int m = 45; m--; )
|
||||
{
|
||||
//iterate through the orientation pairs
|
||||
const int delta = (pointsValue[ orientationPairs[m].i ]-pointsValue[ orientationPairs[m].j ]);
|
||||
direction0 += delta*(orientationPairs[m].weight_dx)/2048;
|
||||
direction1 += delta*(orientationPairs[m].weight_dy)/2048;
|
||||
}
|
||||
|
||||
keypoints[k].angle = static_cast<float>(atan2((float)direction1,(float)direction0)*(180.0/CV_PI));//estimate orientation
|
||||
thetaIdx = int(FREAK_NB_ORIENTATION*keypoints[k].angle*(1/360.0)+0.5);
|
||||
if( thetaIdx < 0 )
|
||||
thetaIdx += FREAK_NB_ORIENTATION;
|
||||
|
||||
if( thetaIdx >= FREAK_NB_ORIENTATION )
|
||||
thetaIdx -= FREAK_NB_ORIENTATION;
|
||||
}
|
||||
// extract descriptor at the computed orientation
|
||||
for( int i = FREAK_NB_POINTS; i--; ) {
|
||||
pointsValue[i] = meanIntensity<srcMatType, iiMatType>(image, imgIntegral,
|
||||
keypoints[k].pt.x, keypoints[k].pt.y,
|
||||
kpScaleIdx[k], thetaIdx, i);
|
||||
}
|
||||
|
||||
// Extract descriptor
|
||||
extractDescriptor<srcMatType>(pointsValue, &ptr);
|
||||
}
|
||||
}
|
||||
else // extract all possible comparisons for selection
|
||||
{
|
||||
_descriptors.create((int)keypoints.size(), 128, CV_8U);
|
||||
_descriptors.setTo(Scalar::all(0));
|
||||
Mat descriptors = _descriptors.getMat();
|
||||
std::bitset<1024>* ptr = (std::bitset<1024>*) (descriptors.data+(keypoints.size()-1)*descriptors.step[0]);
|
||||
|
||||
for( size_t k = keypoints.size(); k--; )
|
||||
{
|
||||
//estimate orientation (gradient)
|
||||
if( !orientationNormalized )
|
||||
{
|
||||
thetaIdx = 0;//assign 0° to all keypoints
|
||||
keypoints[k].angle = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//get the points intensity value in the un-rotated pattern
|
||||
for( int i = FREAK_NB_POINTS;i--; )
|
||||
pointsValue[i] = meanIntensity<srcMatType, iiMatType>(image, imgIntegral,
|
||||
keypoints[k].pt.x,keypoints[k].pt.y,
|
||||
kpScaleIdx[k], 0, i);
|
||||
|
||||
direction0 = 0;
|
||||
direction1 = 0;
|
||||
for( int m = 45; m--; )
|
||||
{
|
||||
//iterate through the orientation pairs
|
||||
const int delta = (pointsValue[ orientationPairs[m].i ]-pointsValue[ orientationPairs[m].j ]);
|
||||
direction0 += delta*(orientationPairs[m].weight_dx)/2048;
|
||||
direction1 += delta*(orientationPairs[m].weight_dy)/2048;
|
||||
}
|
||||
|
||||
keypoints[k].angle = static_cast<float>(atan2((float)direction1,(float)direction0)*(180.0/CV_PI)); //estimate orientation
|
||||
thetaIdx = int(FREAK_NB_ORIENTATION*keypoints[k].angle*(1/360.0)+0.5);
|
||||
|
||||
if( thetaIdx < 0 )
|
||||
thetaIdx += FREAK_NB_ORIENTATION;
|
||||
|
||||
if( thetaIdx >= FREAK_NB_ORIENTATION )
|
||||
thetaIdx -= FREAK_NB_ORIENTATION;
|
||||
}
|
||||
// get the points intensity value in the rotated pattern
|
||||
for( int i = FREAK_NB_POINTS; i--; ) {
|
||||
pointsValue[i] = meanIntensity<srcMatType, iiMatType>(image, imgIntegral,
|
||||
keypoints[k].pt.x, keypoints[k].pt.y,
|
||||
kpScaleIdx[k], thetaIdx, i);
|
||||
}
|
||||
|
||||
int cnt(0);
|
||||
for( int i = 1; i < FREAK_NB_POINTS; ++i )
|
||||
{
|
||||
//(generate all the pairs)
|
||||
for( int j = 0; j < i; ++j )
|
||||
{
|
||||
ptr->set(cnt, pointsValue[i] >= pointsValue[j] );
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
--ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// simply take average on a square patch, not even gaussian approx
|
||||
template <typename imgType, typename iiType>
|
||||
imgType FREAK::meanIntensity( InputArray _image, InputArray _integral,
|
||||
const float kp_x,
|
||||
const float kp_y,
|
||||
const unsigned int scale,
|
||||
const unsigned int rot,
|
||||
const unsigned int point) const {
|
||||
Mat image = _image.getMat(), integral = _integral.getMat();
|
||||
// get point position in image
|
||||
const PatternPoint& FreakPoint = patternLookup[scale*FREAK_NB_ORIENTATION*FREAK_NB_POINTS + rot*FREAK_NB_POINTS + point];
|
||||
const float xf = FreakPoint.x+kp_x;
|
||||
const float yf = FreakPoint.y+kp_y;
|
||||
const int x = int(xf);
|
||||
const int y = int(yf);
|
||||
|
||||
// get the sigma:
|
||||
const float radius = FreakPoint.sigma;
|
||||
|
||||
// calculate output:
|
||||
if( radius < 0.5 )
|
||||
{
|
||||
// interpolation multipliers:
|
||||
const int r_x = static_cast<int>((xf-x)*1024);
|
||||
const int r_y = static_cast<int>((yf-y)*1024);
|
||||
const int r_x_1 = (1024-r_x);
|
||||
const int r_y_1 = (1024-r_y);
|
||||
unsigned int ret_val;
|
||||
// linear interpolation:
|
||||
ret_val = r_x_1*r_y_1*int(image.at<imgType>(y , x ))
|
||||
+ r_x *r_y_1*int(image.at<imgType>(y , x+1))
|
||||
+ r_x_1*r_y *int(image.at<imgType>(y+1, x ))
|
||||
+ r_x *r_y *int(image.at<imgType>(y+1, x+1));
|
||||
//return the rounded mean
|
||||
ret_val += 2 * 1024 * 1024;
|
||||
return static_cast<imgType>(ret_val / (4 * 1024 * 1024));
|
||||
}
|
||||
|
||||
// expected case:
|
||||
|
||||
// calculate borders
|
||||
const int x_left = int(xf-radius+0.5);
|
||||
const int y_top = int(yf-radius+0.5);
|
||||
const int x_right = int(xf+radius+1.5);//integral image is 1px wider
|
||||
const int y_bottom = int(yf+radius+1.5);//integral image is 1px higher
|
||||
iiType ret_val;
|
||||
|
||||
ret_val = integral.at<iiType>(y_bottom,x_right);//bottom right corner
|
||||
ret_val -= integral.at<iiType>(y_bottom,x_left);
|
||||
ret_val += integral.at<iiType>(y_top,x_left);
|
||||
ret_val -= integral.at<iiType>(y_top,x_right);
|
||||
ret_val = ret_val/( (x_right-x_left)* (y_bottom-y_top) );
|
||||
//~ std::cout<<integral.step[1]<<std::endl;
|
||||
return static_cast<imgType>(ret_val);
|
||||
}
|
||||
|
||||
// pair selection algorithm from a set of training images and corresponding keypoints
|
||||
std::vector<int> FREAK::selectPairs(const std::vector<Mat>& images
|
||||
, std::vector<std::vector<KeyPoint> >& keypoints
|
||||
, const double corrTresh
|
||||
, bool verbose )
|
||||
{
|
||||
extAll = true;
|
||||
// compute descriptors with all pairs
|
||||
Mat descriptors;
|
||||
|
||||
if( verbose )
|
||||
std::cout << "Number of images: " << images.size() << std::endl;
|
||||
|
||||
for( size_t i = 0;i < images.size(); ++i )
|
||||
{
|
||||
Mat descriptorsTmp;
|
||||
computeImpl(images[i],keypoints[i],descriptorsTmp);
|
||||
descriptors.push_back(descriptorsTmp);
|
||||
}
|
||||
|
||||
if( verbose )
|
||||
std::cout << "number of keypoints: " << descriptors.rows << std::endl;
|
||||
|
||||
//descriptor in floating point format (each bit is a float)
|
||||
Mat descriptorsFloat = Mat::zeros(descriptors.rows, 903, CV_32F);
|
||||
|
||||
std::bitset<1024>* ptr = (std::bitset<1024>*) (descriptors.data+(descriptors.rows-1)*descriptors.step[0]);
|
||||
for( int m = descriptors.rows; m--; )
|
||||
{
|
||||
for( int n = 903; n--; )
|
||||
{
|
||||
if( ptr->test(n) == true )
|
||||
descriptorsFloat.at<float>(m,n)=1.0f;
|
||||
}
|
||||
--ptr;
|
||||
}
|
||||
|
||||
std::vector<PairStat> pairStat;
|
||||
for( int n = 903; n--; )
|
||||
{
|
||||
// the higher the variance, the better --> mean = 0.5
|
||||
PairStat tmp = { fabs( mean(descriptorsFloat.col(n))[0]-0.5 ) ,n};
|
||||
pairStat.push_back(tmp);
|
||||
}
|
||||
|
||||
std::sort( pairStat.begin(),pairStat.end(), sortMean() );
|
||||
|
||||
std::vector<PairStat> bestPairs;
|
||||
for( int m = 0; m < 903; ++m )
|
||||
{
|
||||
if( verbose )
|
||||
std::cout << m << ":" << bestPairs.size() << " " << std::flush;
|
||||
double corrMax(0);
|
||||
|
||||
for( size_t n = 0; n < bestPairs.size(); ++n )
|
||||
{
|
||||
int idxA = bestPairs[n].idx;
|
||||
int idxB = pairStat[m].idx;
|
||||
double corr(0);
|
||||
// compute correlation between 2 pairs
|
||||
corr = fabs(compareHist(descriptorsFloat.col(idxA), descriptorsFloat.col(idxB), HISTCMP_CORREL));
|
||||
|
||||
if( corr > corrMax )
|
||||
{
|
||||
corrMax = corr;
|
||||
if( corrMax >= corrTresh )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( corrMax < corrTresh/*0.7*/ )
|
||||
bestPairs.push_back(pairStat[m]);
|
||||
|
||||
if( bestPairs.size() >= 512 )
|
||||
{
|
||||
if( verbose )
|
||||
std::cout << m << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> idxBestPairs;
|
||||
if( (int)bestPairs.size() >= FREAK_NB_PAIRS )
|
||||
{
|
||||
for( int i = 0; i < FREAK_NB_PAIRS; ++i )
|
||||
idxBestPairs.push_back(bestPairs[i].idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( verbose )
|
||||
std::cout << "correlation threshold too small (restrictive)" << std::endl;
|
||||
CV_Error(Error::StsError, "correlation threshold too small (restrictive)");
|
||||
}
|
||||
extAll = false;
|
||||
return idxBestPairs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// create an image showing the brisk pattern
|
||||
void FREAKImpl::drawPattern()
|
||||
{
|
||||
Mat pattern = Mat::zeros(1000, 1000, CV_8UC3) + Scalar(255,255,255);
|
||||
int sFac = 500 / patternScale;
|
||||
for( int n = 0; n < kNB_POINTS; ++n )
|
||||
{
|
||||
PatternPoint& pt = patternLookup[n];
|
||||
circle(pattern, Point( pt.x*sFac,pt.y*sFac)+Point(500,500), pt.sigma*sFac, Scalar(0,0,255),2);
|
||||
// rectangle(pattern, Point( (pt.x-pt.sigma)*sFac,(pt.y-pt.sigma)*sFac)+Point(500,500), Point( (pt.x+pt.sigma)*sFac,(pt.y+pt.sigma)*sFac)+Point(500,500), Scalar(0,0,255),2);
|
||||
|
||||
circle(pattern, Point( pt.x*sFac,pt.y*sFac)+Point(500,500), 1, Scalar(0,0,0),3);
|
||||
std::ostringstream oss;
|
||||
oss << n;
|
||||
putText( pattern, oss.str(), Point( pt.x*sFac,pt.y*sFac)+Point(500,500), FONT_HERSHEY_SIMPLEX,0.5, Scalar(0,0,0), 1);
|
||||
}
|
||||
imshow( "FreakDescriptorExtractor pattern", pattern );
|
||||
waitKey(0);
|
||||
}
|
||||
*/
|
||||
|
||||
// -------------------------------------------------
|
||||
/* FREAK interface implementation */
|
||||
FREAK::FREAK( bool _orientationNormalized, bool _scaleNormalized
|
||||
, float _patternScale, int _nOctaves, const std::vector<int>& _selectedPairs )
|
||||
: orientationNormalized(_orientationNormalized), scaleNormalized(_scaleNormalized),
|
||||
patternScale(_patternScale), nOctaves(_nOctaves), extAll(false), nOctaves0(0), selectedPairs0(_selectedPairs)
|
||||
{
|
||||
}
|
||||
|
||||
FREAK::~FREAK()
|
||||
{
|
||||
}
|
||||
|
||||
int FREAK::descriptorSize() const
|
||||
{
|
||||
return FREAK_NB_PAIRS / 8; // descriptor length in bytes
|
||||
}
|
||||
|
||||
int FREAK::descriptorType() const
|
||||
{
|
||||
return CV_8U;
|
||||
}
|
||||
|
||||
int FREAK::defaultNorm() const
|
||||
{
|
||||
return NORM_HAMMING;
|
||||
}
|
||||
|
||||
} // END NAMESPACE CV
|
||||
@@ -1,19 +0,0 @@
|
||||
// Code generated with '$ scripts/generate_code.py src/test_pairs.txt 16'
|
||||
#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x)
|
||||
desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0));
|
||||
desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0));
|
||||
desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0));
|
||||
desc[3] = (uchar)(((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0));
|
||||
desc[4] = (uchar)(((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0));
|
||||
desc[5] = (uchar)(((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0));
|
||||
desc[6] = (uchar)(((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0));
|
||||
desc[7] = (uchar)(((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0));
|
||||
desc[8] = (uchar)(((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0));
|
||||
desc[9] = (uchar)(((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0));
|
||||
desc[10] = (uchar)(((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0));
|
||||
desc[11] = (uchar)(((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0));
|
||||
desc[12] = (uchar)(((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0));
|
||||
desc[13] = (uchar)(((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0));
|
||||
desc[14] = (uchar)(((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0));
|
||||
desc[15] = (uchar)(((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0));
|
||||
#undef SMOOTHED
|
||||
@@ -1,35 +0,0 @@
|
||||
// Code generated with '$ scripts/generate_code.py src/test_pairs.txt 32'
|
||||
#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x)
|
||||
desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0));
|
||||
desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0));
|
||||
desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0));
|
||||
desc[3] = (uchar)(((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0));
|
||||
desc[4] = (uchar)(((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0));
|
||||
desc[5] = (uchar)(((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0));
|
||||
desc[6] = (uchar)(((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0));
|
||||
desc[7] = (uchar)(((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0));
|
||||
desc[8] = (uchar)(((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0));
|
||||
desc[9] = (uchar)(((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0));
|
||||
desc[10] = (uchar)(((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0));
|
||||
desc[11] = (uchar)(((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0));
|
||||
desc[12] = (uchar)(((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0));
|
||||
desc[13] = (uchar)(((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0));
|
||||
desc[14] = (uchar)(((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0));
|
||||
desc[15] = (uchar)(((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0));
|
||||
desc[16] = (uchar)(((SMOOTHED(-9, 1) < SMOOTHED(-18, 0)) << 7) + ((SMOOTHED(4, 0) < SMOOTHED(1, 12)) << 6) + ((SMOOTHED(0, 9) < SMOOTHED(-14, -10)) << 5) + ((SMOOTHED(-13, -9) < SMOOTHED(-2, 6)) << 4) + ((SMOOTHED(1, 5) < SMOOTHED(10, 10)) << 3) + ((SMOOTHED(-3, -6) < SMOOTHED(-16, -5)) << 2) + ((SMOOTHED(11, 6) < SMOOTHED(-5, 0)) << 1) + ((SMOOTHED(-23, 10) < SMOOTHED(1, 2)) << 0));
|
||||
desc[17] = (uchar)(((SMOOTHED(13, -5) < SMOOTHED(-3, 9)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-13, -5)) << 6) + ((SMOOTHED(10, 13) < SMOOTHED(-11, 8)) << 5) + ((SMOOTHED(19, 20) < SMOOTHED(-9, 2)) << 4) + ((SMOOTHED(4, -8) < SMOOTHED(0, -9)) << 3) + ((SMOOTHED(-14, 10) < SMOOTHED(15, 19)) << 2) + ((SMOOTHED(-14, -12) < SMOOTHED(-10, -3)) << 1) + ((SMOOTHED(-23, -3) < SMOOTHED(17, -2)) << 0));
|
||||
desc[18] = (uchar)(((SMOOTHED(-3, -11) < SMOOTHED(6, -14)) << 7) + ((SMOOTHED(19, -2) < SMOOTHED(-4, 2)) << 6) + ((SMOOTHED(-5, 5) < SMOOTHED(3, -13)) << 5) + ((SMOOTHED(2, -2) < SMOOTHED(-5, 4)) << 4) + ((SMOOTHED(17, 4) < SMOOTHED(17, -11)) << 3) + ((SMOOTHED(-7, -2) < SMOOTHED(1, 23)) << 2) + ((SMOOTHED(8, 13) < SMOOTHED(1, -16)) << 1) + ((SMOOTHED(-13, -5) < SMOOTHED(1, -17)) << 0));
|
||||
desc[19] = (uchar)(((SMOOTHED(4, 6) < SMOOTHED(-8, -3)) << 7) + ((SMOOTHED(-5, -9) < SMOOTHED(-2, -10)) << 6) + ((SMOOTHED(-9, 0) < SMOOTHED(-7, -2)) << 5) + ((SMOOTHED(5, 0) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-4, -16) < SMOOTHED(6, 3)) << 3) + ((SMOOTHED(2, -15) < SMOOTHED(-2, 12)) << 2) + ((SMOOTHED(4, -1) < SMOOTHED(6, 2)) << 1) + ((SMOOTHED(1, 1) < SMOOTHED(-2, -8)) << 0));
|
||||
desc[20] = (uchar)(((SMOOTHED(-2, 12) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, 8) < SMOOTHED(-9, 9)) << 6) + ((SMOOTHED(2, -10) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-4, 10) < SMOOTHED(-9, 4)) << 4) + ((SMOOTHED(6, 12) < SMOOTHED(2, 5)) << 3) + ((SMOOTHED(-3, -8) < SMOOTHED(0, 5)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-7, 2)) << 1) + ((SMOOTHED(-1, -10) < SMOOTHED(7, -18)) << 0));
|
||||
desc[21] = (uchar)(((SMOOTHED(-1, 8) < SMOOTHED(-9, -10)) << 7) + ((SMOOTHED(-23, -1) < SMOOTHED(6, 2)) << 6) + ((SMOOTHED(-5, -3) < SMOOTHED(3, 2)) << 5) + ((SMOOTHED(0, 11) < SMOOTHED(-4, -7)) << 4) + ((SMOOTHED(15, 2) < SMOOTHED(-10, -3)) << 3) + ((SMOOTHED(-20, -8) < SMOOTHED(-13, 3)) << 2) + ((SMOOTHED(-19, -12) < SMOOTHED(5, -11)) << 1) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 0));
|
||||
desc[22] = (uchar)(((SMOOTHED(7, 4) < SMOOTHED(-12, 0)) << 7) + ((SMOOTHED(5, -1) < SMOOTHED(-14, -6)) << 6) + ((SMOOTHED(-4, 11) < SMOOTHED(0, -4)) << 5) + ((SMOOTHED(3, 10) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(13, 21) < SMOOTHED(-11, 6)) << 3) + ((SMOOTHED(-12, 24) < SMOOTHED(-7, -4)) << 2) + ((SMOOTHED(4, 16) < SMOOTHED(3, -14)) << 1) + ((SMOOTHED(-3, 5) < SMOOTHED(-7, -12)) << 0));
|
||||
desc[23] = (uchar)(((SMOOTHED(0, -4) < SMOOTHED(7, -5)) << 7) + ((SMOOTHED(-17, -9) < SMOOTHED(13, -7)) << 6) + ((SMOOTHED(22, -6) < SMOOTHED(-11, 5)) << 5) + ((SMOOTHED(2, -8) < SMOOTHED(23, -11)) << 4) + ((SMOOTHED(7, -10) < SMOOTHED(-1, 14)) << 3) + ((SMOOTHED(-3, -10) < SMOOTHED(8, 3)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-6, 0)) << 1) + ((SMOOTHED(-7, -21) < SMOOTHED(6, -14)) << 0));
|
||||
desc[24] = (uchar)(((SMOOTHED(18, 19) < SMOOTHED(-4, -6)) << 7) + ((SMOOTHED(10, 7) < SMOOTHED(-1, -4)) << 6) + ((SMOOTHED(-1, 21) < SMOOTHED(1, -5)) << 5) + ((SMOOTHED(-10, 6) < SMOOTHED(-11, -2)) << 4) + ((SMOOTHED(18, -3) < SMOOTHED(-1, 7)) << 3) + ((SMOOTHED(-3, -9) < SMOOTHED(-5, 10)) << 2) + ((SMOOTHED(-13, 14) < SMOOTHED(17, -3)) << 1) + ((SMOOTHED(11, -19) < SMOOTHED(-1, -18)) << 0));
|
||||
desc[25] = (uchar)(((SMOOTHED(8, -2) < SMOOTHED(-18, -23)) << 7) + ((SMOOTHED(0, -5) < SMOOTHED(-2, -9)) << 6) + ((SMOOTHED(-4, -11) < SMOOTHED(2, -8)) << 5) + ((SMOOTHED(14, 6) < SMOOTHED(-3, -6)) << 4) + ((SMOOTHED(-3, 0) < SMOOTHED(-15, 0)) << 3) + ((SMOOTHED(-9, 4) < SMOOTHED(-15, -9)) << 2) + ((SMOOTHED(-1, 11) < SMOOTHED(3, 11)) << 1) + ((SMOOTHED(-10, -16) < SMOOTHED(-7, 7)) << 0));
|
||||
desc[26] = (uchar)(((SMOOTHED(-2, -10) < SMOOTHED(-10, -2)) << 7) + ((SMOOTHED(-5, -3) < SMOOTHED(5, -23)) << 6) + ((SMOOTHED(13, -8) < SMOOTHED(-15, -11)) << 5) + ((SMOOTHED(-15, 11) < SMOOTHED(6, -6)) << 4) + ((SMOOTHED(-16, -3) < SMOOTHED(-2, 2)) << 3) + ((SMOOTHED(6, 12) < SMOOTHED(-16, 24)) << 2) + ((SMOOTHED(-10, 0) < SMOOTHED(8, 11)) << 1) + ((SMOOTHED(-7, 7) < SMOOTHED(-19, -7)) << 0));
|
||||
desc[27] = (uchar)(((SMOOTHED(5, 16) < SMOOTHED(9, -3)) << 7) + ((SMOOTHED(9, 7) < SMOOTHED(-7, -16)) << 6) + ((SMOOTHED(3, 2) < SMOOTHED(-10, 9)) << 5) + ((SMOOTHED(21, 1) < SMOOTHED(8, 7)) << 4) + ((SMOOTHED(7, 0) < SMOOTHED(1, 17)) << 3) + ((SMOOTHED(-8, 12) < SMOOTHED(9, 6)) << 2) + ((SMOOTHED(11, -7) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(19, 0) < SMOOTHED(9, 3)) << 0));
|
||||
desc[28] = (uchar)(((SMOOTHED(1, -7) < SMOOTHED(-5, -11)) << 7) + ((SMOOTHED(0, 8) < SMOOTHED(-2, 14)) << 6) + ((SMOOTHED(12, -2) < SMOOTHED(-15, -6)) << 5) + ((SMOOTHED(4, 12) < SMOOTHED(0, -21)) << 4) + ((SMOOTHED(17, -4) < SMOOTHED(-6, -7)) << 3) + ((SMOOTHED(-10, -9) < SMOOTHED(-14, -7)) << 2) + ((SMOOTHED(-15, -10) < SMOOTHED(-15, -14)) << 1) + ((SMOOTHED(-7, -5) < SMOOTHED(5, -12)) << 0));
|
||||
desc[29] = (uchar)(((SMOOTHED(-4, 0) < SMOOTHED(15, -4)) << 7) + ((SMOOTHED(5, 2) < SMOOTHED(-6, -23)) << 6) + ((SMOOTHED(-4, -21) < SMOOTHED(-6, 4)) << 5) + ((SMOOTHED(-10, 5) < SMOOTHED(-15, 6)) << 4) + ((SMOOTHED(4, -3) < SMOOTHED(-1, 5)) << 3) + ((SMOOTHED(-4, 19) < SMOOTHED(-23, -4)) << 2) + ((SMOOTHED(-4, 17) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(1, 12) < SMOOTHED(4, -14)) << 0));
|
||||
desc[30] = (uchar)(((SMOOTHED(-11, -6) < SMOOTHED(-20, 10)) << 7) + ((SMOOTHED(4, 5) < SMOOTHED(3, 20)) << 6) + ((SMOOTHED(-8, -20) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-19, 9) < SMOOTHED(9, -3)) << 4) + ((SMOOTHED(18, 15) < SMOOTHED(11, -4)) << 3) + ((SMOOTHED(12, 16) < SMOOTHED(8, 7)) << 2) + ((SMOOTHED(-14, -8) < SMOOTHED(-3, 9)) << 1) + ((SMOOTHED(-6, 0) < SMOOTHED(2, -4)) << 0));
|
||||
desc[31] = (uchar)(((SMOOTHED(1, -10) < SMOOTHED(-1, 2)) << 7) + ((SMOOTHED(8, -7) < SMOOTHED(-6, 18)) << 6) + ((SMOOTHED(9, 12) < SMOOTHED(-7, -23)) << 5) + ((SMOOTHED(8, -6) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-9, 6) < SMOOTHED(-12, -7)) << 3) + ((SMOOTHED(-1, -2) < SMOOTHED(-7, 2)) << 2) + ((SMOOTHED(9, 9) < SMOOTHED(7, 15)) << 1) + ((SMOOTHED(6, 2) < SMOOTHED(-6, 6)) << 0));
|
||||
#undef SMOOTHED
|
||||
@@ -1,67 +0,0 @@
|
||||
// Code generated with '$ scripts/generate_code.py src/test_pairs.txt 64'
|
||||
#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x)
|
||||
desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0));
|
||||
desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0));
|
||||
desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0));
|
||||
desc[3] = (uchar)(((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0));
|
||||
desc[4] = (uchar)(((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0));
|
||||
desc[5] = (uchar)(((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0));
|
||||
desc[6] = (uchar)(((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0));
|
||||
desc[7] = (uchar)(((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0));
|
||||
desc[8] = (uchar)(((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0));
|
||||
desc[9] = (uchar)(((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0));
|
||||
desc[10] = (uchar)(((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0));
|
||||
desc[11] = (uchar)(((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0));
|
||||
desc[12] = (uchar)(((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0));
|
||||
desc[13] = (uchar)(((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0));
|
||||
desc[14] = (uchar)(((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0));
|
||||
desc[15] = (uchar)(((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0));
|
||||
desc[16] = (uchar)(((SMOOTHED(-9, 1) < SMOOTHED(-18, 0)) << 7) + ((SMOOTHED(4, 0) < SMOOTHED(1, 12)) << 6) + ((SMOOTHED(0, 9) < SMOOTHED(-14, -10)) << 5) + ((SMOOTHED(-13, -9) < SMOOTHED(-2, 6)) << 4) + ((SMOOTHED(1, 5) < SMOOTHED(10, 10)) << 3) + ((SMOOTHED(-3, -6) < SMOOTHED(-16, -5)) << 2) + ((SMOOTHED(11, 6) < SMOOTHED(-5, 0)) << 1) + ((SMOOTHED(-23, 10) < SMOOTHED(1, 2)) << 0));
|
||||
desc[17] = (uchar)(((SMOOTHED(13, -5) < SMOOTHED(-3, 9)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-13, -5)) << 6) + ((SMOOTHED(10, 13) < SMOOTHED(-11, 8)) << 5) + ((SMOOTHED(19, 20) < SMOOTHED(-9, 2)) << 4) + ((SMOOTHED(4, -8) < SMOOTHED(0, -9)) << 3) + ((SMOOTHED(-14, 10) < SMOOTHED(15, 19)) << 2) + ((SMOOTHED(-14, -12) < SMOOTHED(-10, -3)) << 1) + ((SMOOTHED(-23, -3) < SMOOTHED(17, -2)) << 0));
|
||||
desc[18] = (uchar)(((SMOOTHED(-3, -11) < SMOOTHED(6, -14)) << 7) + ((SMOOTHED(19, -2) < SMOOTHED(-4, 2)) << 6) + ((SMOOTHED(-5, 5) < SMOOTHED(3, -13)) << 5) + ((SMOOTHED(2, -2) < SMOOTHED(-5, 4)) << 4) + ((SMOOTHED(17, 4) < SMOOTHED(17, -11)) << 3) + ((SMOOTHED(-7, -2) < SMOOTHED(1, 23)) << 2) + ((SMOOTHED(8, 13) < SMOOTHED(1, -16)) << 1) + ((SMOOTHED(-13, -5) < SMOOTHED(1, -17)) << 0));
|
||||
desc[19] = (uchar)(((SMOOTHED(4, 6) < SMOOTHED(-8, -3)) << 7) + ((SMOOTHED(-5, -9) < SMOOTHED(-2, -10)) << 6) + ((SMOOTHED(-9, 0) < SMOOTHED(-7, -2)) << 5) + ((SMOOTHED(5, 0) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-4, -16) < SMOOTHED(6, 3)) << 3) + ((SMOOTHED(2, -15) < SMOOTHED(-2, 12)) << 2) + ((SMOOTHED(4, -1) < SMOOTHED(6, 2)) << 1) + ((SMOOTHED(1, 1) < SMOOTHED(-2, -8)) << 0));
|
||||
desc[20] = (uchar)(((SMOOTHED(-2, 12) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, 8) < SMOOTHED(-9, 9)) << 6) + ((SMOOTHED(2, -10) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-4, 10) < SMOOTHED(-9, 4)) << 4) + ((SMOOTHED(6, 12) < SMOOTHED(2, 5)) << 3) + ((SMOOTHED(-3, -8) < SMOOTHED(0, 5)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-7, 2)) << 1) + ((SMOOTHED(-1, -10) < SMOOTHED(7, -18)) << 0));
|
||||
desc[21] = (uchar)(((SMOOTHED(-1, 8) < SMOOTHED(-9, -10)) << 7) + ((SMOOTHED(-23, -1) < SMOOTHED(6, 2)) << 6) + ((SMOOTHED(-5, -3) < SMOOTHED(3, 2)) << 5) + ((SMOOTHED(0, 11) < SMOOTHED(-4, -7)) << 4) + ((SMOOTHED(15, 2) < SMOOTHED(-10, -3)) << 3) + ((SMOOTHED(-20, -8) < SMOOTHED(-13, 3)) << 2) + ((SMOOTHED(-19, -12) < SMOOTHED(5, -11)) << 1) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 0));
|
||||
desc[22] = (uchar)(((SMOOTHED(7, 4) < SMOOTHED(-12, 0)) << 7) + ((SMOOTHED(5, -1) < SMOOTHED(-14, -6)) << 6) + ((SMOOTHED(-4, 11) < SMOOTHED(0, -4)) << 5) + ((SMOOTHED(3, 10) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(13, 21) < SMOOTHED(-11, 6)) << 3) + ((SMOOTHED(-12, 24) < SMOOTHED(-7, -4)) << 2) + ((SMOOTHED(4, 16) < SMOOTHED(3, -14)) << 1) + ((SMOOTHED(-3, 5) < SMOOTHED(-7, -12)) << 0));
|
||||
desc[23] = (uchar)(((SMOOTHED(0, -4) < SMOOTHED(7, -5)) << 7) + ((SMOOTHED(-17, -9) < SMOOTHED(13, -7)) << 6) + ((SMOOTHED(22, -6) < SMOOTHED(-11, 5)) << 5) + ((SMOOTHED(2, -8) < SMOOTHED(23, -11)) << 4) + ((SMOOTHED(7, -10) < SMOOTHED(-1, 14)) << 3) + ((SMOOTHED(-3, -10) < SMOOTHED(8, 3)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-6, 0)) << 1) + ((SMOOTHED(-7, -21) < SMOOTHED(6, -14)) << 0));
|
||||
desc[24] = (uchar)(((SMOOTHED(18, 19) < SMOOTHED(-4, -6)) << 7) + ((SMOOTHED(10, 7) < SMOOTHED(-1, -4)) << 6) + ((SMOOTHED(-1, 21) < SMOOTHED(1, -5)) << 5) + ((SMOOTHED(-10, 6) < SMOOTHED(-11, -2)) << 4) + ((SMOOTHED(18, -3) < SMOOTHED(-1, 7)) << 3) + ((SMOOTHED(-3, -9) < SMOOTHED(-5, 10)) << 2) + ((SMOOTHED(-13, 14) < SMOOTHED(17, -3)) << 1) + ((SMOOTHED(11, -19) < SMOOTHED(-1, -18)) << 0));
|
||||
desc[25] = (uchar)(((SMOOTHED(8, -2) < SMOOTHED(-18, -23)) << 7) + ((SMOOTHED(0, -5) < SMOOTHED(-2, -9)) << 6) + ((SMOOTHED(-4, -11) < SMOOTHED(2, -8)) << 5) + ((SMOOTHED(14, 6) < SMOOTHED(-3, -6)) << 4) + ((SMOOTHED(-3, 0) < SMOOTHED(-15, 0)) << 3) + ((SMOOTHED(-9, 4) < SMOOTHED(-15, -9)) << 2) + ((SMOOTHED(-1, 11) < SMOOTHED(3, 11)) << 1) + ((SMOOTHED(-10, -16) < SMOOTHED(-7, 7)) << 0));
|
||||
desc[26] = (uchar)(((SMOOTHED(-2, -10) < SMOOTHED(-10, -2)) << 7) + ((SMOOTHED(-5, -3) < SMOOTHED(5, -23)) << 6) + ((SMOOTHED(13, -8) < SMOOTHED(-15, -11)) << 5) + ((SMOOTHED(-15, 11) < SMOOTHED(6, -6)) << 4) + ((SMOOTHED(-16, -3) < SMOOTHED(-2, 2)) << 3) + ((SMOOTHED(6, 12) < SMOOTHED(-16, 24)) << 2) + ((SMOOTHED(-10, 0) < SMOOTHED(8, 11)) << 1) + ((SMOOTHED(-7, 7) < SMOOTHED(-19, -7)) << 0));
|
||||
desc[27] = (uchar)(((SMOOTHED(5, 16) < SMOOTHED(9, -3)) << 7) + ((SMOOTHED(9, 7) < SMOOTHED(-7, -16)) << 6) + ((SMOOTHED(3, 2) < SMOOTHED(-10, 9)) << 5) + ((SMOOTHED(21, 1) < SMOOTHED(8, 7)) << 4) + ((SMOOTHED(7, 0) < SMOOTHED(1, 17)) << 3) + ((SMOOTHED(-8, 12) < SMOOTHED(9, 6)) << 2) + ((SMOOTHED(11, -7) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(19, 0) < SMOOTHED(9, 3)) << 0));
|
||||
desc[28] = (uchar)(((SMOOTHED(1, -7) < SMOOTHED(-5, -11)) << 7) + ((SMOOTHED(0, 8) < SMOOTHED(-2, 14)) << 6) + ((SMOOTHED(12, -2) < SMOOTHED(-15, -6)) << 5) + ((SMOOTHED(4, 12) < SMOOTHED(0, -21)) << 4) + ((SMOOTHED(17, -4) < SMOOTHED(-6, -7)) << 3) + ((SMOOTHED(-10, -9) < SMOOTHED(-14, -7)) << 2) + ((SMOOTHED(-15, -10) < SMOOTHED(-15, -14)) << 1) + ((SMOOTHED(-7, -5) < SMOOTHED(5, -12)) << 0));
|
||||
desc[29] = (uchar)(((SMOOTHED(-4, 0) < SMOOTHED(15, -4)) << 7) + ((SMOOTHED(5, 2) < SMOOTHED(-6, -23)) << 6) + ((SMOOTHED(-4, -21) < SMOOTHED(-6, 4)) << 5) + ((SMOOTHED(-10, 5) < SMOOTHED(-15, 6)) << 4) + ((SMOOTHED(4, -3) < SMOOTHED(-1, 5)) << 3) + ((SMOOTHED(-4, 19) < SMOOTHED(-23, -4)) << 2) + ((SMOOTHED(-4, 17) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(1, 12) < SMOOTHED(4, -14)) << 0));
|
||||
desc[30] = (uchar)(((SMOOTHED(-11, -6) < SMOOTHED(-20, 10)) << 7) + ((SMOOTHED(4, 5) < SMOOTHED(3, 20)) << 6) + ((SMOOTHED(-8, -20) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-19, 9) < SMOOTHED(9, -3)) << 4) + ((SMOOTHED(18, 15) < SMOOTHED(11, -4)) << 3) + ((SMOOTHED(12, 16) < SMOOTHED(8, 7)) << 2) + ((SMOOTHED(-14, -8) < SMOOTHED(-3, 9)) << 1) + ((SMOOTHED(-6, 0) < SMOOTHED(2, -4)) << 0));
|
||||
desc[31] = (uchar)(((SMOOTHED(1, -10) < SMOOTHED(-1, 2)) << 7) + ((SMOOTHED(8, -7) < SMOOTHED(-6, 18)) << 6) + ((SMOOTHED(9, 12) < SMOOTHED(-7, -23)) << 5) + ((SMOOTHED(8, -6) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-9, 6) < SMOOTHED(-12, -7)) << 3) + ((SMOOTHED(-1, -2) < SMOOTHED(-7, 2)) << 2) + ((SMOOTHED(9, 9) < SMOOTHED(7, 15)) << 1) + ((SMOOTHED(6, 2) < SMOOTHED(-6, 6)) << 0));
|
||||
desc[32] = (uchar)(((SMOOTHED(16, 12) < SMOOTHED(0, 19)) << 7) + ((SMOOTHED(4, 3) < SMOOTHED(6, 0)) << 6) + ((SMOOTHED(-2, -1) < SMOOTHED(2, 17)) << 5) + ((SMOOTHED(8, 1) < SMOOTHED(3, 1)) << 4) + ((SMOOTHED(-12, -1) < SMOOTHED(-11, 0)) << 3) + ((SMOOTHED(-11, 2) < SMOOTHED(7, 9)) << 2) + ((SMOOTHED(-1, 3) < SMOOTHED(-19, 4)) << 1) + ((SMOOTHED(-1, -11) < SMOOTHED(-1, 3)) << 0));
|
||||
desc[33] = (uchar)(((SMOOTHED(1, -10) < SMOOTHED(-10, -4)) << 7) + ((SMOOTHED(-2, 3) < SMOOTHED(6, 11)) << 6) + ((SMOOTHED(3, 7) < SMOOTHED(-9, -8)) << 5) + ((SMOOTHED(24, -14) < SMOOTHED(-2, -10)) << 4) + ((SMOOTHED(-3, -3) < SMOOTHED(-18, -6)) << 3) + ((SMOOTHED(-13, -10) < SMOOTHED(-7, -1)) << 2) + ((SMOOTHED(2, -7) < SMOOTHED(9, -6)) << 1) + ((SMOOTHED(2, -4) < SMOOTHED(6, -13)) << 0));
|
||||
desc[34] = (uchar)(((SMOOTHED(4, -4) < SMOOTHED(-2, 3)) << 7) + ((SMOOTHED(-4, 2) < SMOOTHED(9, 13)) << 6) + ((SMOOTHED(-11, 5) < SMOOTHED(-6, -11)) << 5) + ((SMOOTHED(4, -2) < SMOOTHED(11, -9)) << 4) + ((SMOOTHED(-19, 0) < SMOOTHED(-23, -5)) << 3) + ((SMOOTHED(-5, -7) < SMOOTHED(-3, -6)) << 2) + ((SMOOTHED(-6, -4) < SMOOTHED(12, 14)) << 1) + ((SMOOTHED(12, -11) < SMOOTHED(-8, -16)) << 0));
|
||||
desc[35] = (uchar)(((SMOOTHED(-21, 15) < SMOOTHED(-12, 6)) << 7) + ((SMOOTHED(-2, -1) < SMOOTHED(-8, 16)) << 6) + ((SMOOTHED(6, -1) < SMOOTHED(-8, -2)) << 5) + ((SMOOTHED(1, -1) < SMOOTHED(-9, 8)) << 4) + ((SMOOTHED(3, -4) < SMOOTHED(-2, -2)) << 3) + ((SMOOTHED(-7, 0) < SMOOTHED(4, -8)) << 2) + ((SMOOTHED(11, -11) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(2, 3) < SMOOTHED(11, 7)) << 0));
|
||||
desc[36] = (uchar)(((SMOOTHED(-7, -4) < SMOOTHED(-9, -6)) << 7) + ((SMOOTHED(3, -7) < SMOOTHED(-5, 0)) << 6) + ((SMOOTHED(3, -7) < SMOOTHED(-10, -5)) << 5) + ((SMOOTHED(-3, -1) < SMOOTHED(8, -10)) << 4) + ((SMOOTHED(0, 8) < SMOOTHED(5, 1)) << 3) + ((SMOOTHED(9, 0) < SMOOTHED(1, 16)) << 2) + ((SMOOTHED(8, 4) < SMOOTHED(-11, -3)) << 1) + ((SMOOTHED(-15, 9) < SMOOTHED(8, 17)) << 0));
|
||||
desc[37] = (uchar)(((SMOOTHED(0, 2) < SMOOTHED(-9, 17)) << 7) + ((SMOOTHED(-6, -11) < SMOOTHED(-10, -3)) << 6) + ((SMOOTHED(1, 1) < SMOOTHED(15, -8)) << 5) + ((SMOOTHED(-12, -13) < SMOOTHED(-2, 4)) << 4) + ((SMOOTHED(-6, 4) < SMOOTHED(-6, -10)) << 3) + ((SMOOTHED(5, -7) < SMOOTHED(7, -5)) << 2) + ((SMOOTHED(10, 6) < SMOOTHED(8, 9)) << 1) + ((SMOOTHED(-5, 7) < SMOOTHED(-18, -3)) << 0));
|
||||
desc[38] = (uchar)(((SMOOTHED(-6, 3) < SMOOTHED(5, 4)) << 7) + ((SMOOTHED(-10, -13) < SMOOTHED(-5, -3)) << 6) + ((SMOOTHED(-11, 2) < SMOOTHED(-16, 0)) << 5) + ((SMOOTHED(7, -21) < SMOOTHED(-5, -13)) << 4) + ((SMOOTHED(-14, -14) < SMOOTHED(-4, -4)) << 3) + ((SMOOTHED(4, 9) < SMOOTHED(7, -3)) << 2) + ((SMOOTHED(4, 11) < SMOOTHED(10, -4)) << 1) + ((SMOOTHED(6, 17) < SMOOTHED(9, 17)) << 0));
|
||||
desc[39] = (uchar)(((SMOOTHED(-10, 8) < SMOOTHED(0, -11)) << 7) + ((SMOOTHED(-6, -16) < SMOOTHED(-6, 8)) << 6) + ((SMOOTHED(-13, 5) < SMOOTHED(10, -5)) << 5) + ((SMOOTHED(3, 2) < SMOOTHED(12, 16)) << 4) + ((SMOOTHED(13, -8) < SMOOTHED(0, -6)) << 3) + ((SMOOTHED(10, 0) < SMOOTHED(4, -11)) << 2) + ((SMOOTHED(8, 5) < SMOOTHED(10, -2)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(-13, 3)) << 0));
|
||||
desc[40] = (uchar)(((SMOOTHED(2, 4) < SMOOTHED(-7, -3)) << 7) + ((SMOOTHED(-14, -2) < SMOOTHED(-11, 16)) << 6) + ((SMOOTHED(11, -6) < SMOOTHED(7, 6)) << 5) + ((SMOOTHED(-3, 15) < SMOOTHED(8, -10)) << 4) + ((SMOOTHED(-3, 8) < SMOOTHED(12, -12)) << 3) + ((SMOOTHED(-13, 6) < SMOOTHED(-14, 7)) << 2) + ((SMOOTHED(-11, -5) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(7, -6) < SMOOTHED(6, 3)) << 0));
|
||||
desc[41] = (uchar)(((SMOOTHED(-4, 10) < SMOOTHED(5, 1)) << 7) + ((SMOOTHED(9, 16) < SMOOTHED(10, 13)) << 6) + ((SMOOTHED(-17, 10) < SMOOTHED(2, 8)) << 5) + ((SMOOTHED(-5, 1) < SMOOTHED(4, -4)) << 4) + ((SMOOTHED(-14, 8) < SMOOTHED(-5, 2)) << 3) + ((SMOOTHED(4, -9) < SMOOTHED(-6, -3)) << 2) + ((SMOOTHED(3, -7) < SMOOTHED(-10, 0)) << 1) + ((SMOOTHED(-2, -8) < SMOOTHED(-10, 4)) << 0));
|
||||
desc[42] = (uchar)(((SMOOTHED(-8, 5) < SMOOTHED(-9, 24)) << 7) + ((SMOOTHED(2, -8) < SMOOTHED(8, -9)) << 6) + ((SMOOTHED(-4, 17) < SMOOTHED(-5, 2)) << 5) + ((SMOOTHED(14, 0) < SMOOTHED(-9, 9)) << 4) + ((SMOOTHED(11, 15) < SMOOTHED(-6, 5)) << 3) + ((SMOOTHED(-8, 1) < SMOOTHED(-3, 4)) << 2) + ((SMOOTHED(9, -21) < SMOOTHED(10, 2)) << 1) + ((SMOOTHED(2, -1) < SMOOTHED(4, 11)) << 0));
|
||||
desc[43] = (uchar)(((SMOOTHED(24, 3) < SMOOTHED(2, -2)) << 7) + ((SMOOTHED(-8, 17) < SMOOTHED(-14, -10)) << 6) + ((SMOOTHED(6, 5) < SMOOTHED(-13, 7)) << 5) + ((SMOOTHED(11, 10) < SMOOTHED(0, -1)) << 4) + ((SMOOTHED(4, 6) < SMOOTHED(-10, 6)) << 3) + ((SMOOTHED(-12, -2) < SMOOTHED(5, 6)) << 2) + ((SMOOTHED(3, -1) < SMOOTHED(8, -15)) << 1) + ((SMOOTHED(1, -4) < SMOOTHED(-7, 11)) << 0));
|
||||
desc[44] = (uchar)(((SMOOTHED(1, 11) < SMOOTHED(5, 0)) << 7) + ((SMOOTHED(6, -12) < SMOOTHED(10, 1)) << 6) + ((SMOOTHED(-3, -2) < SMOOTHED(-1, 4)) << 5) + ((SMOOTHED(-2, -11) < SMOOTHED(-1, 12)) << 4) + ((SMOOTHED(7, -8) < SMOOTHED(-20, -18)) << 3) + ((SMOOTHED(2, 0) < SMOOTHED(-9, 2)) << 2) + ((SMOOTHED(-13, -1) < SMOOTHED(-16, 2)) << 1) + ((SMOOTHED(3, -1) < SMOOTHED(-5, -17)) << 0));
|
||||
desc[45] = (uchar)(((SMOOTHED(15, 8) < SMOOTHED(3, -14)) << 7) + ((SMOOTHED(-13, -12) < SMOOTHED(6, 15)) << 6) + ((SMOOTHED(2, -8) < SMOOTHED(2, 6)) << 5) + ((SMOOTHED(6, 22) < SMOOTHED(-3, -23)) << 4) + ((SMOOTHED(-2, -7) < SMOOTHED(-6, 0)) << 3) + ((SMOOTHED(13, -10) < SMOOTHED(-6, 6)) << 2) + ((SMOOTHED(6, 7) < SMOOTHED(-10, 12)) << 1) + ((SMOOTHED(-6, 7) < SMOOTHED(-2, 11)) << 0));
|
||||
desc[46] = (uchar)(((SMOOTHED(0, -22) < SMOOTHED(-2, -17)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-11, -14)) << 6) + ((SMOOTHED(-2, -8) < SMOOTHED(7, 12)) << 5) + ((SMOOTHED(12, -5) < SMOOTHED(7, -13)) << 4) + ((SMOOTHED(2, -2) < SMOOTHED(-7, 6)) << 3) + ((SMOOTHED(0, 8) < SMOOTHED(-3, 23)) << 2) + ((SMOOTHED(6, 12) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(-21, -10) < SMOOTHED(10, 8)) << 0));
|
||||
desc[47] = (uchar)(((SMOOTHED(-3, 0) < SMOOTHED(7, 15)) << 7) + ((SMOOTHED(7, -6) < SMOOTHED(-5, -12)) << 6) + ((SMOOTHED(-21, -10) < SMOOTHED(12, -11)) << 5) + ((SMOOTHED(-5, -11) < SMOOTHED(8, -11)) << 4) + ((SMOOTHED(5, 0) < SMOOTHED(-11, -1)) << 3) + ((SMOOTHED(8, -9) < SMOOTHED(7, -1)) << 2) + ((SMOOTHED(11, -23) < SMOOTHED(21, -5)) << 1) + ((SMOOTHED(0, -5) < SMOOTHED(-8, 6)) << 0));
|
||||
desc[48] = (uchar)(((SMOOTHED(-6, 8) < SMOOTHED(8, 12)) << 7) + ((SMOOTHED(-7, 5) < SMOOTHED(3, -2)) << 6) + ((SMOOTHED(-5, -20) < SMOOTHED(-12, 9)) << 5) + ((SMOOTHED(-6, 12) < SMOOTHED(-11, 3)) << 4) + ((SMOOTHED(4, 5) < SMOOTHED(13, 11)) << 3) + ((SMOOTHED(2, 12) < SMOOTHED(13, -12)) << 2) + ((SMOOTHED(-4, -13) < SMOOTHED(4, 7)) << 1) + ((SMOOTHED(0, 15) < SMOOTHED(-3, -16)) << 0));
|
||||
desc[49] = (uchar)(((SMOOTHED(-3, 2) < SMOOTHED(-2, 14)) << 7) + ((SMOOTHED(4, -14) < SMOOTHED(16, -11)) << 6) + ((SMOOTHED(-13, 3) < SMOOTHED(23, 10)) << 5) + ((SMOOTHED(9, -19) < SMOOTHED(2, 5)) << 4) + ((SMOOTHED(5, 3) < SMOOTHED(14, -7)) << 3) + ((SMOOTHED(19, -13) < SMOOTHED(-11, 15)) << 2) + ((SMOOTHED(14, 0) < SMOOTHED(-2, -5)) << 1) + ((SMOOTHED(11, -4) < SMOOTHED(0, -6)) << 0));
|
||||
desc[50] = (uchar)(((SMOOTHED(-2, 5) < SMOOTHED(-13, -8)) << 7) + ((SMOOTHED(-11, -15) < SMOOTHED(-7, -17)) << 6) + ((SMOOTHED(1, 3) < SMOOTHED(-10, -8)) << 5) + ((SMOOTHED(-13, -10) < SMOOTHED(7, -12)) << 4) + ((SMOOTHED(0, -13) < SMOOTHED(23, -6)) << 3) + ((SMOOTHED(2, -17) < SMOOTHED(-7, -3)) << 2) + ((SMOOTHED(1, 3) < SMOOTHED(4, -10)) << 1) + ((SMOOTHED(13, 4) < SMOOTHED(14, -6)) << 0));
|
||||
desc[51] = (uchar)(((SMOOTHED(-19, -2) < SMOOTHED(-1, 5)) << 7) + ((SMOOTHED(9, -8) < SMOOTHED(10, -5)) << 6) + ((SMOOTHED(7, -1) < SMOOTHED(5, 7)) << 5) + ((SMOOTHED(9, -10) < SMOOTHED(19, 0)) << 4) + ((SMOOTHED(7, 5) < SMOOTHED(-4, -7)) << 3) + ((SMOOTHED(-11, 1) < SMOOTHED(-1, -11)) << 2) + ((SMOOTHED(2, -1) < SMOOTHED(-4, 11)) << 1) + ((SMOOTHED(-1, 7) < SMOOTHED(2, -2)) << 0));
|
||||
desc[52] = (uchar)(((SMOOTHED(1, -20) < SMOOTHED(-9, -6)) << 7) + ((SMOOTHED(-4, -18) < SMOOTHED(8, -18)) << 6) + ((SMOOTHED(-16, -2) < SMOOTHED(7, -6)) << 5) + ((SMOOTHED(-3, -6) < SMOOTHED(-1, -4)) << 4) + ((SMOOTHED(0, -16) < SMOOTHED(24, -5)) << 3) + ((SMOOTHED(-4, -2) < SMOOTHED(-1, 9)) << 2) + ((SMOOTHED(-8, 2) < SMOOTHED(-6, 15)) << 1) + ((SMOOTHED(11, 4) < SMOOTHED(0, -3)) << 0));
|
||||
desc[53] = (uchar)(((SMOOTHED(7, 6) < SMOOTHED(2, -10)) << 7) + ((SMOOTHED(-7, -9) < SMOOTHED(12, -6)) << 6) + ((SMOOTHED(24, 15) < SMOOTHED(-8, -1)) << 5) + ((SMOOTHED(15, -9) < SMOOTHED(-3, -15)) << 4) + ((SMOOTHED(17, -5) < SMOOTHED(11, -10)) << 3) + ((SMOOTHED(-2, 13) < SMOOTHED(-15, 4)) << 2) + ((SMOOTHED(-2, -1) < SMOOTHED(4, -23)) << 1) + ((SMOOTHED(-16, 3) < SMOOTHED(-7, -14)) << 0));
|
||||
desc[54] = (uchar)(((SMOOTHED(-3, -5) < SMOOTHED(-10, -9)) << 7) + ((SMOOTHED(-5, 3) < SMOOTHED(-2, -1)) << 6) + ((SMOOTHED(-1, 4) < SMOOTHED(1, 8)) << 5) + ((SMOOTHED(12, 9) < SMOOTHED(9, -14)) << 4) + ((SMOOTHED(-9, 17) < SMOOTHED(-3, 0)) << 3) + ((SMOOTHED(5, 4) < SMOOTHED(13, -6)) << 2) + ((SMOOTHED(-1, -8) < SMOOTHED(19, 10)) << 1) + ((SMOOTHED(8, -5) < SMOOTHED(-15, 2)) << 0));
|
||||
desc[55] = (uchar)(((SMOOTHED(-12, -9) < SMOOTHED(-4, -5)) << 7) + ((SMOOTHED(12, 0) < SMOOTHED(24, 4)) << 6) + ((SMOOTHED(8, -2) < SMOOTHED(14, 4)) << 5) + ((SMOOTHED(8, -4) < SMOOTHED(-7, 16)) << 4) + ((SMOOTHED(5, -1) < SMOOTHED(-8, -4)) << 3) + ((SMOOTHED(-2, 18) < SMOOTHED(-5, 17)) << 2) + ((SMOOTHED(8, -2) < SMOOTHED(-9, -2)) << 1) + ((SMOOTHED(3, -7) < SMOOTHED(1, -6)) << 0));
|
||||
desc[56] = (uchar)(((SMOOTHED(-5, -22) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, -10) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(-3, -13) < SMOOTHED(3, 9)) << 5) + ((SMOOTHED(-4, -1) < SMOOTHED(-1, 0)) << 4) + ((SMOOTHED(-7, -21) < SMOOTHED(12, -19)) << 3) + ((SMOOTHED(-8, 8) < SMOOTHED(24, 8)) << 2) + ((SMOOTHED(12, -6) < SMOOTHED(-2, 3)) << 1) + ((SMOOTHED(-5, -11) < SMOOTHED(-22, -4)) << 0));
|
||||
desc[57] = (uchar)(((SMOOTHED(-3, 5) < SMOOTHED(-4, 4)) << 7) + ((SMOOTHED(-16, 24) < SMOOTHED(7, -9)) << 6) + ((SMOOTHED(-10, 23) < SMOOTHED(-9, 18)) << 5) + ((SMOOTHED(1, 12) < SMOOTHED(17, 21)) << 4) + ((SMOOTHED(24, -6) < SMOOTHED(-3, -11)) << 3) + ((SMOOTHED(-7, 17) < SMOOTHED(1, -6)) << 2) + ((SMOOTHED(4, 4) < SMOOTHED(2, -7)) << 1) + ((SMOOTHED(14, 6) < SMOOTHED(-12, 3)) << 0));
|
||||
desc[58] = (uchar)(((SMOOTHED(-6, 0) < SMOOTHED(-16, 13)) << 7) + ((SMOOTHED(-10, 5) < SMOOTHED(7, 12)) << 6) + ((SMOOTHED(5, 2) < SMOOTHED(6, -3)) << 5) + ((SMOOTHED(7, 0) < SMOOTHED(-23, 1)) << 4) + ((SMOOTHED(15, -5) < SMOOTHED(1, 14)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(6, 6)) << 2) + ((SMOOTHED(6, -9) < SMOOTHED(-9, 12)) << 1) + ((SMOOTHED(4, -2) < SMOOTHED(-4, 7)) << 0));
|
||||
desc[59] = (uchar)(((SMOOTHED(-4, -5) < SMOOTHED(4, 4)) << 7) + ((SMOOTHED(-13, 0) < SMOOTHED(6, -10)) << 6) + ((SMOOTHED(2, -12) < SMOOTHED(-6, -3)) << 5) + ((SMOOTHED(16, 0) < SMOOTHED(-3, 3)) << 4) + ((SMOOTHED(5, -14) < SMOOTHED(6, 11)) << 3) + ((SMOOTHED(5, 11) < SMOOTHED(0, -13)) << 2) + ((SMOOTHED(7, 5) < SMOOTHED(-1, -5)) << 1) + ((SMOOTHED(12, 4) < SMOOTHED(6, 10)) << 0));
|
||||
desc[60] = (uchar)(((SMOOTHED(-10, 4) < SMOOTHED(-1, -11)) << 7) + ((SMOOTHED(4, 10) < SMOOTHED(-14, 5)) << 6) + ((SMOOTHED(11, -14) < SMOOTHED(-13, 0)) << 5) + ((SMOOTHED(2, 8) < SMOOTHED(12, 24)) << 4) + ((SMOOTHED(-1, 3) < SMOOTHED(-1, 2)) << 3) + ((SMOOTHED(9, -14) < SMOOTHED(-23, 3)) << 2) + ((SMOOTHED(-8, -6) < SMOOTHED(0, 9)) << 1) + ((SMOOTHED(-15, 14) < SMOOTHED(10, -10)) << 0));
|
||||
desc[61] = (uchar)(((SMOOTHED(-10, -6) < SMOOTHED(-7, -5)) << 7) + ((SMOOTHED(11, 5) < SMOOTHED(-3, -15)) << 6) + ((SMOOTHED(1, 0) < SMOOTHED(1, 8)) << 5) + ((SMOOTHED(-11, -6) < SMOOTHED(-4, -18)) << 4) + ((SMOOTHED(9, 0) < SMOOTHED(22, -4)) << 3) + ((SMOOTHED(-5, -1) < SMOOTHED(-9, 4)) << 2) + ((SMOOTHED(-20, 2) < SMOOTHED(1, 6)) << 1) + ((SMOOTHED(1, 2) < SMOOTHED(-9, -12)) << 0));
|
||||
desc[62] = (uchar)(((SMOOTHED(5, 15) < SMOOTHED(4, -6)) << 7) + ((SMOOTHED(19, 4) < SMOOTHED(4, 11)) << 6) + ((SMOOTHED(17, -4) < SMOOTHED(-8, -1)) << 5) + ((SMOOTHED(-8, -12) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(11, 9) < SMOOTHED(8, 1)) << 3) + ((SMOOTHED(9, 22) < SMOOTHED(-15, 15)) << 2) + ((SMOOTHED(-7, -7) < SMOOTHED(1, -23)) << 1) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 2)) << 0));
|
||||
desc[63] = (uchar)(((SMOOTHED(3, -5) < SMOOTHED(11, -11)) << 7) + ((SMOOTHED(3, -18) < SMOOTHED(14, -5)) << 6) + ((SMOOTHED(-20, 7) < SMOOTHED(-10, -23)) << 5) + ((SMOOTHED(-2, -5) < SMOOTHED(6, 0)) << 4) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 3) + ((SMOOTHED(-6, -1) < SMOOTHED(14, -2)) << 2) + ((SMOOTHED(-12, -16) < SMOOTHED(15, 6)) << 1) + ((SMOOTHED(-12, -2) < SMOOTHED(3, -19)) << 0));
|
||||
#undef SMOOTHED
|
||||
@@ -0,0 +1,151 @@
|
||||
/*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.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, 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 Intel Corporation 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
|
||||
{
|
||||
|
||||
class GFTTDetector_Impl CV_FINAL : public GFTTDetector
|
||||
{
|
||||
public:
|
||||
GFTTDetector_Impl( int _nfeatures, double _qualityLevel,
|
||||
double _minDistance, int _blockSize, int _gradientSize,
|
||||
bool _useHarrisDetector, double _k )
|
||||
: nfeatures(_nfeatures), qualityLevel(_qualityLevel), minDistance(_minDistance),
|
||||
blockSize(_blockSize), gradSize(_gradientSize), useHarrisDetector(_useHarrisDetector), k(_k)
|
||||
{
|
||||
}
|
||||
|
||||
void setMaxFeatures(int maxFeatures) CV_OVERRIDE { nfeatures = maxFeatures; }
|
||||
int getMaxFeatures() const CV_OVERRIDE { return nfeatures; }
|
||||
|
||||
void setQualityLevel(double qlevel) CV_OVERRIDE { qualityLevel = qlevel; }
|
||||
double getQualityLevel() const CV_OVERRIDE { return qualityLevel; }
|
||||
|
||||
void setMinDistance(double minDistance_) CV_OVERRIDE { minDistance = minDistance_; }
|
||||
double getMinDistance() const CV_OVERRIDE { return minDistance; }
|
||||
|
||||
void setBlockSize(int blockSize_) CV_OVERRIDE { blockSize = blockSize_; }
|
||||
int getBlockSize() const CV_OVERRIDE { return blockSize; }
|
||||
|
||||
//void setGradientSize(int gradientSize_) { gradSize = gradientSize_; }
|
||||
//int getGradientSize() { return gradSize; }
|
||||
|
||||
void setHarrisDetector(bool val) CV_OVERRIDE { useHarrisDetector = val; }
|
||||
bool getHarrisDetector() const CV_OVERRIDE { return useHarrisDetector; }
|
||||
|
||||
void setK(double k_) CV_OVERRIDE { k = k_; }
|
||||
double getK() const CV_OVERRIDE { return k; }
|
||||
|
||||
void detect( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) CV_OVERRIDE
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
if(_image.empty())
|
||||
{
|
||||
keypoints.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Point2f> corners;
|
||||
|
||||
if (_image.isUMat())
|
||||
{
|
||||
UMat ugrayImage;
|
||||
if( _image.type() != CV_8U )
|
||||
cvtColor( _image, ugrayImage, COLOR_BGR2GRAY );
|
||||
else
|
||||
ugrayImage = _image.getUMat();
|
||||
|
||||
goodFeaturesToTrack( ugrayImage, corners, nfeatures, qualityLevel, minDistance, _mask,
|
||||
blockSize, gradSize, useHarrisDetector, k );
|
||||
}
|
||||
else
|
||||
{
|
||||
Mat image = _image.getMat(), grayImage = image;
|
||||
if( image.type() != CV_8U )
|
||||
cvtColor( image, grayImage, COLOR_BGR2GRAY );
|
||||
|
||||
goodFeaturesToTrack( grayImage, corners, nfeatures, qualityLevel, minDistance, _mask,
|
||||
blockSize, gradSize, useHarrisDetector, k );
|
||||
}
|
||||
|
||||
keypoints.resize(corners.size());
|
||||
std::vector<Point2f>::const_iterator corner_it = corners.begin();
|
||||
std::vector<KeyPoint>::iterator keypoint_it = keypoints.begin();
|
||||
for( ; corner_it != corners.end() && keypoint_it != keypoints.end(); ++corner_it, ++keypoint_it )
|
||||
*keypoint_it = KeyPoint( *corner_it, (float)blockSize );
|
||||
|
||||
}
|
||||
|
||||
int nfeatures;
|
||||
double qualityLevel;
|
||||
double minDistance;
|
||||
int blockSize;
|
||||
int gradSize;
|
||||
bool useHarrisDetector;
|
||||
double k;
|
||||
};
|
||||
|
||||
|
||||
Ptr<GFTTDetector> GFTTDetector::create( int _nfeatures, double _qualityLevel,
|
||||
double _minDistance, int _blockSize, int _gradientSize,
|
||||
bool _useHarrisDetector, double _k )
|
||||
{
|
||||
return makePtr<GFTTDetector_Impl>(_nfeatures, _qualityLevel,
|
||||
_minDistance, _blockSize, _gradientSize, _useHarrisDetector, _k);
|
||||
}
|
||||
|
||||
Ptr<GFTTDetector> GFTTDetector::create( int _nfeatures, double _qualityLevel,
|
||||
double _minDistance, int _blockSize,
|
||||
bool _useHarrisDetector, double _k )
|
||||
{
|
||||
return makePtr<GFTTDetector_Impl>(_nfeatures, _qualityLevel,
|
||||
_minDistance, _blockSize, 3, _useHarrisDetector, _k);
|
||||
}
|
||||
|
||||
String GFTTDetector::getDefaultName() const
|
||||
{
|
||||
return (Feature2D::getDefaultName() + ".GFTTDetector");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*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) 2017, Intel Corporation, 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*/
|
||||
|
||||
#ifndef OPENCV_FEATURES2D_HAL_REPLACEMENT_HPP
|
||||
#define OPENCV_FEATURES2D_HAL_REPLACEMENT_HPP
|
||||
|
||||
#include "opencv2/core/hal/interface.h"
|
||||
|
||||
#if defined __GNUC__
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#elif defined _MSC_VER
|
||||
# pragma warning( push )
|
||||
# pragma warning( disable: 4100 )
|
||||
#endif
|
||||
|
||||
//! @addtogroup features2d_hal_interface
|
||||
//! @note Define your functions to override default implementations:
|
||||
//! @code
|
||||
//! #undef hal_add8u
|
||||
//! #define hal_add8u my_add8u
|
||||
//! @endcode
|
||||
//! @{
|
||||
/**
|
||||
@brief Detects corners using the FAST algorithm, returns mask.
|
||||
@param src_data,src_step Source image
|
||||
@param dst_data,dst_step Destination mask
|
||||
@param width,height Source image dimensions
|
||||
@param type FAST type
|
||||
*/
|
||||
inline int hal_ni_FAST_dense(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int type) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
//! @cond IGNORED
|
||||
#define cv_hal_FAST_dense hal_ni_FAST_dense
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
@brief Non-maximum suppression for FAST_9_16.
|
||||
@param src_data,src_step Source mask
|
||||
@param dst_data,dst_step Destination mask after NMS
|
||||
@param width,height Source mask dimensions
|
||||
*/
|
||||
inline int hal_ni_FAST_NMS(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
//! @cond IGNORED
|
||||
#define cv_hal_FAST_NMS hal_ni_FAST_NMS
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
@brief Detects corners using the FAST algorithm.
|
||||
@param src_data,src_step Source image
|
||||
@param width,height Source image dimensions
|
||||
@param keypoints_data Pointer to keypoints
|
||||
@param keypoints_count Count of keypoints
|
||||
@param threshold Threshold for keypoint
|
||||
@param nonmax_suppression Indicates if make nonmaxima suppression or not.
|
||||
@param type FAST type
|
||||
*/
|
||||
inline int hal_ni_FAST(const uchar* src_data, size_t src_step, int width, int height, uchar* keypoints_data, size_t* keypoints_count, int threshold, bool nonmax_suppression, int type) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
//! @cond IGNORED
|
||||
#define cv_hal_FAST hal_ni_FAST
|
||||
//! @endcond
|
||||
|
||||
//! @}
|
||||
|
||||
|
||||
#if defined __GNUC__
|
||||
# pragma GCC diagnostic pop
|
||||
#elif defined _MSC_VER
|
||||
# pragma warning( pop )
|
||||
#endif
|
||||
|
||||
#include "custom_hal.hpp"
|
||||
|
||||
//! @cond IGNORED
|
||||
#define CALL_HAL_RET(name, fun, retval, ...) \
|
||||
int res = __CV_EXPAND(fun(__VA_ARGS__, &retval)); \
|
||||
if (res == CV_HAL_ERROR_OK) \
|
||||
return retval; \
|
||||
else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \
|
||||
CV_Error_(cv::Error::StsInternal, \
|
||||
("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res));
|
||||
|
||||
|
||||
#define CALL_HAL(name, fun, ...) \
|
||||
{ \
|
||||
int res = __CV_EXPAND(fun(__VA_ARGS__)); \
|
||||
if (res == CV_HAL_ERROR_OK) \
|
||||
return; \
|
||||
else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \
|
||||
CV_Error_(cv::Error::StsInternal, \
|
||||
("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res)); \
|
||||
}
|
||||
//! @endcond
|
||||
|
||||
#endif
|
||||
+132
-123
@@ -52,145 +52,154 @@ http://www.robesafe.com/personal/pablo.alcantarilla/papers/Alcantarilla12eccv.pd
|
||||
|
||||
namespace cv
|
||||
{
|
||||
KAZE::KAZE()
|
||||
: extended(false)
|
||||
, upright(false)
|
||||
, threshold(0.001f)
|
||||
, octaves(4)
|
||||
, sublevels(4)
|
||||
, diffusivity(DIFF_PM_G2)
|
||||
{
|
||||
}
|
||||
|
||||
KAZE::KAZE(bool _extended, bool _upright, float _threshold, int _octaves,
|
||||
int _sublevels, int _diffusivity)
|
||||
class KAZE_Impl CV_FINAL : public KAZE
|
||||
{
|
||||
public:
|
||||
KAZE_Impl(bool _extended, bool _upright, float _threshold, int _octaves,
|
||||
int _sublevels, int _diffusivity)
|
||||
: extended(_extended)
|
||||
, upright(_upright)
|
||||
, threshold(_threshold)
|
||||
, octaves(_octaves)
|
||||
, sublevels(_sublevels)
|
||||
, diffusivity(_diffusivity)
|
||||
{
|
||||
|
||||
}
|
||||
KAZE::~KAZE()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// returns the descriptor size in bytes
|
||||
int KAZE::descriptorSize() const
|
||||
{
|
||||
return extended ? 128 : 64;
|
||||
}
|
||||
|
||||
// returns the descriptor type
|
||||
int KAZE::descriptorType() const
|
||||
{
|
||||
return CV_32F;
|
||||
}
|
||||
|
||||
// returns the default norm type
|
||||
int KAZE::defaultNorm() const
|
||||
{
|
||||
return NORM_L2;
|
||||
}
|
||||
|
||||
void KAZE::operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const
|
||||
{
|
||||
detectImpl(image, keypoints, mask);
|
||||
}
|
||||
|
||||
void KAZE::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();
|
||||
|
||||
KAZEOptions options;
|
||||
options.img_width = img.cols;
|
||||
options.img_height = img.rows;
|
||||
options.extended = extended;
|
||||
options.upright = upright;
|
||||
options.dthreshold = threshold;
|
||||
options.omax = octaves;
|
||||
options.nsublevels = sublevels;
|
||||
options.diffusivity = diffusivity;
|
||||
|
||||
KAZEFeatures impl(options);
|
||||
impl.Create_Nonlinear_Scale_Space(img1_32);
|
||||
|
||||
if (!useProvidedKeypoints)
|
||||
{
|
||||
impl.Feature_Detection(keypoints);
|
||||
}
|
||||
|
||||
if (!mask.empty())
|
||||
virtual ~KAZE_Impl() CV_OVERRIDE {}
|
||||
|
||||
void setExtended(bool extended_) CV_OVERRIDE { extended = extended_; }
|
||||
bool getExtended() const CV_OVERRIDE { return extended; }
|
||||
|
||||
void setUpright(bool upright_) CV_OVERRIDE { upright = upright_; }
|
||||
bool getUpright() const CV_OVERRIDE { return upright; }
|
||||
|
||||
void setThreshold(double threshold_) CV_OVERRIDE { threshold = (float)threshold_; }
|
||||
double getThreshold() const CV_OVERRIDE { return threshold; }
|
||||
|
||||
void setNOctaves(int octaves_) CV_OVERRIDE { octaves = octaves_; }
|
||||
int getNOctaves() const CV_OVERRIDE { return octaves; }
|
||||
|
||||
void setNOctaveLayers(int octaveLayers_) CV_OVERRIDE { sublevels = octaveLayers_; }
|
||||
int getNOctaveLayers() const CV_OVERRIDE { return sublevels; }
|
||||
|
||||
void setDiffusivity(int diff_) CV_OVERRIDE { diffusivity = diff_; }
|
||||
int getDiffusivity() const CV_OVERRIDE { return diffusivity; }
|
||||
|
||||
// returns the descriptor size in bytes
|
||||
int descriptorSize() const CV_OVERRIDE
|
||||
{
|
||||
cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat());
|
||||
return extended ? 128 : 64;
|
||||
}
|
||||
|
||||
impl.Feature_Description(keypoints, desc);
|
||||
|
||||
CV_Assert((!desc.rows || desc.cols == descriptorSize()));
|
||||
CV_Assert((!desc.rows || (desc.type() == descriptorType())));
|
||||
}
|
||||
|
||||
void KAZE::detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const
|
||||
{
|
||||
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);
|
||||
|
||||
KAZEOptions options;
|
||||
options.img_width = img.cols;
|
||||
options.img_height = img.rows;
|
||||
options.extended = extended;
|
||||
options.upright = upright;
|
||||
|
||||
KAZEFeatures impl(options);
|
||||
impl.Create_Nonlinear_Scale_Space(img1_32);
|
||||
impl.Feature_Detection(keypoints);
|
||||
|
||||
if (!mask.empty())
|
||||
// returns the descriptor type
|
||||
int descriptorType() const CV_OVERRIDE
|
||||
{
|
||||
cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat());
|
||||
return CV_32F;
|
||||
}
|
||||
}
|
||||
|
||||
void KAZE::computeImpl(InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const
|
||||
// returns the default norm type
|
||||
int defaultNorm() const CV_OVERRIDE
|
||||
{
|
||||
return NORM_L2;
|
||||
}
|
||||
|
||||
void detectAndCompute(InputArray image, InputArray mask,
|
||||
std::vector<KeyPoint>& keypoints,
|
||||
OutputArray descriptors,
|
||||
bool useProvidedKeypoints) CV_OVERRIDE
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
cv::Mat img = image.getMat();
|
||||
if (img.channels() > 1)
|
||||
cvtColor(image, img, COLOR_BGR2GRAY);
|
||||
|
||||
Mat img1_32;
|
||||
if ( img.depth() == CV_32F )
|
||||
img1_32 = img;
|
||||
else if ( img.depth() == CV_8U )
|
||||
img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0);
|
||||
else if ( img.depth() == CV_16U )
|
||||
img.convertTo(img1_32, CV_32F, 1.0 / 65535.0, 0);
|
||||
|
||||
CV_Assert( ! img1_32.empty() );
|
||||
|
||||
KAZEOptions options;
|
||||
options.img_width = img.cols;
|
||||
options.img_height = img.rows;
|
||||
options.extended = extended;
|
||||
options.upright = upright;
|
||||
options.dthreshold = threshold;
|
||||
options.omax = octaves;
|
||||
options.nsublevels = sublevels;
|
||||
options.diffusivity = diffusivity;
|
||||
|
||||
KAZEFeatures impl(options);
|
||||
impl.Create_Nonlinear_Scale_Space(img1_32);
|
||||
|
||||
if (!useProvidedKeypoints)
|
||||
{
|
||||
impl.Feature_Detection(keypoints);
|
||||
}
|
||||
|
||||
if (!mask.empty())
|
||||
{
|
||||
cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat());
|
||||
}
|
||||
|
||||
if( descriptors.needed() )
|
||||
{
|
||||
Mat desc;
|
||||
impl.Feature_Description(keypoints, desc);
|
||||
desc.copyTo(descriptors);
|
||||
|
||||
CV_Assert((!desc.rows || desc.cols == descriptorSize()));
|
||||
CV_Assert((!desc.rows || (desc.type() == descriptorType())));
|
||||
}
|
||||
}
|
||||
|
||||
void write(FileStorage& fs) const CV_OVERRIDE
|
||||
{
|
||||
writeFormat(fs);
|
||||
fs << "extended" << (int)extended;
|
||||
fs << "upright" << (int)upright;
|
||||
fs << "threshold" << threshold;
|
||||
fs << "octaves" << octaves;
|
||||
fs << "sublevels" << sublevels;
|
||||
fs << "diffusivity" << diffusivity;
|
||||
}
|
||||
|
||||
void read(const FileNode& fn) CV_OVERRIDE
|
||||
{
|
||||
extended = (int)fn["extended"] != 0;
|
||||
upright = (int)fn["upright"] != 0;
|
||||
threshold = (float)fn["threshold"];
|
||||
octaves = (int)fn["octaves"];
|
||||
sublevels = (int)fn["sublevels"];
|
||||
diffusivity = (int)fn["diffusivity"];
|
||||
}
|
||||
|
||||
bool extended;
|
||||
bool upright;
|
||||
float threshold;
|
||||
int octaves;
|
||||
int sublevels;
|
||||
int diffusivity;
|
||||
};
|
||||
|
||||
Ptr<KAZE> KAZE::create(bool extended, bool upright,
|
||||
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();
|
||||
|
||||
KAZEOptions options;
|
||||
options.img_width = img.cols;
|
||||
options.img_height = img.rows;
|
||||
options.extended = extended;
|
||||
options.upright = upright;
|
||||
|
||||
KAZEFeatures impl(options);
|
||||
impl.Create_Nonlinear_Scale_Space(img1_32);
|
||||
impl.Feature_Description(keypoints, desc);
|
||||
|
||||
CV_Assert((!desc.rows || desc.cols == descriptorSize()));
|
||||
CV_Assert((!desc.rows || (desc.type() == descriptorType())));
|
||||
return makePtr<KAZE_Impl>(extended, upright, threshold, octaves, sublevels, diffusivity);
|
||||
}
|
||||
|
||||
String KAZE::getDefaultName() const
|
||||
{
|
||||
return (Feature2D::getDefaultName() + ".KAZE");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,23 +8,8 @@
|
||||
#ifndef __OPENCV_FEATURES_2D_AKAZE_CONFIG_H__
|
||||
#define __OPENCV_FEATURES_2D_AKAZE_CONFIG_H__
|
||||
|
||||
/* ************************************************************************* */
|
||||
// OpenCV
|
||||
#include "../precomp.hpp"
|
||||
#include <opencv2/features2d.hpp>
|
||||
|
||||
/* ************************************************************************* */
|
||||
/// Lookup table for 2d gaussian (sigma = 2.5) where (0,0) is top left and (6,6) is bottom right
|
||||
const float gauss25[7][7] = {
|
||||
{ 0.02546481f, 0.02350698f, 0.01849125f, 0.01239505f, 0.00708017f, 0.00344629f, 0.00142946f },
|
||||
{ 0.02350698f, 0.02169968f, 0.01706957f, 0.01144208f, 0.00653582f, 0.00318132f, 0.00131956f },
|
||||
{ 0.01849125f, 0.01706957f, 0.01342740f, 0.00900066f, 0.00514126f, 0.00250252f, 0.00103800f },
|
||||
{ 0.01239505f, 0.01144208f, 0.00900066f, 0.00603332f, 0.00344629f, 0.00167749f, 0.00069579f },
|
||||
{ 0.00708017f, 0.00653582f, 0.00514126f, 0.00344629f, 0.00196855f, 0.00095820f, 0.00039744f },
|
||||
{ 0.00344629f, 0.00318132f, 0.00250252f, 0.00167749f, 0.00095820f, 0.00046640f, 0.00019346f },
|
||||
{ 0.00142946f, 0.00131956f, 0.00103800f, 0.00069579f, 0.00039744f, 0.00019346f, 0.00008024f }
|
||||
};
|
||||
|
||||
namespace cv
|
||||
{
|
||||
/* ************************************************************************* */
|
||||
/// AKAZE configuration options structure
|
||||
struct AKAZEOptions {
|
||||
@@ -37,12 +22,12 @@ struct AKAZEOptions {
|
||||
, soffset(1.6f)
|
||||
, derivative_factor(1.5f)
|
||||
, sderivatives(1.0)
|
||||
, diffusivity(cv::DIFF_PM_G2)
|
||||
, diffusivity(KAZE::DIFF_PM_G2)
|
||||
|
||||
, dthreshold(0.001f)
|
||||
, min_dthreshold(0.00001f)
|
||||
|
||||
, descriptor(cv::DESCRIPTOR_MLDB)
|
||||
, descriptor(AKAZE::DESCRIPTOR_MLDB)
|
||||
, descriptor_size(0)
|
||||
, descriptor_channels(3)
|
||||
, descriptor_pattern_size(10)
|
||||
@@ -75,4 +60,6 @@ struct AKAZEOptions {
|
||||
int kcontrast_nbins; ///< Number of bins for the contrast factor histogram
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,9 +11,62 @@
|
||||
|
||||
/* ************************************************************************* */
|
||||
// Includes
|
||||
#include "../precomp.hpp"
|
||||
#include "AKAZEConfig.h"
|
||||
#include "TEvolution.h"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/// A-KAZE nonlinear diffusion filtering evolution
|
||||
template <typename MatType>
|
||||
struct Evolution
|
||||
{
|
||||
Evolution() {
|
||||
etime = 0.0f;
|
||||
esigma = 0.0f;
|
||||
octave = 0;
|
||||
sublevel = 0;
|
||||
sigma_size = 0;
|
||||
octave_ratio = 0.0f;
|
||||
border = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
explicit Evolution(const Evolution<T> &other) {
|
||||
size = other.size;
|
||||
etime = other.etime;
|
||||
esigma = other.esigma;
|
||||
octave = other.octave;
|
||||
sublevel = other.sublevel;
|
||||
sigma_size = other.sigma_size;
|
||||
octave_ratio = other.octave_ratio;
|
||||
border = other.border;
|
||||
|
||||
other.Lx.copyTo(Lx);
|
||||
other.Ly.copyTo(Ly);
|
||||
other.Lt.copyTo(Lt);
|
||||
other.Lsmooth.copyTo(Lsmooth);
|
||||
other.Ldet.copyTo(Ldet);
|
||||
}
|
||||
|
||||
MatType Lx, Ly; ///< First order spatial derivatives
|
||||
MatType Lt; ///< Evolution image
|
||||
MatType Lsmooth; ///< Smoothed image, used only for computing determinant, released afterwards
|
||||
MatType Ldet; ///< Detector response
|
||||
|
||||
Size size; ///< Size of the layer
|
||||
float etime; ///< Evolution time
|
||||
float esigma; ///< Evolution sigma. For linear diffusion t = sigma^2 / 2
|
||||
int octave; ///< Image octave
|
||||
int sublevel; ///< Image sublevel in each octave
|
||||
int sigma_size; ///< Integer esigma. For computing the feature detector responses
|
||||
float octave_ratio; ///< Scaling ratio of this octave. ratio = 2^octave
|
||||
int border; ///< Width of border where descriptors cannot be computed
|
||||
};
|
||||
|
||||
typedef Evolution<Mat> MEvolution;
|
||||
typedef Evolution<UMat> UEvolution;
|
||||
typedef std::vector<MEvolution> Pyramid;
|
||||
typedef std::vector<UEvolution> UMatPyramid;
|
||||
|
||||
/* ************************************************************************* */
|
||||
// AKAZE Class Declaration
|
||||
@@ -22,7 +75,7 @@ class AKAZEFeatures {
|
||||
private:
|
||||
|
||||
AKAZEOptions options_; ///< Configuration options for AKAZE
|
||||
std::vector<TEvolution> evolution_; ///< Vector of nonlinear diffusion evolution
|
||||
Pyramid evolution_; ///< Vector of nonlinear diffusion evolution
|
||||
|
||||
/// FED parameters
|
||||
int ncycles_; ///< Number of cycles
|
||||
@@ -35,23 +88,21 @@ private:
|
||||
cv::Mat descriptorBits_;
|
||||
cv::Mat bitMask_;
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor with input arguments
|
||||
AKAZEFeatures(const AKAZEOptions& options);
|
||||
|
||||
/// Scale Space methods
|
||||
void Allocate_Memory_Evolution();
|
||||
int Create_Nonlinear_Scale_Space(const cv::Mat& img);
|
||||
void Feature_Detection(std::vector<cv::KeyPoint>& kpts);
|
||||
void Compute_Determinant_Hessian_Response(void);
|
||||
void Compute_Multiscale_Derivatives(void);
|
||||
void Find_Scale_Space_Extrema(std::vector<cv::KeyPoint>& kpts);
|
||||
void Do_Subpixel_Refinement(std::vector<cv::KeyPoint>& kpts);
|
||||
void Find_Scale_Space_Extrema(std::vector<Mat>& keypoints_by_layers);
|
||||
void Do_Subpixel_Refinement(std::vector<Mat>& keypoints_by_layers,
|
||||
std::vector<KeyPoint>& kpts);
|
||||
|
||||
/// Feature description methods
|
||||
void Compute_Descriptors(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc);
|
||||
static void Compute_Main_Orientation(cv::KeyPoint& kpt, const std::vector<TEvolution>& evolution_);
|
||||
void Compute_Keypoints_Orientation(std::vector<cv::KeyPoint>& kpts) const;
|
||||
|
||||
public:
|
||||
/// Constructor with input arguments
|
||||
AKAZEFeatures(const AKAZEOptions& options);
|
||||
void Create_Nonlinear_Scale_Space(InputArray img);
|
||||
void Feature_Detection(std::vector<cv::KeyPoint>& kpts);
|
||||
void Compute_Descriptors(std::vector<cv::KeyPoint>& kpts, OutputArray desc);
|
||||
};
|
||||
|
||||
/* ************************************************************************* */
|
||||
@@ -59,4 +110,6 @@ public:
|
||||
void generateDescriptorSubsample(cv::Mat& sampleList, cv::Mat& comparisons,
|
||||
int nbits, int pattern_size, int nchannels);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,19 +5,21 @@
|
||||
* @author Pablo F. Alcantarilla
|
||||
*/
|
||||
|
||||
#ifndef __OPENCV_FEATURES_2D_AKAZE_CONFIG_H__
|
||||
#define __OPENCV_FEATURES_2D_AKAZE_CONFIG_H__
|
||||
#ifndef __OPENCV_FEATURES_2D_KAZE_CONFIG_H__
|
||||
#define __OPENCV_FEATURES_2D_KAZE_CONFIG_H__
|
||||
|
||||
// OpenCV Includes
|
||||
#include "../precomp.hpp"
|
||||
#include <opencv2/features2d.hpp>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
//*************************************************************************************
|
||||
|
||||
struct KAZEOptions {
|
||||
|
||||
KAZEOptions()
|
||||
: diffusivity(cv::DIFF_PM_G2)
|
||||
: diffusivity(KAZE::DIFF_PM_G2)
|
||||
|
||||
, soffset(1.60f)
|
||||
, omax(4)
|
||||
@@ -49,4 +51,6 @@ struct KAZEOptions {
|
||||
bool extended;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,14 +20,15 @@
|
||||
* @date Jan 21, 2012
|
||||
* @author Pablo F. Alcantarilla
|
||||
*/
|
||||
|
||||
#include "../precomp.hpp"
|
||||
#include "KAZEFeatures.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
// Namespaces
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using namespace cv::details::kaze;
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
@@ -52,21 +53,22 @@ KAZEFeatures::KAZEFeatures(KAZEOptions& options)
|
||||
void KAZEFeatures::Allocate_Memory_Evolution(void) {
|
||||
|
||||
// Allocate the dimension of the matrices for the evolution
|
||||
for (int i = 0; i <= options_.omax - 1; i++) {
|
||||
for (int j = 0; j <= options_.nsublevels - 1; j++) {
|
||||
|
||||
for (int i = 0; i <= options_.omax - 1; i++)
|
||||
{
|
||||
for (int j = 0; j <= options_.nsublevels - 1; j++)
|
||||
{
|
||||
TEvolution aux;
|
||||
aux.Lx = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Ly = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Lxx = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Lxy = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Lyy = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Lt = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Lsmooth = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Ldet = cv::Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.esigma = options_.soffset*pow((float)2.0f, (float)(j) / (float)(options_.nsublevels)+i);
|
||||
aux.Lx = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Ly = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Lxx = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Lxy = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Lyy = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Lt = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Lsmooth = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.Ldet = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
|
||||
aux.esigma = options_.soffset*pow((float)2.0f, (float)(j) / (float)(options_.nsublevels)+i);
|
||||
aux.etime = 0.5f*(aux.esigma*aux.esigma);
|
||||
aux.sigma_size = fRound(aux.esigma);
|
||||
aux.sigma_size = cvRound(aux.esigma);
|
||||
aux.octave = i;
|
||||
aux.sublevel = j;
|
||||
evolution_.push_back(aux);
|
||||
@@ -74,7 +76,8 @@ void KAZEFeatures::Allocate_Memory_Evolution(void) {
|
||||
}
|
||||
|
||||
// Allocate memory for the FED number of cycles and time steps
|
||||
for (size_t i = 1; i < evolution_.size(); i++) {
|
||||
for (size_t i = 1; i < evolution_.size(); i++)
|
||||
{
|
||||
int naux = 0;
|
||||
vector<float> tau;
|
||||
float ttime = 0.0;
|
||||
@@ -92,47 +95,43 @@ void KAZEFeatures::Allocate_Memory_Evolution(void) {
|
||||
* @param img Input image for which the nonlinear scale space needs to be created
|
||||
* @return 0 if the nonlinear scale space was created successfully. -1 otherwise
|
||||
*/
|
||||
int KAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat &img)
|
||||
int KAZEFeatures::Create_Nonlinear_Scale_Space(const Mat &img)
|
||||
{
|
||||
CV_Assert(evolution_.size() > 0);
|
||||
|
||||
// Copy the original image to the first level of the evolution
|
||||
img.copyTo(evolution_[0].Lt);
|
||||
gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lt, 0, 0, options_.soffset);
|
||||
gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lsmooth, 0, 0, options_.sderivatives);
|
||||
gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lt, 0, 0, options_.soffset);
|
||||
gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lsmooth, 0, 0, options_.sderivatives);
|
||||
|
||||
// Firstly compute the kcontrast factor
|
||||
Compute_KContrast(evolution_[0].Lt, options_.kcontrast_percentille);
|
||||
|
||||
// Allocate memory for the flow and step images
|
||||
cv::Mat Lflow = cv::Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
|
||||
cv::Mat Lstep = cv::Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
|
||||
Mat Lflow = Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
|
||||
Mat Lstep = Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F);
|
||||
|
||||
// Now generate the rest of evolution levels
|
||||
for (size_t i = 1; i < evolution_.size(); i++) {
|
||||
|
||||
for (size_t i = 1; i < evolution_.size(); i++)
|
||||
{
|
||||
evolution_[i - 1].Lt.copyTo(evolution_[i].Lt);
|
||||
gaussian_2D_convolution(evolution_[i - 1].Lt, evolution_[i].Lsmooth, 0, 0, options_.sderivatives);
|
||||
gaussian_2D_convolution(evolution_[i - 1].Lt, evolution_[i].Lsmooth, 0, 0, options_.sderivatives);
|
||||
|
||||
// Compute the Gaussian derivatives Lx and Ly
|
||||
Scharr(evolution_[i].Lsmooth, evolution_[i].Lx, CV_32F, 1, 0, 1, 0, BORDER_DEFAULT);
|
||||
Scharr(evolution_[i].Lsmooth, evolution_[i].Ly, CV_32F, 0, 1, 1, 0, BORDER_DEFAULT);
|
||||
|
||||
// Compute the conductivity equation
|
||||
if (options_.diffusivity == cv::DIFF_PM_G1) {
|
||||
pm_g1(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
|
||||
}
|
||||
else if (options_.diffusivity == cv::DIFF_PM_G2) {
|
||||
pm_g2(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
|
||||
}
|
||||
else if (options_.diffusivity == cv::DIFF_WEICKERT) {
|
||||
weickert_diffusivity(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
|
||||
}
|
||||
if (options_.diffusivity == KAZE::DIFF_PM_G1)
|
||||
pm_g1(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
|
||||
else if (options_.diffusivity == KAZE::DIFF_PM_G2)
|
||||
pm_g2(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
|
||||
else if (options_.diffusivity == KAZE::DIFF_WEICKERT)
|
||||
weickert_diffusivity(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast);
|
||||
|
||||
// Perform FED n inner steps
|
||||
for (int j = 0; j < nsteps_[i - 1]; j++) {
|
||||
for (int j = 0; j < nsteps_[i - 1]; j++)
|
||||
nld_step_scalar(evolution_[i].Lt, Lflow, Lstep, tsteps_[i - 1][j]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -144,9 +143,9 @@ int KAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat &img)
|
||||
* @param img Input image
|
||||
* @param kpercentile Percentile of the gradient histogram
|
||||
*/
|
||||
void KAZEFeatures::Compute_KContrast(const cv::Mat &img, const float &kpercentile)
|
||||
void KAZEFeatures::Compute_KContrast(const Mat &img, const float &kpercentile)
|
||||
{
|
||||
options_.kcontrast = compute_k_percentile(img, kpercentile, options_.sderivatives, options_.kcontrast_bins, 0, 0);
|
||||
options_.kcontrast = compute_k_percentile(img, kpercentile, options_.sderivatives, options_.kcontrast_bins, 0, 0);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
@@ -181,7 +180,7 @@ void KAZEFeatures::Compute_Detector_Response(void)
|
||||
* @brief This method selects interesting keypoints through the nonlinear scale space
|
||||
* @param kpts Vector of keypoints
|
||||
*/
|
||||
void KAZEFeatures::Feature_Detection(std::vector<cv::KeyPoint>& kpts)
|
||||
void KAZEFeatures::Feature_Detection(std::vector<KeyPoint>& kpts)
|
||||
{
|
||||
kpts.clear();
|
||||
Compute_Detector_Response();
|
||||
@@ -190,14 +189,14 @@ void KAZEFeatures::Feature_Detection(std::vector<cv::KeyPoint>& kpts)
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
class MultiscaleDerivativesKAZEInvoker : public cv::ParallelLoopBody
|
||||
class MultiscaleDerivativesKAZEInvoker : public ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
explicit MultiscaleDerivativesKAZEInvoker(std::vector<TEvolution>& ev) : evolution_(&ev)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(const cv::Range& range) const
|
||||
void operator()(const Range& range) const CV_OVERRIDE
|
||||
{
|
||||
std::vector<TEvolution>& evolution = *evolution_;
|
||||
for (int i = range.start; i < range.end; i++)
|
||||
@@ -226,74 +225,79 @@ private:
|
||||
*/
|
||||
void KAZEFeatures::Compute_Multiscale_Derivatives(void)
|
||||
{
|
||||
cv::parallel_for_(cv::Range(0, (int)evolution_.size()),
|
||||
parallel_for_(Range(0, (int)evolution_.size()),
|
||||
MultiscaleDerivativesKAZEInvoker(evolution_));
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************************* */
|
||||
class FindExtremumKAZEInvoker : public cv::ParallelLoopBody
|
||||
class FindExtremumKAZEInvoker : public ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
explicit FindExtremumKAZEInvoker(std::vector<TEvolution>& ev, std::vector<std::vector<cv::KeyPoint> >& kpts_par,
|
||||
explicit FindExtremumKAZEInvoker(std::vector<TEvolution>& ev, std::vector<std::vector<KeyPoint> >& kpts_par,
|
||||
const KAZEOptions& options) : evolution_(&ev), kpts_par_(&kpts_par), options_(options)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(const cv::Range& range) const
|
||||
void operator()(const Range& range) const CV_OVERRIDE
|
||||
{
|
||||
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++) {
|
||||
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);
|
||||
|
||||
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);
|
||||
// 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)
|
||||
{
|
||||
KeyPoint point;
|
||||
point.pt.x = (float)jx;
|
||||
point.pt.y = (float)ix;
|
||||
point.response = fabs(value);
|
||||
point.size = evolution[i].esigma;
|
||||
point.octave = (int)evolution[i].octave;
|
||||
point.class_id = i;
|
||||
|
||||
// We use the angle field for the sublevel value
|
||||
// Then, we will replace this angle field with the main orientation
|
||||
point.angle = static_cast<float>(evolution[i].sublevel);
|
||||
kpts_par[i - 1].push_back(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<TEvolution>* evolution_;
|
||||
std::vector<std::vector<cv::KeyPoint> >* kpts_par_;
|
||||
std::vector<std::vector<KeyPoint> >* kpts_par_;
|
||||
KAZEOptions options_;
|
||||
};
|
||||
|
||||
@@ -304,7 +308,7 @@ private:
|
||||
* @param kpts Vector of keypoints
|
||||
* @note We compute features for each of the nonlinear scale space level in a different processing thread
|
||||
*/
|
||||
void KAZEFeatures::Determinant_Hessian(std::vector<cv::KeyPoint>& kpts)
|
||||
void KAZEFeatures::Determinant_Hessian(std::vector<KeyPoint>& kpts)
|
||||
{
|
||||
int level = 0;
|
||||
float dist = 0.0, smax = 3.0;
|
||||
@@ -325,12 +329,14 @@ void KAZEFeatures::Determinant_Hessian(std::vector<cv::KeyPoint>& kpts)
|
||||
kpts_par_.push_back(aux);
|
||||
}
|
||||
|
||||
cv::parallel_for_(cv::Range(1, (int)evolution_.size()-1),
|
||||
FindExtremumKAZEInvoker(evolution_, kpts_par_, options_));
|
||||
parallel_for_(Range(1, (int)evolution_.size()-1),
|
||||
FindExtremumKAZEInvoker(evolution_, kpts_par_, options_));
|
||||
|
||||
// Now fill the vector of keypoints!!!
|
||||
for (int i = 0; i < (int)kpts_par_.size(); i++) {
|
||||
for (int j = 0; j < (int)kpts_par_[i].size(); j++) {
|
||||
for (int i = 0; i < (int)kpts_par_.size(); i++)
|
||||
{
|
||||
for (int j = 0; j < (int)kpts_par_[i].size(); j++)
|
||||
{
|
||||
level = i + 1;
|
||||
is_extremum = true;
|
||||
is_repeated = false;
|
||||
@@ -357,18 +363,16 @@ void KAZEFeatures::Determinant_Hessian(std::vector<cv::KeyPoint>& kpts)
|
||||
|
||||
if (is_extremum == true) {
|
||||
// Check that the point is under the image limits for the descriptor computation
|
||||
left_x = fRound(kpts_par_[i][j].pt.x - smax*kpts_par_[i][j].size);
|
||||
right_x = fRound(kpts_par_[i][j].pt.x + smax*kpts_par_[i][j].size);
|
||||
up_y = fRound(kpts_par_[i][j].pt.y - smax*kpts_par_[i][j].size);
|
||||
down_y = fRound(kpts_par_[i][j].pt.y + smax*kpts_par_[i][j].size);
|
||||
left_x = cvRound(kpts_par_[i][j].pt.x - smax*kpts_par_[i][j].size);
|
||||
right_x = cvRound(kpts_par_[i][j].pt.x + smax*kpts_par_[i][j].size);
|
||||
up_y = cvRound(kpts_par_[i][j].pt.y - smax*kpts_par_[i][j].size);
|
||||
down_y = cvRound(kpts_par_[i][j].pt.y + smax*kpts_par_[i][j].size);
|
||||
|
||||
if (left_x < 0 || right_x >= evolution_[level].Ldet.cols ||
|
||||
up_y < 0 || down_y >= evolution_[level].Ldet.rows) {
|
||||
is_out = true;
|
||||
}
|
||||
|
||||
is_out = false;
|
||||
|
||||
if (is_out == false) {
|
||||
if (is_repeated == false) {
|
||||
kpts.push_back(kpts_par_[i][j]);
|
||||
@@ -388,7 +392,7 @@ void KAZEFeatures::Determinant_Hessian(std::vector<cv::KeyPoint>& kpts)
|
||||
* @brief This method performs subpixel refinement of the detected keypoints
|
||||
* @param kpts Vector of detected keypoints
|
||||
*/
|
||||
void KAZEFeatures::Do_Subpixel_Refinement(std::vector<cv::KeyPoint> &kpts) {
|
||||
void KAZEFeatures::Do_Subpixel_Refinement(std::vector<KeyPoint> &kpts) {
|
||||
|
||||
int step = 1;
|
||||
int x = 0, y = 0;
|
||||
@@ -482,10 +486,10 @@ void KAZEFeatures::Do_Subpixel_Refinement(std::vector<cv::KeyPoint> &kpts) {
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
class KAZE_Descriptor_Invoker : public cv::ParallelLoopBody
|
||||
class KAZE_Descriptor_Invoker : public ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
KAZE_Descriptor_Invoker(std::vector<cv::KeyPoint> &kpts, cv::Mat &desc, std::vector<TEvolution>& evolution, const KAZEOptions& options)
|
||||
KAZE_Descriptor_Invoker(std::vector<KeyPoint> &kpts, Mat &desc, std::vector<TEvolution>& evolution, const KAZEOptions& options)
|
||||
: kpts_(&kpts)
|
||||
, desc_(&desc)
|
||||
, evolution_(&evolution)
|
||||
@@ -497,16 +501,16 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (const cv::Range& range) const
|
||||
void operator() (const Range& range) const CV_OVERRIDE
|
||||
{
|
||||
std::vector<cv::KeyPoint> &kpts = *kpts_;
|
||||
cv::Mat &desc = *desc_;
|
||||
std::vector<TEvolution> &evolution = *evolution_;
|
||||
std::vector<KeyPoint> &kpts = *kpts_;
|
||||
Mat &desc = *desc_;
|
||||
std::vector<TEvolution> &evolution = *evolution_;
|
||||
|
||||
for (int i = range.start; i < range.end; i++)
|
||||
{
|
||||
kpts[i].angle = 0.0;
|
||||
if (options_.upright)
|
||||
if (options_.upright)
|
||||
{
|
||||
kpts[i].angle = 0.0;
|
||||
if (options_.extended)
|
||||
@@ -526,13 +530,13 @@ public:
|
||||
}
|
||||
}
|
||||
private:
|
||||
void Get_KAZE_Upright_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const;
|
||||
void Get_KAZE_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const;
|
||||
void Get_KAZE_Upright_Descriptor_128(const cv::KeyPoint& kpt, float* desc) const;
|
||||
void Get_KAZE_Descriptor_128(const cv::KeyPoint& kpt, float *desc) const;
|
||||
void Get_KAZE_Upright_Descriptor_64(const KeyPoint& kpt, float* desc) const;
|
||||
void Get_KAZE_Descriptor_64(const KeyPoint& kpt, float* desc) const;
|
||||
void Get_KAZE_Upright_Descriptor_128(const KeyPoint& kpt, float* desc) const;
|
||||
void Get_KAZE_Descriptor_128(const KeyPoint& kpt, float *desc) const;
|
||||
|
||||
std::vector<cv::KeyPoint> * kpts_;
|
||||
cv::Mat * desc_;
|
||||
std::vector<KeyPoint> * kpts_;
|
||||
Mat * desc_;
|
||||
std::vector<TEvolution> * evolution_;
|
||||
KAZEOptions options_;
|
||||
};
|
||||
@@ -543,7 +547,7 @@ private:
|
||||
* @param kpts Vector of keypoints
|
||||
* @param desc Matrix with the feature descriptors
|
||||
*/
|
||||
void KAZEFeatures::Feature_Description(std::vector<cv::KeyPoint> &kpts, cv::Mat &desc)
|
||||
void KAZEFeatures::Feature_Description(std::vector<KeyPoint> &kpts, Mat &desc)
|
||||
{
|
||||
for(size_t i = 0; i < kpts.size(); i++)
|
||||
{
|
||||
@@ -558,7 +562,7 @@ void KAZEFeatures::Feature_Description(std::vector<cv::KeyPoint> &kpts, cv::Mat
|
||||
desc = Mat::zeros((int)kpts.size(), 64, CV_32FC1);
|
||||
}
|
||||
|
||||
cv::parallel_for_(cv::Range(0, (int)kpts.size()), KAZE_Descriptor_Invoker(kpts, desc, evolution_, options_));
|
||||
parallel_for_(Range(0, (int)kpts.size()), KAZE_Descriptor_Invoker(kpts, desc, evolution_, options_));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
@@ -568,7 +572,7 @@ void KAZEFeatures::Feature_Description(std::vector<cv::KeyPoint> &kpts, cv::Mat
|
||||
* @note The orientation is computed using a similar approach as described in the
|
||||
* original SURF method. See Bay et al., Speeded Up Robust Features, ECCV 2006
|
||||
*/
|
||||
void KAZEFeatures::Compute_Main_Orientation(cv::KeyPoint &kpt, const std::vector<TEvolution>& evolution_, const KAZEOptions& options)
|
||||
void KAZEFeatures::Compute_Main_Orientation(KeyPoint &kpt, const std::vector<TEvolution>& evolution_, const KAZEOptions& options)
|
||||
{
|
||||
int ix = 0, iy = 0, idx = 0, s = 0, level = 0;
|
||||
float xf = 0.0, yf = 0.0, gweight = 0.0;
|
||||
@@ -581,14 +585,14 @@ void KAZEFeatures::Compute_Main_Orientation(cv::KeyPoint &kpt, const std::vector
|
||||
xf = kpt.pt.x;
|
||||
yf = kpt.pt.y;
|
||||
level = kpt.class_id;
|
||||
s = fRound(kpt.size / 2.0f);
|
||||
s = cvRound(kpt.size / 2.0f);
|
||||
|
||||
// Calculate derivatives responses for points within radius of 6*scale
|
||||
for (int i = -6; i <= 6; ++i) {
|
||||
for (int j = -6; j <= 6; ++j) {
|
||||
if (i*i + j*j < 36) {
|
||||
iy = fRound(yf + j*s);
|
||||
ix = fRound(xf + i*s);
|
||||
iy = cvRound(yf + j*s);
|
||||
ix = cvRound(xf + i*s);
|
||||
|
||||
if (iy >= 0 && iy < options.img_height && ix >= 0 && ix < options.img_width) {
|
||||
gweight = gaussian(iy - yf, ix - xf, 2.5f*s);
|
||||
@@ -600,7 +604,7 @@ void KAZEFeatures::Compute_Main_Orientation(cv::KeyPoint &kpt, const std::vector
|
||||
resY[idx] = 0.0;
|
||||
}
|
||||
|
||||
Ang[idx] = getAngle(resX[idx], resY[idx]);
|
||||
Ang[idx] = fastAtan2(resY[idx], resX[idx]) * (float)(CV_PI / 180.0f);
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
@@ -632,7 +636,7 @@ void KAZEFeatures::Compute_Main_Orientation(cv::KeyPoint &kpt, const std::vector
|
||||
if (sumX*sumX + sumY*sumY > max) {
|
||||
// store largest orientation
|
||||
max = sumX*sumX + sumY*sumY;
|
||||
kpt.angle = getAngle(sumX, sumY);
|
||||
kpt.angle = fastAtan2(sumY, sumX);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -647,7 +651,7 @@ void KAZEFeatures::Compute_Main_Orientation(cv::KeyPoint &kpt, const std::vector
|
||||
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
|
||||
* ECCV 2008
|
||||
*/
|
||||
void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_64(const cv::KeyPoint &kpt, float *desc) const
|
||||
void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_64(const KeyPoint &kpt, float *desc) const
|
||||
{
|
||||
float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0;
|
||||
float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0;
|
||||
@@ -670,7 +674,7 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_64(const cv::KeyPoint
|
||||
// Get the information from the keypoint
|
||||
yf = kpt.pt.y;
|
||||
xf = kpt.pt.x;
|
||||
scale = fRound(kpt.size / 2.0f);
|
||||
scale = cvRound(kpt.size / 2.0f);
|
||||
level = kpt.class_id;
|
||||
|
||||
i = -8;
|
||||
@@ -775,7 +779,7 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_64(const cv::KeyPoint
|
||||
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
|
||||
* ECCV 2008
|
||||
*/
|
||||
void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const cv::KeyPoint &kpt, float *desc) const
|
||||
void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const KeyPoint &kpt, float *desc) const
|
||||
{
|
||||
float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0;
|
||||
float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0;
|
||||
@@ -798,8 +802,8 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const cv::KeyPoint &kpt, fl
|
||||
// Get the information from the keypoint
|
||||
yf = kpt.pt.y;
|
||||
xf = kpt.pt.x;
|
||||
scale = fRound(kpt.size / 2.0f);
|
||||
angle = kpt.angle;
|
||||
scale = cvRound(kpt.size / 2.0f);
|
||||
angle = kpt.angle * static_cast<float>(CV_PI / 180.f);
|
||||
level = kpt.class_id;
|
||||
co = cos(angle);
|
||||
si = sin(angle);
|
||||
@@ -837,13 +841,13 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const cv::KeyPoint &kpt, fl
|
||||
|
||||
// Get the gaussian weighted x and y responses
|
||||
gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale);
|
||||
y1 = fRound(sample_y - 0.5f);
|
||||
x1 = fRound(sample_x - 0.5f);
|
||||
y1 = cvFloor(sample_y);
|
||||
x1 = cvFloor(sample_x);
|
||||
|
||||
checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height);
|
||||
|
||||
y2 = (int)(sample_y + 0.5f);
|
||||
x2 = (int)(sample_x + 0.5f);
|
||||
y2 = y1 + 1;
|
||||
x2 = x1 + 1;
|
||||
|
||||
checkDescriptorLimits(x2, y2, options_.img_width, options_.img_height);
|
||||
|
||||
@@ -904,7 +908,7 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const cv::KeyPoint &kpt, fl
|
||||
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
|
||||
* ECCV 2008
|
||||
*/
|
||||
void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_128(const cv::KeyPoint &kpt, float *desc) const
|
||||
void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_128(const KeyPoint &kpt, float *desc) const
|
||||
{
|
||||
float gauss_s1 = 0.0, gauss_s2 = 0.0;
|
||||
float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0;
|
||||
@@ -929,7 +933,7 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_128(const cv::KeyPoint
|
||||
// Get the information from the keypoint
|
||||
yf = kpt.pt.y;
|
||||
xf = kpt.pt.x;
|
||||
scale = fRound(kpt.size / 2.0f);
|
||||
scale = cvRound(kpt.size / 2.0f);
|
||||
level = kpt.class_id;
|
||||
|
||||
i = -8;
|
||||
@@ -1056,7 +1060,7 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_128(const cv::KeyPoint
|
||||
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
|
||||
* ECCV 2008
|
||||
*/
|
||||
void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const cv::KeyPoint &kpt, float *desc) const
|
||||
void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const KeyPoint &kpt, float *desc) const
|
||||
{
|
||||
float gauss_s1 = 0.0, gauss_s2 = 0.0;
|
||||
float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0;
|
||||
@@ -1081,8 +1085,8 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const cv::KeyPoint &kpt, f
|
||||
// Get the information from the keypoint
|
||||
yf = kpt.pt.y;
|
||||
xf = kpt.pt.x;
|
||||
scale = fRound(kpt.size / 2.0f);
|
||||
angle = kpt.angle;
|
||||
scale = cvRound(kpt.size / 2.0f);
|
||||
angle = kpt.angle * static_cast<float>(CV_PI / 180.f);
|
||||
level = kpt.class_id;
|
||||
co = cos(angle);
|
||||
si = sin(angle);
|
||||
@@ -1123,13 +1127,13 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const cv::KeyPoint &kpt, f
|
||||
// Get the gaussian weighted x and y responses
|
||||
gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale);
|
||||
|
||||
y1 = fRound(sample_y - 0.5f);
|
||||
x1 = fRound(sample_x - 0.5f);
|
||||
y1 = cvFloor(sample_y);
|
||||
x1 = cvFloor(sample_x);
|
||||
|
||||
checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height);
|
||||
|
||||
y2 = (int)(sample_y + 0.5f);
|
||||
x2 = (int)(sample_x + 0.5f);
|
||||
y2 = y1 + 1;
|
||||
x2 = x1 + 1;
|
||||
|
||||
checkDescriptorLimits(x2, y2, options_.img_width, options_.img_height);
|
||||
|
||||
@@ -1202,3 +1206,5 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const cv::KeyPoint &kpt, f
|
||||
desc[i] /= len;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,43 +17,48 @@
|
||||
#include "fed.h"
|
||||
#include "TEvolution.h"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/* ************************************************************************* */
|
||||
// KAZE Class Declaration
|
||||
class KAZEFeatures {
|
||||
|
||||
class KAZEFeatures
|
||||
{
|
||||
private:
|
||||
|
||||
/// Parameters of the Nonlinear diffusion class
|
||||
KAZEOptions options_; ///< Configuration options for KAZE
|
||||
std::vector<TEvolution> evolution_; ///< Vector of nonlinear diffusion evolution
|
||||
/// Parameters of the Nonlinear diffusion class
|
||||
KAZEOptions options_; ///< Configuration options for KAZE
|
||||
std::vector<TEvolution> evolution_; ///< Vector of nonlinear diffusion evolution
|
||||
|
||||
/// Vector of keypoint vectors for finding extrema in multiple threads
|
||||
/// Vector of keypoint vectors for finding extrema in multiple threads
|
||||
std::vector<std::vector<cv::KeyPoint> > kpts_par_;
|
||||
|
||||
/// FED parameters
|
||||
int ncycles_; ///< Number of cycles
|
||||
bool reordering_; ///< Flag for reordering time steps
|
||||
std::vector<std::vector<float > > tsteps_; ///< Vector of FED dynamic time steps
|
||||
std::vector<int> nsteps_; ///< Vector of number of steps per cycle
|
||||
/// FED parameters
|
||||
int ncycles_; ///< Number of cycles
|
||||
bool reordering_; ///< Flag for reordering time steps
|
||||
std::vector<std::vector<float > > tsteps_; ///< Vector of FED dynamic time steps
|
||||
std::vector<int> nsteps_; ///< Vector of number of steps per cycle
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
/// Constructor
|
||||
KAZEFeatures(KAZEOptions& options);
|
||||
|
||||
/// Public methods for KAZE interface
|
||||
/// Public methods for KAZE interface
|
||||
void Allocate_Memory_Evolution(void);
|
||||
int Create_Nonlinear_Scale_Space(const cv::Mat& img);
|
||||
void Feature_Detection(std::vector<cv::KeyPoint>& kpts);
|
||||
void Feature_Description(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc);
|
||||
static void Compute_Main_Orientation(cv::KeyPoint& kpt, const std::vector<TEvolution>& evolution_, const KAZEOptions& options);
|
||||
|
||||
/// Feature Detection Methods
|
||||
/// Feature Detection Methods
|
||||
void Compute_KContrast(const cv::Mat& img, const float& kper);
|
||||
void Compute_Multiscale_Derivatives(void);
|
||||
void Compute_Detector_Response(void);
|
||||
void Determinant_Hessian(std::vector<cv::KeyPoint>& kpts);
|
||||
void Determinant_Hessian(std::vector<cv::KeyPoint>& kpts);
|
||||
void Do_Subpixel_Refinement(std::vector<cv::KeyPoint>& kpts);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
#ifndef __OPENCV_FEATURES_2D_TEVOLUTION_H__
|
||||
#define __OPENCV_FEATURES_2D_TEVOLUTION_H__
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/* ************************************************************************* */
|
||||
/// KAZE/A-KAZE nonlinear diffusion filtering evolution
|
||||
struct TEvolution {
|
||||
|
||||
struct TEvolution
|
||||
{
|
||||
TEvolution() {
|
||||
etime = 0.0f;
|
||||
esigma = 0.0f;
|
||||
@@ -20,11 +23,12 @@ struct TEvolution {
|
||||
sigma_size = 0;
|
||||
}
|
||||
|
||||
cv::Mat Lx, Ly; ///< First order spatial derivatives
|
||||
cv::Mat Lxx, Lxy, Lyy; ///< Second order spatial derivatives
|
||||
cv::Mat Lt; ///< Evolution image
|
||||
cv::Mat Lsmooth; ///< Smoothed image
|
||||
cv::Mat Ldet; ///< Detector response
|
||||
Mat Lx, Ly; ///< First order spatial derivatives
|
||||
Mat Lxx, Lxy, Lyy; ///< Second order spatial derivatives
|
||||
Mat Lt; ///< Evolution image
|
||||
Mat Lsmooth; ///< Smoothed image
|
||||
Mat Ldet; ///< Detector response
|
||||
|
||||
float etime; ///< Evolution time
|
||||
float esigma; ///< Evolution sigma. For linear diffusion t = sigma^2 / 2
|
||||
int octave; ///< Image octave
|
||||
@@ -32,4 +36,6 @@ struct TEvolution {
|
||||
int sigma_size; ///< Integer esigma. For computing the feature detector responses
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -72,7 +72,7 @@ int fed_tau_by_cycle_time(const float& t, const float& tau_max,
|
||||
float scale = 0.0; // Ratio of t we search to maximal t
|
||||
|
||||
// Compute necessary number of time steps
|
||||
n = (int)(ceilf(sqrtf(3.0f*t/tau_max+0.25f)-0.5f-1.0e-8f)+ 0.5f);
|
||||
n = cvCeil(sqrtf(3.0f*t/tau_max+0.25f)-0.5f-1.0e-8f);
|
||||
scale = 3.0f*t/(tau_max*(float)(n*(n+1)));
|
||||
|
||||
// Call internal FED time step creation routine
|
||||
|
||||
@@ -22,416 +22,521 @@
|
||||
* @author Pablo F. Alcantarilla
|
||||
*/
|
||||
|
||||
#include "../precomp.hpp"
|
||||
#include "nldiffusion_functions.h"
|
||||
#include <iostream>
|
||||
|
||||
// Namespaces
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
namespace cv {
|
||||
namespace details {
|
||||
namespace kaze {
|
||||
namespace cv
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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) {
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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;
|
||||
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_;
|
||||
}
|
||||
// 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_ = cvCeil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f)));
|
||||
ksize_y_ = ksize_x_;
|
||||
}
|
||||
|
||||
// The kernel size must be and odd number
|
||||
if ((ksize_x_ % 2) == 0) {
|
||||
ksize_x_ += 1;
|
||||
}
|
||||
// The kernel size must be and odd number
|
||||
if ((ksize_x_ % 2) == 0) {
|
||||
ksize_x_ += 1;
|
||||
}
|
||||
|
||||
if ((ksize_y_ % 2) == 0) {
|
||||
ksize_y_ += 1;
|
||||
}
|
||||
if ((ksize_y_ % 2) == 0) {
|
||||
ksize_y_ += 1;
|
||||
}
|
||||
|
||||
// Perform the Gaussian Smoothing with border replication
|
||||
GaussianBlur(src, dst, Size(ksize_x_, ksize_y_), sigma, sigma, BORDER_REPLICATE);
|
||||
}
|
||||
// Perform the Gaussian Smoothing with border replication
|
||||
GaussianBlur(src, dst, Size(ksize_x_, ksize_y_), sigma, sigma, BORDER_REPLICATE);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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) {
|
||||
cv::exp(-(Lx.mul(Lx) + Ly.mul(Ly)) / (k*k), 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(InputArray _Lx, InputArray _Ly, OutputArray _dst, float k) {
|
||||
_dst.create(_Lx.size(), _Lx.type());
|
||||
Mat Lx = _Lx.getMat();
|
||||
Mat Ly = _Ly.getMat();
|
||||
Mat dst = _dst.getMat();
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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) {
|
||||
dst = 1.0f / (1.0f + (Lx.mul(Lx) + Ly.mul(Ly)) / (k*k));
|
||||
}
|
||||
Size sz = Lx.size();
|
||||
float inv_k = 1.0f / (k*k);
|
||||
for (int y = 0; y < sz.height; y++) {
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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) {
|
||||
Mat modg;
|
||||
cv::pow((Lx.mul(Lx) + Ly.mul(Ly)) / (k*k), 4, modg);
|
||||
cv::exp(-3.315f / modg, dst);
|
||||
dst = 1.0f - dst;
|
||||
}
|
||||
const float* Lx_row = Lx.ptr<float>(y);
|
||||
const float* Ly_row = Ly.ptr<float>(y);
|
||||
float* dst_row = dst.ptr<float>(y);
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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) {
|
||||
Mat den;
|
||||
cv::sqrt(1.0f + (Lx.mul(Lx) + Ly.mul(Ly)) / (k*k), den);
|
||||
dst = 1.0f / den;
|
||||
}
|
||||
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 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) {
|
||||
exp(dst, dst);
|
||||
}
|
||||
|
||||
int nbin = 0, nelements = 0, nthreshold = 0, k = 0;
|
||||
float kperc = 0.0, modg = 0.0, lx = 0.0, ly = 0.0;
|
||||
float npoints = 0.0;
|
||||
float hmax = 0.0;
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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(InputArray _Lx, InputArray _Ly, OutputArray _dst, float k) {
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
// Create the array for the histogram
|
||||
std::vector<int> hist(nbins, 0);
|
||||
_dst.create(_Lx.size(), _Lx.type());
|
||||
Mat Lx = _Lx.getMat();
|
||||
Mat Ly = _Ly.getMat();
|
||||
Mat dst = _dst.getMat();
|
||||
|
||||
// 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);
|
||||
Size sz = Lx.size();
|
||||
dst.create(sz, Lx.type());
|
||||
float k2inv = 1.0f / (k * k);
|
||||
|
||||
// Perform the Gaussian convolution
|
||||
gaussian_2D_convolution(img, gaussian, ksize_x, ksize_y, gscale);
|
||||
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(InputArray _Lx, InputArray _Ly, OutputArray _dst, float k) {
|
||||
_dst.create(_Lx.size(), _Lx.type());
|
||||
Mat Lx = _Lx.getMat();
|
||||
Mat Ly = _Ly.getMat();
|
||||
Mat dst = _dst.getMat();
|
||||
|
||||
// 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);
|
||||
Size sz = Lx.size();
|
||||
float inv_k = 1.0f / (k*k);
|
||||
for (int y = 0; y < sz.height; y++) {
|
||||
|
||||
// Skip the borders for computing the histogram
|
||||
for (int i = 1; i < gaussian.rows - 1; i++) {
|
||||
for (int j = 1; j < gaussian.cols - 1; j++) {
|
||||
lx = *(Lx.ptr<float>(i)+j);
|
||||
ly = *(Ly.ptr<float>(i)+j);
|
||||
modg = sqrt(lx*lx + ly*ly);
|
||||
const float* Lx_row = Lx.ptr<float>(y);
|
||||
const float* Ly_row = Ly.ptr<float>(y);
|
||||
float* dst_row = dst.ptr<float>(y);
|
||||
|
||||
// Get the maximum
|
||||
if (modg > hmax) {
|
||||
hmax = modg;
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Skip the borders for computing the histogram
|
||||
for (int i = 1; i < gaussian.rows - 1; i++) {
|
||||
for (int j = 1; j < gaussian.cols - 1; j++) {
|
||||
lx = *(Lx.ptr<float>(i)+j);
|
||||
ly = *(Ly.ptr<float>(i)+j);
|
||||
modg = sqrt(lx*lx + ly*ly);
|
||||
exp(dst, dst);
|
||||
dst = 1.0 - dst;
|
||||
}
|
||||
|
||||
// Find the correspondent bin
|
||||
if (modg != 0.0) {
|
||||
nbin = (int)floor(nbins*(modg / hmax));
|
||||
|
||||
if (nbin == nbins) {
|
||||
nbin--;
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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(InputArray _Lx, InputArray _Ly, OutputArray _dst, float k) {
|
||||
_dst.create(_Lx.size(), _Lx.type());
|
||||
Mat Lx = _Lx.getMat();
|
||||
Mat Ly = _Ly.getMat();
|
||||
Mat dst = _dst.getMat();
|
||||
|
||||
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 den = sqrt(1.0f+inv_k*(Lx_row[x]*Lx_row[x] + Ly_row[x]*Ly_row[x]));
|
||||
dst_row[x] = 1.0f / den;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nelements < nthreshold) {
|
||||
kperc = 0.03f;
|
||||
}
|
||||
else {
|
||||
kperc = hmax*((float)(k) / (float)nbins);
|
||||
}
|
||||
|
||||
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) {
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
int nbin = 0, nelements = 0, nthreshold = 0, k = 0;
|
||||
float kperc = 0.0, modg = 0.0;
|
||||
float npoints = 0.0;
|
||||
float hmax = 0.0;
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @brief Compute derivative kernels for sizes different than 3
|
||||
* @param _kx Horizontal kernel values
|
||||
* @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) {
|
||||
// Create the array for the histogram
|
||||
std::vector<int> hist(nbins, 0);
|
||||
|
||||
int ksize = 3 + 2 * (scale - 1);
|
||||
// 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);
|
||||
|
||||
// The standard Scharr kernel
|
||||
if (scale == 1) {
|
||||
getDerivKernels(_kx, _ky, dx, dy, 0, true, CV_32F);
|
||||
return;
|
||||
}
|
||||
// Perform the Gaussian convolution
|
||||
gaussian_2D_convolution(img, gaussian, ksize_x, ksize_y, gscale);
|
||||
|
||||
_kx.create(ksize, 1, CV_32F, -1, true);
|
||||
_ky.create(ksize, 1, CV_32F, -1, true);
|
||||
Mat kx = _kx.getMat();
|
||||
Mat ky = _ky.getMat();
|
||||
// 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);
|
||||
|
||||
float w = 10.0f / 3.0f;
|
||||
float norm = 1.0f / (2.0f*scale*(w + 2.0f));
|
||||
// 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];
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
for (int j = 1; j < Lstep.cols - 1; j++)
|
||||
{
|
||||
float xpos = ((*(c.ptr<float>(i)+j)) + (*(c.ptr<float>(i)+j + 1)))*((*(Ld.ptr<float>(i)+j + 1)) - (*(Ld.ptr<float>(i)+j)));
|
||||
float xneg = ((*(c.ptr<float>(i)+j - 1)) + (*(c.ptr<float>(i)+j)))*((*(Ld.ptr<float>(i)+j)) - (*(Ld.ptr<float>(i)+j - 1)));
|
||||
float ypos = ((*(c.ptr<float>(i)+j)) + (*(c.ptr<float>(i + 1) + j)))*((*(Ld.ptr<float>(i + 1) + j)) - (*(Ld.ptr<float>(i)+j)));
|
||||
float yneg = ((*(c.ptr<float>(i - 1) + j)) + (*(c.ptr<float>(i)+j)))*((*(Ld.ptr<float>(i)+j)) - (*(Ld.ptr<float>(i - 1) + j)));
|
||||
*(Lstep.ptr<float>(i)+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));
|
||||
|
||||
for (int j = 1; j < Lstep.cols - 1; j++) {
|
||||
float xpos = ((*(c.ptr<float>(0) + j)) + (*(c.ptr<float>(0) + j + 1)))*((*(Ld.ptr<float>(0) + j + 1)) - (*(Ld.ptr<float>(0) + j)));
|
||||
float xneg = ((*(c.ptr<float>(0) + j - 1)) + (*(c.ptr<float>(0) + j)))*((*(Ld.ptr<float>(0) + j)) - (*(Ld.ptr<float>(0) + j - 1)));
|
||||
float ypos = ((*(c.ptr<float>(0) + j)) + (*(c.ptr<float>(1) + j)))*((*(Ld.ptr<float>(1) + j)) - (*(Ld.ptr<float>(0) + j)));
|
||||
*(Lstep.ptr<float>(0) + j) = 0.5f*stepsize*(xpos - xneg + ypos);
|
||||
}
|
||||
|
||||
for (int j = 1; j < Lstep.cols - 1; j++) {
|
||||
float xpos = ((*(c.ptr<float>(Lstep.rows - 1) + j)) + (*(c.ptr<float>(Lstep.rows - 1) + j + 1)))*((*(Ld.ptr<float>(Lstep.rows - 1) + j + 1)) - (*(Ld.ptr<float>(Lstep.rows - 1) + j)));
|
||||
float xneg = ((*(c.ptr<float>(Lstep.rows - 1) + j - 1)) + (*(c.ptr<float>(Lstep.rows - 1) + j)))*((*(Ld.ptr<float>(Lstep.rows - 1) + j)) - (*(Ld.ptr<float>(Lstep.rows - 1) + j - 1)));
|
||||
float ypos = ((*(c.ptr<float>(Lstep.rows - 1) + j)) + (*(c.ptr<float>(Lstep.rows - 1) + j)))*((*(Ld.ptr<float>(Lstep.rows - 1) + j)) - (*(Ld.ptr<float>(Lstep.rows - 1) + j)));
|
||||
float yneg = ((*(c.ptr<float>(Lstep.rows - 2) + j)) + (*(c.ptr<float>(Lstep.rows - 1) + j)))*((*(Ld.ptr<float>(Lstep.rows - 1) + j)) - (*(Ld.ptr<float>(Lstep.rows - 2) + j)));
|
||||
*(Lstep.ptr<float>(Lstep.rows - 1) + j) = 0.5f*stepsize*(xpos - xneg + ypos - yneg);
|
||||
}
|
||||
|
||||
for (int i = 1; i < Lstep.rows - 1; i++) {
|
||||
float xpos = ((*(c.ptr<float>(i))) + (*(c.ptr<float>(i)+1)))*((*(Ld.ptr<float>(i)+1)) - (*(Ld.ptr<float>(i))));
|
||||
float xneg = ((*(c.ptr<float>(i))) + (*(c.ptr<float>(i))))*((*(Ld.ptr<float>(i))) - (*(Ld.ptr<float>(i))));
|
||||
float ypos = ((*(c.ptr<float>(i))) + (*(c.ptr<float>(i + 1))))*((*(Ld.ptr<float>(i + 1))) - (*(Ld.ptr<float>(i))));
|
||||
float yneg = ((*(c.ptr<float>(i - 1))) + (*(c.ptr<float>(i))))*((*(Ld.ptr<float>(i))) - (*(Ld.ptr<float>(i - 1))));
|
||||
*(Lstep.ptr<float>(i)) = 0.5f*stepsize*(xpos - xneg + ypos - yneg);
|
||||
}
|
||||
|
||||
for (int i = 1; i < Lstep.rows - 1; i++) {
|
||||
float xneg = ((*(c.ptr<float>(i)+Lstep.cols - 2)) + (*(c.ptr<float>(i)+Lstep.cols - 1)))*((*(Ld.ptr<float>(i)+Lstep.cols - 1)) - (*(Ld.ptr<float>(i)+Lstep.cols - 2)));
|
||||
float ypos = ((*(c.ptr<float>(i)+Lstep.cols - 1)) + (*(c.ptr<float>(i + 1) + Lstep.cols - 1)))*((*(Ld.ptr<float>(i + 1) + Lstep.cols - 1)) - (*(Ld.ptr<float>(i)+Lstep.cols - 1)));
|
||||
float yneg = ((*(c.ptr<float>(i - 1) + Lstep.cols - 1)) + (*(c.ptr<float>(i)+Lstep.cols - 1)))*((*(Ld.ptr<float>(i)+Lstep.cols - 1)) - (*(Ld.ptr<float>(i - 1) + Lstep.cols - 1)));
|
||||
*(Lstep.ptr<float>(i)+Lstep.cols - 1) = 0.5f*stepsize*(-xneg + ypos - yneg);
|
||||
}
|
||||
|
||||
Ld = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((*(img.ptr<float>(i)+j)) > value) {
|
||||
response = false;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now find the perc of the histogram percentile
|
||||
nthreshold = (int)(npoints*perc);
|
||||
|
||||
for (k = 0; nelements < nthreshold && k < nbins; k++) {
|
||||
nelements = nelements + hist[k];
|
||||
}
|
||||
|
||||
if (nelements < nthreshold) {
|
||||
kperc = 0.03f;
|
||||
}
|
||||
else {
|
||||
kperc = hmax*((float)(k) / (float)nbins);
|
||||
}
|
||||
|
||||
return kperc;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @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) {
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
int ksize = 3 + 2 * (scale - 1);
|
||||
|
||||
// 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();
|
||||
std::vector<float> kerI;
|
||||
|
||||
float w = 10.0f / 3.0f;
|
||||
float norm = 1.0f / (2.0f*scale*(w + 2.0f));
|
||||
|
||||
for (int k = 0; k < 2; k++) {
|
||||
Mat* kernel = k == 0 ? &kx : &ky;
|
||||
int order = k == 0 ? dx : dy;
|
||||
kerI.assign(ksize, 0.0f);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_OVERRIDE
|
||||
{
|
||||
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_INSTRUMENT_REGION();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((*(img.ptr<float>(i)+j)) > value) {
|
||||
response = false;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,43 +11,37 @@
|
||||
#ifndef __OPENCV_FEATURES_2D_NLDIFFUSION_FUNCTIONS_H__
|
||||
#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(InputArray Lx, InputArray Ly, OutputArray dst, float k);
|
||||
void pm_g2(InputArray Lx, InputArray Ly, OutputArray dst, float k);
|
||||
void weickert_diffusivity(InputArray Lx, InputArray Ly, OutputArray dst, float k);
|
||||
void charbonnier_diffusivity(InputArray Lx, InputArray Ly, OutputArray 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 suppression
|
||||
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
|
||||
|
||||
@@ -1,31 +1,6 @@
|
||||
#ifndef __OPENCV_FEATURES_2D_KAZE_UTILS_H__
|
||||
#define __OPENCV_FEATURES_2D_KAZE_UTILS_H__
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @brief This function computes the angle from the vector given by (X Y). From 0 to 2*Pi
|
||||
*/
|
||||
inline float getAngle(float x, float y) {
|
||||
|
||||
if (x >= 0 && y >= 0) {
|
||||
return atanf(y / x);
|
||||
}
|
||||
|
||||
if (x < 0 && y >= 0) {
|
||||
return static_cast<float>(CV_PI)-atanf(-y / x);
|
||||
}
|
||||
|
||||
if (x < 0 && y < 0) {
|
||||
return static_cast<float>(CV_PI)+atanf(y / x);
|
||||
}
|
||||
|
||||
if (x >= 0 && y < 0) {
|
||||
return static_cast<float>(2.0 * CV_PI) - atanf(-y / x);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @brief This function computes the value of a 2D Gaussian function
|
||||
@@ -64,14 +39,4 @@ inline void checkDescriptorLimits(int &x, int &y, int width, int height) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* @brief This funtion rounds float to nearest integer
|
||||
* @param flt Input float
|
||||
* @return dst Nearest integer
|
||||
*/
|
||||
inline int fRound(float flt) {
|
||||
return (int)(flt + 0.5f);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -77,8 +77,8 @@ void KeyPointsFilter::retainBest(std::vector<KeyPoint>& keypoints, int n_points)
|
||||
return;
|
||||
}
|
||||
//first use nth element to partition the keypoints into the best and worst.
|
||||
std::nth_element(keypoints.begin(), keypoints.begin() + n_points, keypoints.end(), KeypointResponseGreater());
|
||||
//this is the boundary response, and in the case of FAST may be ambigous
|
||||
std::nth_element(keypoints.begin(), keypoints.begin() + n_points - 1, keypoints.end(), KeypointResponseGreater());
|
||||
//this is the boundary response, and in the case of FAST may be ambiguous
|
||||
float ambiguous_response = keypoints[n_points - 1].response;
|
||||
//use std::partition to grab all of the keypoints with the boundary response.
|
||||
std::vector<KeyPoint>::const_iterator new_end =
|
||||
@@ -156,6 +156,8 @@ private:
|
||||
|
||||
void KeyPointsFilter::runByPixelsMask( std::vector<KeyPoint>& keypoints, const Mat& mask )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
if( mask.empty() )
|
||||
return;
|
||||
|
||||
@@ -221,4 +223,44 @@ void KeyPointsFilter::removeDuplicated( std::vector<KeyPoint>& keypoints )
|
||||
keypoints.resize(j);
|
||||
}
|
||||
|
||||
struct KeyPoint12_LessThan
|
||||
{
|
||||
bool operator()(const KeyPoint &kp1, const KeyPoint &kp2) const
|
||||
{
|
||||
if( kp1.pt.x != kp2.pt.x )
|
||||
return kp1.pt.x < kp2.pt.x;
|
||||
if( kp1.pt.y != kp2.pt.y )
|
||||
return kp1.pt.y < kp2.pt.y;
|
||||
if( kp1.size != kp2.size )
|
||||
return kp1.size > kp2.size;
|
||||
if( kp1.angle != kp2.angle )
|
||||
return kp1.angle < kp2.angle;
|
||||
if( kp1.response != kp2.response )
|
||||
return kp1.response > kp2.response;
|
||||
if( kp1.octave != kp2.octave )
|
||||
return kp1.octave > kp2.octave;
|
||||
return kp1.class_id > kp2.class_id;
|
||||
}
|
||||
};
|
||||
|
||||
void KeyPointsFilter::removeDuplicatedSorted( std::vector<KeyPoint>& keypoints )
|
||||
{
|
||||
int i, j, n = (int)keypoints.size();
|
||||
|
||||
if (n < 2) return;
|
||||
|
||||
std::sort(keypoints.begin(), keypoints.end(), KeyPoint12_LessThan());
|
||||
|
||||
for( i = 0, j = 1; j < n; ++j )
|
||||
{
|
||||
const KeyPoint& kp1 = keypoints[i];
|
||||
const KeyPoint& kp2 = keypoints[j];
|
||||
if( kp1.pt.x != kp2.pt.x || kp1.pt.y != kp2.pt.y ||
|
||||
kp1.size != kp2.size || kp1.angle != kp2.angle ) {
|
||||
keypoints[++i] = keypoints[j];
|
||||
}
|
||||
}
|
||||
keypoints.resize(i + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*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.
|
||||
// Copyright (C) 2015, Itseez 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*/
|
||||
|
||||
//
|
||||
// Library initialization file
|
||||
//
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
IPP_INITIALIZER_AUTO
|
||||
|
||||
/* End of file. */
|
||||
+283
-729
File diff suppressed because it is too large
Load Diff
+824
-1015
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,122 @@
|
||||
// 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
|
||||
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
__kernel void
|
||||
AKAZE_pm_g2(__global const float* lx, __global const float* ly, __global float* dst,
|
||||
float k, int size)
|
||||
{
|
||||
int i = get_global_id(0);
|
||||
// OpenCV plays with dimensions so we need explicit check for this
|
||||
if (!(i < size))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const float k2inv = 1.0f / (k * k);
|
||||
dst[i] = 1.0f / (1.0f + ((lx[i] * lx[i] + ly[i] * ly[i]) * k2inv));
|
||||
}
|
||||
|
||||
__kernel void
|
||||
AKAZE_nld_step_scalar(__global const float* lt, int lt_step, int lt_offset, int rows, int cols,
|
||||
__global const float* lf, __global float* dst, float step_size)
|
||||
{
|
||||
/* The labeling scheme for this five star stencil:
|
||||
[ a ]
|
||||
[ -1 c +1 ]
|
||||
[ b ]
|
||||
*/
|
||||
// column-first indexing
|
||||
int i = get_global_id(1);
|
||||
int j = get_global_id(0);
|
||||
|
||||
// OpenCV plays with dimensions so we need explicit check for this
|
||||
if (!(i < rows && j < cols))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// get row indexes
|
||||
int a = (i - 1) * cols;
|
||||
int c = (i ) * cols;
|
||||
int b = (i + 1) * cols;
|
||||
// compute stencil
|
||||
float res = 0.0f;
|
||||
if (i == 0) // first rows
|
||||
{
|
||||
if (j == 0 || j == (cols - 1))
|
||||
{
|
||||
res = 0.0f;
|
||||
} else
|
||||
{
|
||||
res = (lf[c + j] + lf[c + j + 1])*(lt[c + j + 1] - lt[c + j]) +
|
||||
(lf[c + j] + lf[c + j - 1])*(lt[c + j - 1] - lt[c + j]) +
|
||||
(lf[c + j] + lf[b + j ])*(lt[b + j ] - lt[c + j]);
|
||||
}
|
||||
} else if (i == (rows - 1)) // last row
|
||||
{
|
||||
if (j == 0 || j == (cols - 1))
|
||||
{
|
||||
res = 0.0f;
|
||||
} else
|
||||
{
|
||||
res = (lf[c + j] + lf[c + j + 1])*(lt[c + j + 1] - lt[c + j]) +
|
||||
(lf[c + j] + lf[c + j - 1])*(lt[c + j - 1] - lt[c + j]) +
|
||||
(lf[c + j] + lf[a + j ])*(lt[a + j ] - lt[c + j]);
|
||||
}
|
||||
} else // inner rows
|
||||
{
|
||||
if (j == 0) // first column
|
||||
{
|
||||
res = (lf[c + 0] + lf[c + 1])*(lt[c + 1] - lt[c + 0]) +
|
||||
(lf[c + 0] + lf[b + 0])*(lt[b + 0] - lt[c + 0]) +
|
||||
(lf[c + 0] + lf[a + 0])*(lt[a + 0] - lt[c + 0]);
|
||||
} else if (j == (cols - 1)) // last column
|
||||
{
|
||||
res = (lf[c + j] + lf[c + j - 1])*(lt[c + j - 1] - lt[c + j]) +
|
||||
(lf[c + j] + lf[b + j ])*(lt[b + j ] - lt[c + j]) +
|
||||
(lf[c + j] + lf[a + j ])*(lt[a + j ] - lt[c + j]);
|
||||
} else // inner stencil
|
||||
{
|
||||
res = (lf[c + j] + lf[c + j + 1])*(lt[c + j + 1] - lt[c + j]) +
|
||||
(lf[c + j] + lf[c + j - 1])*(lt[c + j - 1] - lt[c + j]) +
|
||||
(lf[c + j] + lf[b + j ])*(lt[b + j ] - lt[c + j]) +
|
||||
(lf[c + j] + lf[a + j ])*(lt[a + j ] - lt[c + j]);
|
||||
}
|
||||
}
|
||||
|
||||
dst[c + j] = res * step_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compute determinant from hessians
|
||||
* @details Compute Ldet by (Lxx.mul(Lyy) - Lxy.mul(Lxy)) * sigma
|
||||
*
|
||||
* @param lxx spatial derivates
|
||||
* @param lxy spatial derivates
|
||||
* @param lyy spatial derivates
|
||||
* @param dst output determinant
|
||||
* @param sigma determinant will be scaled by this sigma
|
||||
*/
|
||||
__kernel void
|
||||
AKAZE_compute_determinant(__global const float* lxx, __global const float* lxy, __global const float* lyy,
|
||||
__global float* dst, float sigma, int size)
|
||||
{
|
||||
int i = get_global_id(0);
|
||||
// OpenCV plays with dimensions so we need explicit check for this
|
||||
if (!(i < size))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dst[i] = (lxx[i] * lyy[i] - lxy[i] * lxy[i]) * sigma;
|
||||
}
|
||||
@@ -59,39 +59,71 @@
|
||||
#define MAX_DESC_LEN 64
|
||||
#endif
|
||||
|
||||
#define BLOCK_SIZE_ODD (BLOCK_SIZE + 1)
|
||||
#ifndef SHARED_MEM_SZ
|
||||
# if (BLOCK_SIZE < MAX_DESC_LEN)
|
||||
# define SHARED_MEM_SZ (kercn * (BLOCK_SIZE * MAX_DESC_LEN + BLOCK_SIZE * BLOCK_SIZE))
|
||||
# else
|
||||
# define SHARED_MEM_SZ (kercn * 2 * BLOCK_SIZE_ODD * BLOCK_SIZE)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef DIST_TYPE
|
||||
#define DIST_TYPE 2
|
||||
#endif
|
||||
|
||||
// dirty fix for non-template support
|
||||
#if (DIST_TYPE == 2) // L1Dist
|
||||
#if (DIST_TYPE == 2) // L1Dist
|
||||
# ifdef T_FLOAT
|
||||
# define DIST(x, y) fabs((x) - (y))
|
||||
typedef float value_type;
|
||||
typedef float result_type;
|
||||
# if (8 == kercn)
|
||||
typedef float8 value_type;
|
||||
# define DIST(x, y) {value_type d = fabs((x) - (y)); result += d.s0 + d.s1 + d.s2 + d.s3 + d.s4 + d.s5 + d.s6 + d.s7;}
|
||||
# elif (4 == kercn)
|
||||
typedef float4 value_type;
|
||||
# define DIST(x, y) {value_type d = fabs((x) - (y)); result += d.s0 + d.s1 + d.s2 + d.s3;}
|
||||
# else
|
||||
typedef float value_type;
|
||||
# define DIST(x, y) result += fabs((x) - (y))
|
||||
# endif
|
||||
# else
|
||||
# define DIST(x, y) abs((x) - (y))
|
||||
typedef int value_type;
|
||||
typedef int result_type;
|
||||
# if (8 == kercn)
|
||||
typedef int8 value_type;
|
||||
# define DIST(x, y) {value_type d = abs((x) - (y)); result += d.s0 + d.s1 + d.s2 + d.s3 + d.s4 + d.s5 + d.s6 + d.s7;}
|
||||
# elif (4 == kercn)
|
||||
typedef int4 value_type;
|
||||
# define DIST(x, y) {value_type d = abs((x) - (y)); result += d.s0 + d.s1 + d.s2 + d.s3;}
|
||||
# else
|
||||
typedef int value_type;
|
||||
# define DIST(x, y) result += abs((x) - (y))
|
||||
# endif
|
||||
# endif
|
||||
#define DIST_RES(x) (x)
|
||||
# define DIST_RES(x) (x)
|
||||
#elif (DIST_TYPE == 4) // L2Dist
|
||||
#define DIST(x, y) (((x) - (y)) * ((x) - (y)))
|
||||
typedef float value_type;
|
||||
typedef float result_type;
|
||||
#define DIST_RES(x) sqrt(x)
|
||||
typedef float result_type;
|
||||
# if (8 == kercn)
|
||||
typedef float8 value_type;
|
||||
# define DIST(x, y) {value_type d = ((x) - (y)); result += dot(d.s0123, d.s0123) + dot(d.s4567, d.s4567);}
|
||||
# elif (4 == kercn)
|
||||
typedef float4 value_type;
|
||||
# define DIST(x, y) {value_type d = ((x) - (y)); result += dot(d, d);}
|
||||
# else
|
||||
typedef float value_type;
|
||||
# define DIST(x, y) {value_type d = ((x) - (y)); result = mad(d, d, result);}
|
||||
# endif
|
||||
# define DIST_RES(x) sqrt(x)
|
||||
#elif (DIST_TYPE == 6) // Hamming
|
||||
//http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
|
||||
inline int bit1Count(int v)
|
||||
{
|
||||
v = v - ((v >> 1) & 0x55555555); // reuse input as temporary
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp
|
||||
return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
|
||||
}
|
||||
#define DIST(x, y) bit1Count( (x) ^ (y) )
|
||||
typedef int value_type;
|
||||
typedef int result_type;
|
||||
#define DIST_RES(x) (x)
|
||||
# if (8 == kercn)
|
||||
typedef int8 value_type;
|
||||
# elif (4 == kercn)
|
||||
typedef int4 value_type;
|
||||
# else
|
||||
typedef int value_type;
|
||||
# endif
|
||||
typedef int result_type;
|
||||
# define DIST(x, y) result += popcount( (x) ^ (y) )
|
||||
# define DIST_RES(x) (x)
|
||||
#endif
|
||||
|
||||
inline result_type reduce_block(
|
||||
@@ -105,9 +137,7 @@ inline result_type reduce_block(
|
||||
#pragma unroll
|
||||
for (int j = 0 ; j < BLOCK_SIZE ; j++)
|
||||
{
|
||||
result += DIST(
|
||||
s_query[lidy * BLOCK_SIZE + j],
|
||||
s_train[j * BLOCK_SIZE + lidx]);
|
||||
DIST(s_query[lidy * BLOCK_SIZE_ODD + j], s_train[j * BLOCK_SIZE_ODD + lidx]);
|
||||
}
|
||||
return DIST_RES(result);
|
||||
}
|
||||
@@ -123,11 +153,9 @@ inline result_type reduce_block_match(
|
||||
#pragma unroll
|
||||
for (int j = 0 ; j < BLOCK_SIZE ; j++)
|
||||
{
|
||||
result += DIST(
|
||||
s_query[lidy * BLOCK_SIZE + j],
|
||||
s_train[j * BLOCK_SIZE + lidx]);
|
||||
DIST(s_query[lidy * BLOCK_SIZE_ODD + j], s_train[j * BLOCK_SIZE_ODD + lidx]);
|
||||
}
|
||||
return (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline result_type reduce_multi_block(
|
||||
@@ -142,23 +170,16 @@ inline result_type reduce_multi_block(
|
||||
#pragma unroll
|
||||
for (int j = 0 ; j < BLOCK_SIZE ; j++)
|
||||
{
|
||||
result += DIST(
|
||||
s_query[lidy * MAX_DESC_LEN + block_index * BLOCK_SIZE + j],
|
||||
s_train[j * BLOCK_SIZE + lidx]);
|
||||
DIST(s_query[lidy * MAX_DESC_LEN + block_index * BLOCK_SIZE + j], s_train[j * BLOCK_SIZE + lidx]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 2dim launch, global size: dim0 is (query rows + BLOCK_SIZE - 1) / BLOCK_SIZE * BLOCK_SIZE, dim1 is BLOCK_SIZE
|
||||
local size: dim0 is BLOCK_SIZE, dim1 is BLOCK_SIZE.
|
||||
*/
|
||||
__kernel void BruteForceMatch_UnrollMatch(
|
||||
__kernel void BruteForceMatch_Match(
|
||||
__global T *query,
|
||||
__global T *train,
|
||||
//__global float *mask,
|
||||
__global int *bestTrainIdx,
|
||||
__global float *bestDistance,
|
||||
__local float *sharebuffer,
|
||||
int query_rows,
|
||||
int query_cols,
|
||||
int train_rows,
|
||||
@@ -170,17 +191,28 @@ __kernel void BruteForceMatch_UnrollMatch(
|
||||
const int lidy = get_local_id(1);
|
||||
const int groupidx = get_group_id(0);
|
||||
|
||||
__local value_type *s_query = (__local value_type *)sharebuffer;
|
||||
__local value_type *s_train = (__local value_type *)sharebuffer + BLOCK_SIZE * MAX_DESC_LEN;
|
||||
const int queryIdx = mad24(BLOCK_SIZE, groupidx, lidy);
|
||||
const int queryOffset = min(queryIdx, query_rows - 1) * step;
|
||||
__global TN *query_vec = (__global TN *)(query + queryOffset);
|
||||
query_cols /= kercn;
|
||||
|
||||
int queryIdx = groupidx * BLOCK_SIZE + lidy;
|
||||
__local float sharebuffer[SHARED_MEM_SZ];
|
||||
__local value_type *s_query = (__local value_type *)sharebuffer;
|
||||
|
||||
#if 0 < MAX_DESC_LEN
|
||||
__local value_type *s_train = (__local value_type *)sharebuffer + BLOCK_SIZE * MAX_DESC_LEN;
|
||||
// load the query into local memory.
|
||||
#pragma unroll
|
||||
for (int i = 0 ; i < MAX_DESC_LEN / BLOCK_SIZE; i ++)
|
||||
for (int i = 0; i < MAX_DESC_LEN / BLOCK_SIZE; i++)
|
||||
{
|
||||
int loadx = lidx + i * BLOCK_SIZE;
|
||||
s_query[lidy * MAX_DESC_LEN + loadx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0;
|
||||
const int loadx = mad24(BLOCK_SIZE, i, lidx);
|
||||
s_query[mad24(MAX_DESC_LEN, lidy, loadx)] = loadx < query_cols ? query_vec[loadx] : 0;
|
||||
}
|
||||
#else
|
||||
__local value_type *s_train = (__local value_type *)sharebuffer + BLOCK_SIZE_ODD * BLOCK_SIZE;
|
||||
const int s_query_i = mad24(BLOCK_SIZE_ODD, lidy, lidx);
|
||||
const int s_train_i = mad24(BLOCK_SIZE_ODD, lidx, lidy);
|
||||
#endif
|
||||
|
||||
float myBestDistance = MAX_FLOAT;
|
||||
int myBestTrainIdx = -1;
|
||||
@@ -189,12 +221,16 @@ __kernel void BruteForceMatch_UnrollMatch(
|
||||
for (int t = 0, endt = (train_rows + BLOCK_SIZE - 1) / BLOCK_SIZE; t < endt; t++)
|
||||
{
|
||||
result_type result = 0;
|
||||
|
||||
const int trainOffset = min(mad24(BLOCK_SIZE, t, lidy), train_rows - 1) * step;
|
||||
__global TN *train_vec = (__global TN *)(train + trainOffset);
|
||||
#if 0 < MAX_DESC_LEN
|
||||
#pragma unroll
|
||||
for (int i = 0 ; i < MAX_DESC_LEN / BLOCK_SIZE ; i++)
|
||||
for (int i = 0; i < MAX_DESC_LEN / BLOCK_SIZE; i++)
|
||||
{
|
||||
//load a BLOCK_SIZE * BLOCK_SIZE block into local train.
|
||||
const int loadx = lidx + i * BLOCK_SIZE;
|
||||
s_train[lidx * BLOCK_SIZE + lidy] = loadx < train_cols ? train[min(t * BLOCK_SIZE + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0;
|
||||
const int loadx = mad24(BLOCK_SIZE, i, lidx);
|
||||
s_train[mad24(BLOCK_SIZE, lidx, lidy)] = loadx < train_cols ? train_vec[loadx] : 0;
|
||||
|
||||
//synchronize to make sure each elem for reduceIteration in share memory is written already.
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
@@ -203,89 +239,20 @@ __kernel void BruteForceMatch_UnrollMatch(
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
}
|
||||
|
||||
result = DIST_RES(result);
|
||||
|
||||
int trainIdx = t * BLOCK_SIZE + lidx;
|
||||
|
||||
if (queryIdx < query_rows && trainIdx < train_rows && result < myBestDistance/* && mask(queryIdx, trainIdx)*/)
|
||||
#else
|
||||
for (int i = 0, endq = (query_cols + BLOCK_SIZE - 1) / BLOCK_SIZE; i < endq; i++)
|
||||
{
|
||||
myBestDistance = result;
|
||||
myBestTrainIdx = trainIdx;
|
||||
}
|
||||
}
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
__local float *s_distance = (__local float*)(sharebuffer);
|
||||
__local int* s_trainIdx = (__local int *)(sharebuffer + BLOCK_SIZE * BLOCK_SIZE);
|
||||
|
||||
//find BestMatch
|
||||
s_distance += lidy * BLOCK_SIZE;
|
||||
s_trainIdx += lidy * BLOCK_SIZE;
|
||||
s_distance[lidx] = myBestDistance;
|
||||
s_trainIdx[lidx] = myBestTrainIdx;
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
//reduce -- now all reduce implement in each threads.
|
||||
#pragma unroll
|
||||
for (int k = 0 ; k < BLOCK_SIZE; k++)
|
||||
{
|
||||
if (myBestDistance > s_distance[k])
|
||||
{
|
||||
myBestDistance = s_distance[k];
|
||||
myBestTrainIdx = s_trainIdx[k];
|
||||
}
|
||||
}
|
||||
|
||||
if (queryIdx < query_rows && lidx == 0)
|
||||
{
|
||||
bestTrainIdx[queryIdx] = myBestTrainIdx;
|
||||
bestDistance[queryIdx] = myBestDistance;
|
||||
}
|
||||
}
|
||||
|
||||
__kernel void BruteForceMatch_Match(
|
||||
__global T *query,
|
||||
__global T *train,
|
||||
//__global float *mask,
|
||||
__global int *bestTrainIdx,
|
||||
__global float *bestDistance,
|
||||
__local float *sharebuffer,
|
||||
int query_rows,
|
||||
int query_cols,
|
||||
int train_rows,
|
||||
int train_cols,
|
||||
int step
|
||||
)
|
||||
{
|
||||
const int lidx = get_local_id(0);
|
||||
const int lidy = get_local_id(1);
|
||||
const int groupidx = get_group_id(0);
|
||||
|
||||
const int queryIdx = groupidx * BLOCK_SIZE + lidy;
|
||||
|
||||
float myBestDistance = MAX_FLOAT;
|
||||
int myBestTrainIdx = -1;
|
||||
|
||||
__local value_type *s_query = (__local value_type *)sharebuffer;
|
||||
__local value_type *s_train = (__local value_type *)sharebuffer + BLOCK_SIZE * BLOCK_SIZE;
|
||||
|
||||
// loop
|
||||
for (int t = 0 ; t < (train_rows + BLOCK_SIZE - 1) / BLOCK_SIZE ; t++)
|
||||
{
|
||||
result_type result = 0;
|
||||
for (int i = 0 ; i < (query_cols + BLOCK_SIZE - 1) / BLOCK_SIZE ; i++)
|
||||
{
|
||||
const int loadx = lidx + i * BLOCK_SIZE;
|
||||
const int loadx = mad24(i, BLOCK_SIZE, lidx);
|
||||
//load query and train into local memory
|
||||
s_query[lidy * BLOCK_SIZE + lidx] = 0;
|
||||
s_train[lidx * BLOCK_SIZE + lidy] = 0;
|
||||
|
||||
if (loadx < query_cols)
|
||||
{
|
||||
s_query[lidy * BLOCK_SIZE + lidx] = query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx];
|
||||
s_train[lidx * BLOCK_SIZE + lidy] = train[min(t * BLOCK_SIZE + lidy, train_rows - 1) * (step / sizeof(float)) + loadx];
|
||||
s_query[s_query_i] = query_vec[loadx];
|
||||
s_train[s_train_i] = train_vec[loadx];
|
||||
}
|
||||
else
|
||||
{
|
||||
s_query[s_query_i] = 0;
|
||||
s_train[s_train_i] = 0;
|
||||
}
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
@@ -294,10 +261,10 @@ __kernel void BruteForceMatch_Match(
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
}
|
||||
|
||||
#endif
|
||||
result = DIST_RES(result);
|
||||
|
||||
const int trainIdx = t * BLOCK_SIZE + lidx;
|
||||
const int trainIdx = mad24(BLOCK_SIZE, t, lidx);
|
||||
|
||||
if (queryIdx < query_rows && trainIdx < train_rows && result < myBestDistance /*&& mask(queryIdx, trainIdx)*/)
|
||||
{
|
||||
@@ -309,17 +276,18 @@ __kernel void BruteForceMatch_Match(
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
__local float *s_distance = (__local float *)sharebuffer;
|
||||
__local int *s_trainIdx = (__local int *)(sharebuffer + BLOCK_SIZE * BLOCK_SIZE);
|
||||
__local int *s_trainIdx = (__local int *)(sharebuffer + BLOCK_SIZE_ODD * BLOCK_SIZE);
|
||||
|
||||
//findBestMatch
|
||||
s_distance += lidy * BLOCK_SIZE;
|
||||
s_trainIdx += lidy * BLOCK_SIZE;
|
||||
s_distance += lidy * BLOCK_SIZE_ODD;
|
||||
s_trainIdx += lidy * BLOCK_SIZE_ODD;
|
||||
s_distance[lidx] = myBestDistance;
|
||||
s_trainIdx[lidx] = myBestTrainIdx;
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
//reduce -- now all reduce implement in each threads.
|
||||
#pragma unroll
|
||||
for (int k = 0 ; k < BLOCK_SIZE; k++)
|
||||
{
|
||||
if (myBestDistance > s_distance[k])
|
||||
@@ -336,76 +304,14 @@ __kernel void BruteForceMatch_Match(
|
||||
}
|
||||
}
|
||||
|
||||
//radius_unrollmatch
|
||||
__kernel void BruteForceMatch_RadiusUnrollMatch(
|
||||
__global T *query,
|
||||
__global T *train,
|
||||
float maxDistance,
|
||||
//__global float *mask,
|
||||
__global int *bestTrainIdx,
|
||||
__global float *bestDistance,
|
||||
__global int *nMatches,
|
||||
__local float *sharebuffer,
|
||||
int query_rows,
|
||||
int query_cols,
|
||||
int train_rows,
|
||||
int train_cols,
|
||||
int bestTrainIdx_cols,
|
||||
int step,
|
||||
int ostep
|
||||
)
|
||||
{
|
||||
const int lidx = get_local_id(0);
|
||||
const int lidy = get_local_id(1);
|
||||
const int groupidx = get_group_id(0);
|
||||
const int groupidy = get_group_id(1);
|
||||
|
||||
const int queryIdx = groupidy * BLOCK_SIZE + lidy;
|
||||
const int trainIdx = groupidx * BLOCK_SIZE + lidx;
|
||||
|
||||
__local value_type *s_query = (__local value_type *)sharebuffer;
|
||||
__local value_type *s_train = (__local value_type *)sharebuffer + BLOCK_SIZE * BLOCK_SIZE;
|
||||
|
||||
result_type result = 0;
|
||||
for (int i = 0 ; i < MAX_DESC_LEN / BLOCK_SIZE ; ++i)
|
||||
{
|
||||
//load a BLOCK_SIZE * BLOCK_SIZE block into local train.
|
||||
const int loadx = lidx + i * BLOCK_SIZE;
|
||||
|
||||
s_query[lidy * BLOCK_SIZE + lidx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0;
|
||||
s_train[lidx * BLOCK_SIZE + lidy] = loadx < query_cols ? train[min(groupidx * BLOCK_SIZE + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0;
|
||||
|
||||
//synchronize to make sure each elem for reduceIteration in share memory is written already.
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
result += reduce_block(s_query, s_train, lidx, lidy);
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
}
|
||||
|
||||
if (queryIdx < query_rows && trainIdx < train_rows &&
|
||||
convert_float(result) < maxDistance/* && mask(queryIdx, trainIdx)*/)
|
||||
{
|
||||
int ind = atom_inc(nMatches + queryIdx/*, (unsigned int) -1*/);
|
||||
|
||||
if(ind < bestTrainIdx_cols)
|
||||
{
|
||||
bestTrainIdx[queryIdx * (ostep / sizeof(int)) + ind] = trainIdx;
|
||||
bestDistance[queryIdx * (ostep / sizeof(float)) + ind] = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//radius_match
|
||||
__kernel void BruteForceMatch_RadiusMatch(
|
||||
__global T *query,
|
||||
__global T *train,
|
||||
float maxDistance,
|
||||
//__global float *mask,
|
||||
__global int *bestTrainIdx,
|
||||
__global float *bestDistance,
|
||||
__global int *nMatches,
|
||||
__local float *sharebuffer,
|
||||
int query_rows,
|
||||
int query_cols,
|
||||
int train_rows,
|
||||
@@ -420,20 +326,38 @@ __kernel void BruteForceMatch_RadiusMatch(
|
||||
const int groupidx = get_group_id(0);
|
||||
const int groupidy = get_group_id(1);
|
||||
|
||||
const int queryIdx = groupidy * BLOCK_SIZE + lidy;
|
||||
const int trainIdx = groupidx * BLOCK_SIZE + lidx;
|
||||
const int queryIdx = mad24(BLOCK_SIZE, groupidy, lidy);
|
||||
const int queryOffset = min(queryIdx, query_rows - 1) * step;
|
||||
__global TN *query_vec = (__global TN *)(query + queryOffset);
|
||||
|
||||
const int trainIdx = mad24(BLOCK_SIZE, groupidx, lidx);
|
||||
const int trainOffset = min(mad24(BLOCK_SIZE, groupidx, lidy), train_rows - 1) * step;
|
||||
__global TN *train_vec = (__global TN *)(train + trainOffset);
|
||||
|
||||
query_cols /= kercn;
|
||||
|
||||
__local float sharebuffer[SHARED_MEM_SZ];
|
||||
__local value_type *s_query = (__local value_type *)sharebuffer;
|
||||
__local value_type *s_train = (__local value_type *)sharebuffer + BLOCK_SIZE * BLOCK_SIZE;
|
||||
__local value_type *s_train = (__local value_type *)sharebuffer + BLOCK_SIZE_ODD * BLOCK_SIZE;
|
||||
|
||||
result_type result = 0;
|
||||
const int s_query_i = mad24(BLOCK_SIZE_ODD, lidy, lidx);
|
||||
const int s_train_i = mad24(BLOCK_SIZE_ODD, lidx, lidy);
|
||||
for (int i = 0 ; i < (query_cols + BLOCK_SIZE - 1) / BLOCK_SIZE ; ++i)
|
||||
{
|
||||
//load a BLOCK_SIZE * BLOCK_SIZE block into local train.
|
||||
const int loadx = lidx + i * BLOCK_SIZE;
|
||||
const int loadx = mad24(BLOCK_SIZE, i, lidx);
|
||||
|
||||
s_query[lidy * BLOCK_SIZE + lidx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0;
|
||||
s_train[lidx * BLOCK_SIZE + lidy] = loadx < query_cols ? train[min(groupidx * BLOCK_SIZE + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0;
|
||||
if (loadx < query_cols)
|
||||
{
|
||||
s_query[s_query_i] = query_vec[loadx];
|
||||
s_train[s_train_i] = train_vec[loadx];
|
||||
}
|
||||
else
|
||||
{
|
||||
s_query[s_query_i] = 0;
|
||||
s_train[s_train_i] = 0;
|
||||
}
|
||||
|
||||
//synchronize to make sure each elem for reduceIteration in share memory is written already.
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
@@ -442,28 +366,23 @@ __kernel void BruteForceMatch_RadiusMatch(
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
}
|
||||
|
||||
if (queryIdx < query_rows && trainIdx < train_rows &&
|
||||
convert_float(result) < maxDistance/* && mask(queryIdx, trainIdx)*/)
|
||||
if (queryIdx < query_rows && trainIdx < train_rows && convert_float(result) < maxDistance)
|
||||
{
|
||||
int ind = atom_inc(nMatches + queryIdx);
|
||||
|
||||
if(ind < bestTrainIdx_cols)
|
||||
{
|
||||
bestTrainIdx[queryIdx * (ostep / sizeof(int)) + ind] = trainIdx;
|
||||
bestDistance[queryIdx * (ostep / sizeof(float)) + ind] = result;
|
||||
bestTrainIdx[mad24(queryIdx, ostep, ind)] = trainIdx;
|
||||
bestDistance[mad24(queryIdx, ostep, ind)] = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__kernel void BruteForceMatch_knnUnrollMatch(
|
||||
__kernel void BruteForceMatch_knnMatch(
|
||||
__global T *query,
|
||||
__global T *train,
|
||||
//__global float *mask,
|
||||
__global int2 *bestTrainIdx,
|
||||
__global float2 *bestDistance,
|
||||
__local float *sharebuffer,
|
||||
int query_rows,
|
||||
int query_cols,
|
||||
int train_rows,
|
||||
@@ -475,31 +394,47 @@ __kernel void BruteForceMatch_knnUnrollMatch(
|
||||
const int lidy = get_local_id(1);
|
||||
const int groupidx = get_group_id(0);
|
||||
|
||||
const int queryIdx = groupidx * BLOCK_SIZE + lidy;
|
||||
__local value_type *s_query = (__local value_type *)sharebuffer;
|
||||
__local value_type *s_train = (__local value_type *)sharebuffer + BLOCK_SIZE * MAX_DESC_LEN;
|
||||
const int queryIdx = mad24(BLOCK_SIZE, groupidx, lidy);
|
||||
const int queryOffset = min(queryIdx, query_rows - 1) * step;
|
||||
__global TN *query_vec = (__global TN *)(query + queryOffset);
|
||||
query_cols /= kercn;
|
||||
|
||||
__local float sharebuffer[SHARED_MEM_SZ];
|
||||
__local value_type *s_query = (__local value_type *)sharebuffer;
|
||||
|
||||
#if 0 < MAX_DESC_LEN
|
||||
__local value_type *s_train = (__local value_type *)sharebuffer + BLOCK_SIZE * MAX_DESC_LEN;
|
||||
// load the query into local memory.
|
||||
#pragma unroll
|
||||
for (int i = 0 ; i < MAX_DESC_LEN / BLOCK_SIZE; i ++)
|
||||
{
|
||||
int loadx = lidx + i * BLOCK_SIZE;
|
||||
s_query[lidy * MAX_DESC_LEN + loadx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0;
|
||||
int loadx = mad24(BLOCK_SIZE, i, lidx);
|
||||
s_query[mad24(MAX_DESC_LEN, lidy, loadx)] = loadx < query_cols ? query_vec[loadx] : 0;
|
||||
}
|
||||
#else
|
||||
__local value_type *s_train = (__local value_type *)sharebuffer + BLOCK_SIZE_ODD * BLOCK_SIZE;
|
||||
const int s_query_i = mad24(BLOCK_SIZE_ODD, lidy, lidx);
|
||||
const int s_train_i = mad24(BLOCK_SIZE_ODD, lidx, lidy);
|
||||
#endif
|
||||
|
||||
float myBestDistance1 = MAX_FLOAT;
|
||||
float myBestDistance2 = MAX_FLOAT;
|
||||
int myBestTrainIdx1 = -1;
|
||||
int myBestTrainIdx2 = -1;
|
||||
|
||||
//loopUnrolledCached
|
||||
for (int t = 0 ; t < (train_rows + BLOCK_SIZE - 1) / BLOCK_SIZE ; t++)
|
||||
for (int t = 0, endt = (train_rows + BLOCK_SIZE - 1) / BLOCK_SIZE; t < endt ; t++)
|
||||
{
|
||||
result_type result = 0;
|
||||
|
||||
int trainOffset = min(mad24(BLOCK_SIZE, t, lidy), train_rows - 1) * step;
|
||||
__global TN *train_vec = (__global TN *)(train + trainOffset);
|
||||
#if 0 < MAX_DESC_LEN
|
||||
#pragma unroll
|
||||
for (int i = 0 ; i < MAX_DESC_LEN / BLOCK_SIZE ; i++)
|
||||
{
|
||||
//load a BLOCK_SIZE * BLOCK_SIZE block into local train.
|
||||
const int loadx = lidx + i * BLOCK_SIZE;
|
||||
s_train[lidx * BLOCK_SIZE + lidy] = loadx < train_cols ? train[min(t * BLOCK_SIZE + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0;
|
||||
const int loadx = mad24(BLOCK_SIZE, i, lidx);
|
||||
s_train[mad24(BLOCK_SIZE, lidx, lidy)] = loadx < train_cols ? train_vec[loadx] : 0;
|
||||
|
||||
//synchronize to make sure each elem for reduceIteration in share memory is written already.
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
@@ -508,10 +443,32 @@ __kernel void BruteForceMatch_knnUnrollMatch(
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
}
|
||||
#else
|
||||
for (int i = 0, endq = (query_cols + BLOCK_SIZE -1) / BLOCK_SIZE; i < endq ; i++)
|
||||
{
|
||||
const int loadx = mad24(BLOCK_SIZE, i, lidx);
|
||||
//load query and train into local memory
|
||||
if (loadx < query_cols)
|
||||
{
|
||||
s_query[s_query_i] = query_vec[loadx];
|
||||
s_train[s_train_i] = train_vec[loadx];
|
||||
}
|
||||
else
|
||||
{
|
||||
s_query[s_query_i] = 0;
|
||||
s_train[s_train_i] = 0;
|
||||
}
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
result += reduce_block_match(s_query, s_train, lidx, lidy);
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
}
|
||||
#endif
|
||||
result = DIST_RES(result);
|
||||
|
||||
const int trainIdx = t * BLOCK_SIZE + lidx;
|
||||
const int trainIdx = mad24(BLOCK_SIZE, t, lidx);
|
||||
|
||||
if (queryIdx < query_rows && trainIdx < train_rows)
|
||||
{
|
||||
@@ -532,13 +489,12 @@ __kernel void BruteForceMatch_knnUnrollMatch(
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
__local float *s_distance = (local float *)sharebuffer;
|
||||
__local int *s_trainIdx = (local int *)(sharebuffer + BLOCK_SIZE * BLOCK_SIZE);
|
||||
__local float *s_distance = (__local float *)sharebuffer;
|
||||
__local int *s_trainIdx = (__local int *)(sharebuffer + BLOCK_SIZE_ODD * BLOCK_SIZE);
|
||||
|
||||
// find BestMatch
|
||||
s_distance += lidy * BLOCK_SIZE;
|
||||
s_trainIdx += lidy * BLOCK_SIZE;
|
||||
|
||||
s_distance += lidy * BLOCK_SIZE_ODD;
|
||||
s_trainIdx += lidy * BLOCK_SIZE_ODD;
|
||||
s_distance[lidx] = myBestDistance1;
|
||||
s_trainIdx[lidx] = myBestTrainIdx1;
|
||||
|
||||
@@ -601,189 +557,4 @@ __kernel void BruteForceMatch_knnUnrollMatch(
|
||||
bestTrainIdx[queryIdx] = (int2)(myBestTrainIdx1, myBestTrainIdx2);
|
||||
bestDistance[queryIdx] = (float2)(myBestDistance1, myBestDistance2);
|
||||
}
|
||||
}
|
||||
|
||||
__kernel void BruteForceMatch_knnMatch(
|
||||
__global T *query,
|
||||
__global T *train,
|
||||
//__global float *mask,
|
||||
__global int2 *bestTrainIdx,
|
||||
__global float2 *bestDistance,
|
||||
__local float *sharebuffer,
|
||||
int query_rows,
|
||||
int query_cols,
|
||||
int train_rows,
|
||||
int train_cols,
|
||||
int step
|
||||
)
|
||||
{
|
||||
const int lidx = get_local_id(0);
|
||||
const int lidy = get_local_id(1);
|
||||
const int groupidx = get_group_id(0);
|
||||
|
||||
const int queryIdx = groupidx * BLOCK_SIZE + lidy;
|
||||
__local value_type *s_query = (__local value_type *)sharebuffer;
|
||||
__local value_type *s_train = (__local value_type *)sharebuffer + BLOCK_SIZE * BLOCK_SIZE;
|
||||
|
||||
float myBestDistance1 = MAX_FLOAT;
|
||||
float myBestDistance2 = MAX_FLOAT;
|
||||
int myBestTrainIdx1 = -1;
|
||||
int myBestTrainIdx2 = -1;
|
||||
|
||||
//loop
|
||||
for (int t = 0 ; t < (train_rows + BLOCK_SIZE - 1) / BLOCK_SIZE ; t++)
|
||||
{
|
||||
result_type result = 0.0f;
|
||||
for (int i = 0 ; i < (query_cols + BLOCK_SIZE -1) / BLOCK_SIZE ; i++)
|
||||
{
|
||||
const int loadx = lidx + i * BLOCK_SIZE;
|
||||
//load query and train into local memory
|
||||
s_query[lidy * BLOCK_SIZE + lidx] = 0;
|
||||
s_train[lidx * BLOCK_SIZE + lidy] = 0;
|
||||
|
||||
if (loadx < query_cols)
|
||||
{
|
||||
s_query[lidy * BLOCK_SIZE + lidx] = query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx];
|
||||
s_train[lidx * BLOCK_SIZE + lidy] = train[min(t * BLOCK_SIZE + lidy, train_rows - 1) * (step / sizeof(float)) + loadx];
|
||||
}
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
result += reduce_block_match(s_query, s_train, lidx, lidy);
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
}
|
||||
|
||||
result = DIST_RES(result);
|
||||
|
||||
const int trainIdx = t * BLOCK_SIZE + lidx;
|
||||
|
||||
if (queryIdx < query_rows && trainIdx < train_rows /*&& mask(queryIdx, trainIdx)*/)
|
||||
{
|
||||
if (result < myBestDistance1)
|
||||
{
|
||||
myBestDistance2 = myBestDistance1;
|
||||
myBestTrainIdx2 = myBestTrainIdx1;
|
||||
myBestDistance1 = result;
|
||||
myBestTrainIdx1 = trainIdx;
|
||||
}
|
||||
else if (result < myBestDistance2)
|
||||
{
|
||||
myBestDistance2 = result;
|
||||
myBestTrainIdx2 = trainIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
__local float *s_distance = (__local float *)sharebuffer;
|
||||
__local int *s_trainIdx = (__local int *)(sharebuffer + BLOCK_SIZE * BLOCK_SIZE);
|
||||
|
||||
//findBestMatch
|
||||
s_distance += lidy * BLOCK_SIZE;
|
||||
s_trainIdx += lidy * BLOCK_SIZE;
|
||||
|
||||
s_distance[lidx] = myBestDistance1;
|
||||
s_trainIdx[lidx] = myBestTrainIdx1;
|
||||
|
||||
float bestDistance1 = MAX_FLOAT;
|
||||
float bestDistance2 = MAX_FLOAT;
|
||||
int bestTrainIdx1 = -1;
|
||||
int bestTrainIdx2 = -1;
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
if (lidx == 0)
|
||||
{
|
||||
for (int i = 0 ; i < BLOCK_SIZE ; i++)
|
||||
{
|
||||
float val = s_distance[i];
|
||||
if (val < bestDistance1)
|
||||
{
|
||||
bestDistance2 = bestDistance1;
|
||||
bestTrainIdx2 = bestTrainIdx1;
|
||||
|
||||
bestDistance1 = val;
|
||||
bestTrainIdx1 = s_trainIdx[i];
|
||||
}
|
||||
else if (val < bestDistance2)
|
||||
{
|
||||
bestDistance2 = val;
|
||||
bestTrainIdx2 = s_trainIdx[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
s_distance[lidx] = myBestDistance2;
|
||||
s_trainIdx[lidx] = myBestTrainIdx2;
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
if (lidx == 0)
|
||||
{
|
||||
for (int i = 0 ; i < BLOCK_SIZE ; i++)
|
||||
{
|
||||
float val = s_distance[i];
|
||||
|
||||
if (val < bestDistance2)
|
||||
{
|
||||
bestDistance2 = val;
|
||||
bestTrainIdx2 = s_trainIdx[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myBestDistance1 = bestDistance1;
|
||||
myBestDistance2 = bestDistance2;
|
||||
|
||||
myBestTrainIdx1 = bestTrainIdx1;
|
||||
myBestTrainIdx2 = bestTrainIdx2;
|
||||
|
||||
if (queryIdx < query_rows && lidx == 0)
|
||||
{
|
||||
bestTrainIdx[queryIdx] = (int2)(myBestTrainIdx1, myBestTrainIdx2);
|
||||
bestDistance[queryIdx] = (float2)(myBestDistance1, myBestDistance2);
|
||||
}
|
||||
}
|
||||
|
||||
kernel void BruteForceMatch_calcDistanceUnrolled(
|
||||
__global T *query,
|
||||
__global T *train,
|
||||
//__global float *mask,
|
||||
__global float *allDist,
|
||||
__local float *sharebuffer,
|
||||
int query_rows,
|
||||
int query_cols,
|
||||
int train_rows,
|
||||
int train_cols,
|
||||
int step)
|
||||
{
|
||||
/* Todo */
|
||||
}
|
||||
|
||||
kernel void BruteForceMatch_calcDistance(
|
||||
__global T *query,
|
||||
__global T *train,
|
||||
//__global float *mask,
|
||||
__global float *allDist,
|
||||
__local float *sharebuffer,
|
||||
int query_rows,
|
||||
int query_cols,
|
||||
int train_rows,
|
||||
int train_cols,
|
||||
int step)
|
||||
{
|
||||
/* Todo */
|
||||
}
|
||||
|
||||
kernel void BruteForceMatch_findBestMatch(
|
||||
__global float *allDist,
|
||||
__global int *bestTrainIdx,
|
||||
__global float *bestDistance,
|
||||
int k
|
||||
)
|
||||
{
|
||||
/* Todo */
|
||||
}
|
||||
}
|
||||
@@ -148,8 +148,8 @@ ORB_computeDescriptor(__global const uchar* imgbuf, int imgstep, int imgoffset0,
|
||||
float angle = as_float(kpt[KEYPOINT_ANGLE]);
|
||||
angle *= 0.01745329251994329547f;
|
||||
|
||||
float sina = sin(angle);
|
||||
float cosa = cos(angle);
|
||||
float cosa;
|
||||
float sina = sincos(angle, &cosa);
|
||||
|
||||
__global uchar* desc = _desc + idx*dsize;
|
||||
|
||||
@@ -207,7 +207,7 @@ ORB_computeDescriptor(__global const uchar* imgbuf, int imgstep, int imgoffset0,
|
||||
pattern += 12*2;
|
||||
|
||||
#elif WTA_K == 4
|
||||
int t0, t1, t2, t3, k, val;
|
||||
int t0, t1, t2, t3, k;
|
||||
int a, b;
|
||||
|
||||
t0 = GET_VALUE(0); t1 = GET_VALUE(1);
|
||||
|
||||
+154
-64
@@ -38,6 +38,10 @@
|
||||
#include "opencl_kernels_features2d.hpp"
|
||||
#include <iterator>
|
||||
|
||||
#ifndef CV_IMPL_ADD
|
||||
#define CV_IMPL_ADD(x)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cv
|
||||
@@ -49,9 +53,11 @@ template<typename _Tp> inline void copyVectorToUMat(const std::vector<_Tp>& v, O
|
||||
{
|
||||
if(v.empty())
|
||||
um.release();
|
||||
Mat(1, (int)(v.size()*sizeof(v[0])), CV_8U, (void*)&v[0]).copyTo(um);
|
||||
else
|
||||
Mat(1, (int)(v.size()*sizeof(v[0])), CV_8U, (void*)&v[0]).copyTo(um);
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
static bool
|
||||
ocl_HarrisResponses(const UMat& imgbuf,
|
||||
const UMat& layerinfo,
|
||||
@@ -59,7 +65,7 @@ ocl_HarrisResponses(const UMat& imgbuf,
|
||||
UMat& responses,
|
||||
int nkeypoints, int blockSize, float harris_k)
|
||||
{
|
||||
size_t globalSize[] = {nkeypoints};
|
||||
size_t globalSize[] = {(size_t)nkeypoints};
|
||||
|
||||
float scale = 1.f/((1 << 2) * blockSize * 255.f);
|
||||
float scale_sq_sq = scale * scale * scale * scale;
|
||||
@@ -81,7 +87,7 @@ ocl_ICAngles(const UMat& imgbuf, const UMat& layerinfo,
|
||||
const UMat& keypoints, UMat& responses,
|
||||
const UMat& umax, int nkeypoints, int half_k)
|
||||
{
|
||||
size_t globalSize[] = {nkeypoints};
|
||||
size_t globalSize[] = {(size_t)nkeypoints};
|
||||
|
||||
ocl::Kernel icangle_ker("ORB_ICAngle", ocl::features2d::orb_oclsrc, "-D ORB_ANGLES");
|
||||
if( icangle_ker.empty() )
|
||||
@@ -99,12 +105,12 @@ ocl_ICAngles(const UMat& imgbuf, const UMat& layerinfo,
|
||||
static bool
|
||||
ocl_computeOrbDescriptors(const UMat& imgbuf, const UMat& layerInfo,
|
||||
const UMat& keypoints, UMat& desc, const UMat& pattern,
|
||||
int nkeypoints, int dsize, int WTA_K)
|
||||
int nkeypoints, int dsize, int wta_k)
|
||||
{
|
||||
size_t globalSize[] = {nkeypoints};
|
||||
size_t globalSize[] = {(size_t)nkeypoints};
|
||||
|
||||
ocl::Kernel desc_ker("ORB_computeDescriptor", ocl::features2d::orb_oclsrc,
|
||||
format("-D ORB_DESCRIPTORS -D WTA_K=%d", WTA_K));
|
||||
format("-D ORB_DESCRIPTORS -D WTA_K=%d", wta_k));
|
||||
if( desc_ker.empty() )
|
||||
return false;
|
||||
|
||||
@@ -115,7 +121,7 @@ ocl_computeOrbDescriptors(const UMat& imgbuf, const UMat& layerInfo,
|
||||
ocl::KernelArg::PtrReadOnly(pattern),
|
||||
nkeypoints, dsize).run(1, globalSize, 0, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Function that computes the Harris responses in a
|
||||
@@ -137,7 +143,7 @@ HarrisResponses(const Mat& img, const std::vector<Rect>& layerinfo,
|
||||
float scale_sq_sq = scale * scale * scale * scale;
|
||||
|
||||
AutoBuffer<int> ofsbuf(blockSize*blockSize);
|
||||
int* ofs = ofsbuf;
|
||||
int* ofs = ofsbuf.data();
|
||||
for( int i = 0; i < blockSize; i++ )
|
||||
for( int j = 0; j < blockSize; j++ )
|
||||
ofs[i*blockSize + j] = (int)(i*step + j);
|
||||
@@ -208,7 +214,7 @@ static void ICAngles(const Mat& img, const std::vector<Rect>& layerinfo,
|
||||
static void
|
||||
computeOrbDescriptors( const Mat& imagePyramid, const std::vector<Rect>& layerInfo,
|
||||
const std::vector<float>& layerScale, std::vector<KeyPoint>& keypoints,
|
||||
Mat& descriptors, const std::vector<Point>& _pattern, int dsize, int WTA_K )
|
||||
Mat& descriptors, const std::vector<Point>& _pattern, int dsize, int wta_k )
|
||||
{
|
||||
int step = (int)imagePyramid.step;
|
||||
int j, i, nkeypoints = (int)keypoints.size();
|
||||
@@ -247,7 +253,7 @@ computeOrbDescriptors( const Mat& imagePyramid, const std::vector<Rect>& layerIn
|
||||
center[iy*step + ix+1]*x*(1-y) + center[(iy+1)*step + ix+1]*x*y))
|
||||
#endif
|
||||
|
||||
if( WTA_K == 2 )
|
||||
if( wta_k == 2 )
|
||||
{
|
||||
for (i = 0; i < dsize; ++i, pattern += 16)
|
||||
{
|
||||
@@ -272,7 +278,7 @@ computeOrbDescriptors( const Mat& imagePyramid, const std::vector<Rect>& layerIn
|
||||
desc[i] = (uchar)val;
|
||||
}
|
||||
}
|
||||
else if( WTA_K == 3 )
|
||||
else if( wta_k == 3 )
|
||||
{
|
||||
for (i = 0; i < dsize; ++i, pattern += 12)
|
||||
{
|
||||
@@ -292,7 +298,7 @@ computeOrbDescriptors( const Mat& imagePyramid, const std::vector<Rect>& layerIn
|
||||
desc[i] = (uchar)val;
|
||||
}
|
||||
}
|
||||
else if( WTA_K == 4 )
|
||||
else if( wta_k == 4 )
|
||||
{
|
||||
for (i = 0; i < dsize; ++i, pattern += 16)
|
||||
{
|
||||
@@ -333,7 +339,7 @@ computeOrbDescriptors( const Mat& imagePyramid, const std::vector<Rect>& layerIn
|
||||
}
|
||||
}
|
||||
else
|
||||
CV_Error( Error::StsBadSize, "Wrong WTA_K. It can be only 2, 3 or 4." );
|
||||
CV_Error( Error::StsBadSize, "Wrong wta_k. It can be only 2, 3 or 4." );
|
||||
#undef GET_VALUE
|
||||
}
|
||||
}
|
||||
@@ -644,43 +650,93 @@ static inline float getScale(int level, int firstLevel, double scaleFactor)
|
||||
return (float)std::pow(scaleFactor, (double)(level - firstLevel));
|
||||
}
|
||||
|
||||
/** Constructor
|
||||
* @param detector_params parameters to use
|
||||
*/
|
||||
ORB::ORB(int _nfeatures, float _scaleFactor, int _nlevels, int _edgeThreshold,
|
||||
int _firstLevel, int _WTA_K, int _scoreType, int _patchSize) :
|
||||
nfeatures(_nfeatures), scaleFactor(_scaleFactor), nlevels(_nlevels),
|
||||
edgeThreshold(_edgeThreshold), firstLevel(_firstLevel), WTA_K(_WTA_K),
|
||||
scoreType(_scoreType), patchSize(_patchSize)
|
||||
{}
|
||||
|
||||
class ORB_Impl CV_FINAL : public ORB
|
||||
{
|
||||
public:
|
||||
explicit ORB_Impl(int _nfeatures, float _scaleFactor, int _nlevels, int _edgeThreshold,
|
||||
int _firstLevel, int _WTA_K, int _scoreType, int _patchSize, int _fastThreshold) :
|
||||
nfeatures(_nfeatures), scaleFactor(_scaleFactor), nlevels(_nlevels),
|
||||
edgeThreshold(_edgeThreshold), firstLevel(_firstLevel), wta_k(_WTA_K),
|
||||
scoreType(_scoreType), patchSize(_patchSize), fastThreshold(_fastThreshold)
|
||||
{}
|
||||
|
||||
int ORB::descriptorSize() const
|
||||
void setMaxFeatures(int maxFeatures) CV_OVERRIDE { nfeatures = maxFeatures; }
|
||||
int getMaxFeatures() const CV_OVERRIDE { return nfeatures; }
|
||||
|
||||
void setScaleFactor(double scaleFactor_) CV_OVERRIDE { scaleFactor = scaleFactor_; }
|
||||
double getScaleFactor() const CV_OVERRIDE { return scaleFactor; }
|
||||
|
||||
void setNLevels(int nlevels_) CV_OVERRIDE { nlevels = nlevels_; }
|
||||
int getNLevels() const CV_OVERRIDE { return nlevels; }
|
||||
|
||||
void setEdgeThreshold(int edgeThreshold_) CV_OVERRIDE { edgeThreshold = edgeThreshold_; }
|
||||
int getEdgeThreshold() const CV_OVERRIDE { return edgeThreshold; }
|
||||
|
||||
void setFirstLevel(int firstLevel_) CV_OVERRIDE { CV_Assert(firstLevel_ >= 0); firstLevel = firstLevel_; }
|
||||
int getFirstLevel() const CV_OVERRIDE { return firstLevel; }
|
||||
|
||||
void setWTA_K(int wta_k_) CV_OVERRIDE { wta_k = wta_k_; }
|
||||
int getWTA_K() const CV_OVERRIDE { return wta_k; }
|
||||
|
||||
void setScoreType(int scoreType_) CV_OVERRIDE { scoreType = scoreType_; }
|
||||
int getScoreType() const CV_OVERRIDE { return scoreType; }
|
||||
|
||||
void setPatchSize(int patchSize_) CV_OVERRIDE { patchSize = patchSize_; }
|
||||
int getPatchSize() const CV_OVERRIDE { return patchSize; }
|
||||
|
||||
void setFastThreshold(int fastThreshold_) CV_OVERRIDE { fastThreshold = fastThreshold_; }
|
||||
int getFastThreshold() const CV_OVERRIDE { return fastThreshold; }
|
||||
|
||||
// returns the descriptor size in bytes
|
||||
int descriptorSize() const CV_OVERRIDE;
|
||||
// returns the descriptor type
|
||||
int descriptorType() const CV_OVERRIDE;
|
||||
// returns the default norm type
|
||||
int defaultNorm() const CV_OVERRIDE;
|
||||
|
||||
// Compute the ORB_Impl features and descriptors on an image
|
||||
void detectAndCompute( InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints,
|
||||
OutputArray descriptors, bool useProvidedKeypoints=false ) CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
int nfeatures;
|
||||
double scaleFactor;
|
||||
int nlevels;
|
||||
int edgeThreshold;
|
||||
int firstLevel;
|
||||
int wta_k;
|
||||
int scoreType;
|
||||
int patchSize;
|
||||
int fastThreshold;
|
||||
};
|
||||
|
||||
int ORB_Impl::descriptorSize() const
|
||||
{
|
||||
return kBytes;
|
||||
}
|
||||
|
||||
int ORB::descriptorType() const
|
||||
int ORB_Impl::descriptorType() const
|
||||
{
|
||||
return CV_8U;
|
||||
}
|
||||
|
||||
int ORB::defaultNorm() const
|
||||
int ORB_Impl::defaultNorm() const
|
||||
{
|
||||
return NORM_HAMMING;
|
||||
switch (wta_k)
|
||||
{
|
||||
case 2:
|
||||
return NORM_HAMMING;
|
||||
case 3:
|
||||
case 4:
|
||||
return NORM_HAMMING2;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Compute the ORB 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::operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const
|
||||
{
|
||||
(*this)(image, mask, keypoints, noArray(), false);
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
static void uploadORBKeypoints(const std::vector<KeyPoint>& src, std::vector<Vec3i>& buf, OutputArray dst)
|
||||
{
|
||||
size_t i, n = src.size();
|
||||
@@ -713,9 +769,9 @@ static void uploadORBKeypoints(const std::vector<KeyPoint>& src,
|
||||
}
|
||||
copyVectorToUMat(buf, dst);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/** Compute the ORB keypoints on an image
|
||||
/** Compute the ORB_Impl keypoints on an image
|
||||
* @param image_pyramid the image pyramid to compute the features and descriptors on
|
||||
* @param mask_pyramid the masks to apply at every level
|
||||
* @param keypoints the resulting keypoints, clustered per level
|
||||
@@ -729,8 +785,12 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
std::vector<KeyPoint>& allKeypoints,
|
||||
int nfeatures, double scaleFactor,
|
||||
int edgeThreshold, int patchSize, int scoreType,
|
||||
bool useOCL )
|
||||
bool useOCL, int fastThreshold )
|
||||
{
|
||||
#ifndef HAVE_OPENCL
|
||||
CV_UNUSED(uimagePyramid);CV_UNUSED(ulayerInfo);CV_UNUSED(useOCL);
|
||||
#endif
|
||||
|
||||
int i, nkeypoints, level, nlevels = (int)layerInfo.size();
|
||||
std::vector<int> nfeaturesPerLevel(nlevels);
|
||||
|
||||
@@ -780,14 +840,16 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
Mat mask = maskPyramid.empty() ? Mat() : maskPyramid(layerInfo[level]);
|
||||
|
||||
// Detect FAST features, 20 is a good threshold
|
||||
FastFeatureDetector fd(20, 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);
|
||||
|
||||
// Keep more points than necessary as FAST does not give amazing corners
|
||||
KeyPointsFilter::retainBest(keypoints, scoreType == ORB::HARRIS_SCORE ? 2 * featuresNum : featuresNum);
|
||||
KeyPointsFilter::retainBest(keypoints, scoreType == ORB_Impl::HARRIS_SCORE ? 2 * featuresNum : featuresNum);
|
||||
|
||||
nkeypoints = (int)keypoints.size();
|
||||
counters[level] = nkeypoints;
|
||||
@@ -805,12 +867,17 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
std::vector<Vec3i> ukeypoints_buf;
|
||||
|
||||
nkeypoints = (int)allKeypoints.size();
|
||||
if(nkeypoints == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Mat responses;
|
||||
UMat ukeypoints, uresponses(1, nkeypoints, CV_32F);
|
||||
|
||||
// Select best features using the Harris cornerness (better scoring than FAST)
|
||||
if( scoreType == ORB::HARRIS_SCORE )
|
||||
if( scoreType == ORB_Impl::HARRIS_SCORE )
|
||||
{
|
||||
#ifdef HAVE_OPENCL
|
||||
if( useOCL )
|
||||
{
|
||||
uploadORBKeypoints(allKeypoints, ukeypoints_buf, ukeypoints);
|
||||
@@ -818,6 +885,7 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
uresponses, nkeypoints, 7, HARRIS_K );
|
||||
if( useOCL )
|
||||
{
|
||||
CV_IMPL_ADD(CV_IMPL_OCL);
|
||||
uresponses.copyTo(responses);
|
||||
for( i = 0; i < nkeypoints; i++ )
|
||||
allKeypoints[i].response = responses.at<float>(i);
|
||||
@@ -825,6 +893,7 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
}
|
||||
|
||||
if( !useOCL )
|
||||
#endif
|
||||
HarrisResponses(imagePyramid, layerInfo, allKeypoints, 7, HARRIS_K);
|
||||
|
||||
std::vector<KeyPoint> newAllKeypoints;
|
||||
@@ -850,6 +919,8 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
}
|
||||
|
||||
nkeypoints = (int)allKeypoints.size();
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
if( useOCL )
|
||||
{
|
||||
UMat uumax;
|
||||
@@ -862,6 +933,7 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
|
||||
if( useOCL )
|
||||
{
|
||||
CV_IMPL_ADD(CV_IMPL_OCL);
|
||||
uresponses.copyTo(responses);
|
||||
for( i = 0; i < nkeypoints; i++ )
|
||||
allKeypoints[i].angle = responses.at<float>(i);
|
||||
@@ -869,6 +941,7 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
}
|
||||
|
||||
if( !useOCL )
|
||||
#endif
|
||||
{
|
||||
ICAngles(imagePyramid, layerInfo, allKeypoints, umax, halfPatchSize);
|
||||
}
|
||||
@@ -881,7 +954,7 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
}
|
||||
|
||||
|
||||
/** Compute the ORB features and descriptors on an image
|
||||
/** 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
|
||||
@@ -889,9 +962,12 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
* @param do_keypoints if true, the keypoints are computed, otherwise used as an input
|
||||
* @param do_descriptors if true, also computes the descriptors
|
||||
*/
|
||||
void ORB::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_INSTRUMENT_REGION();
|
||||
|
||||
CV_Assert(patchSize >= 2);
|
||||
|
||||
bool do_keypoints = !useProvidedKeypoints;
|
||||
@@ -903,9 +979,11 @@ void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>
|
||||
//ROI handling
|
||||
const int HARRIS_BLOCK_SIZE = 9;
|
||||
int halfPatchSize = patchSize / 2;
|
||||
int border = std::max(edgeThreshold, std::max(halfPatchSize, HARRIS_BLOCK_SIZE/2))+1;
|
||||
// sqrt(2.0) is for handling patch rotation
|
||||
int descPatchSize = cvCeil(halfPatchSize*sqrt(2.0));
|
||||
int border = std::max(edgeThreshold, std::max(descPatchSize, HARRIS_BLOCK_SIZE/2))+1;
|
||||
|
||||
bool useOCL = ocl::useOpenCL();
|
||||
bool useOCL = ocl::isOpenCLActivated() && OCL_FORCE_CHECK(_image.isUMat() || _descriptors.isUMat());
|
||||
|
||||
Mat image = _image.getMat(), mask = _mask.getMat();
|
||||
if( image.type() != CV_8UC1 )
|
||||
@@ -945,7 +1023,7 @@ void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>
|
||||
|
||||
int level_dy = image.rows + border*2;
|
||||
Point level_ofs(0,0);
|
||||
Size bufSize((image.cols + border*2 + 15) & -16, 0);
|
||||
Size bufSize((cvRound(image.cols/getScale(0, firstLevel, scaleFactor)) + border*2 + 15) & -16, 0);
|
||||
|
||||
for( level = 0; level < nLevels; level++ )
|
||||
{
|
||||
@@ -991,10 +1069,10 @@ void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>
|
||||
// Compute the resized image
|
||||
if( level != firstLevel )
|
||||
{
|
||||
resize(prevImg, currImg, sz, 0, 0, INTER_LINEAR);
|
||||
resize(prevImg, currImg, sz, 0, 0, INTER_LINEAR_EXACT);
|
||||
if( !mask.empty() )
|
||||
{
|
||||
resize(prevMask, currMask, sz, 0, 0, INTER_LINEAR);
|
||||
resize(prevMask, currMask, sz, 0, 0, INTER_LINEAR_EXACT);
|
||||
if( level > firstLevel )
|
||||
threshold(currMask, currMask, 254, 0, THRESH_TOZERO);
|
||||
}
|
||||
@@ -1013,8 +1091,11 @@ void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>
|
||||
copyMakeBorder(mask, extMask, border, border, border, border,
|
||||
BORDER_CONSTANT+BORDER_ISOLATED);
|
||||
}
|
||||
prevImg = currImg;
|
||||
prevMask = currMask;
|
||||
if (level > firstLevel)
|
||||
{
|
||||
prevImg = currImg;
|
||||
prevMask = currMask;
|
||||
}
|
||||
}
|
||||
|
||||
if( useOCL )
|
||||
@@ -1028,7 +1109,7 @@ void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>
|
||||
// Get keypoints, those will be far enough from the border that no check will be required for the descriptor
|
||||
computeKeyPoints(imagePyramid, uimagePyramid, maskPyramid,
|
||||
layerInfo, ulayerInfo, layerScale, keypoints,
|
||||
nfeatures, scaleFactor, edgeThreshold, patchSize, scoreType, useOCL);
|
||||
nfeatures, scaleFactor, edgeThreshold, patchSize, scoreType, useOCL, fastThreshold);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1074,14 +1155,14 @@ void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>
|
||||
makeRandomPattern(patchSize, patternbuf, npoints);
|
||||
}
|
||||
|
||||
CV_Assert( WTA_K == 2 || WTA_K == 3 || WTA_K == 4 );
|
||||
CV_Assert( wta_k == 2 || wta_k == 3 || wta_k == 4 );
|
||||
|
||||
if( WTA_K == 2 )
|
||||
if( wta_k == 2 )
|
||||
std::copy(pattern0, pattern0 + npoints, std::back_inserter(pattern));
|
||||
else
|
||||
{
|
||||
int ntuples = descriptorSize()*4;
|
||||
initializeOrbPattern(pattern0, pattern, ntuples, WTA_K, npoints);
|
||||
initializeOrbPattern(pattern0, pattern, ntuples, wta_k, npoints);
|
||||
}
|
||||
|
||||
for( level = 0; level < nLevels; level++ )
|
||||
@@ -1093,6 +1174,7 @@ void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>
|
||||
GaussianBlur(workingMat, workingMat, Size(7, 7), 2, 2, BORDER_REFLECT_101);
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
if( useOCL )
|
||||
{
|
||||
imagePyramid.copyTo(uimagePyramid);
|
||||
@@ -1104,26 +1186,34 @@ void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>
|
||||
UMat udescriptors = _descriptors.getUMat();
|
||||
useOCL = ocl_computeOrbDescriptors(uimagePyramid, ulayerInfo,
|
||||
ukeypoints, udescriptors, upattern,
|
||||
nkeypoints, dsize, WTA_K);
|
||||
nkeypoints, dsize, wta_k);
|
||||
if(useOCL)
|
||||
{
|
||||
CV_IMPL_ADD(CV_IMPL_OCL);
|
||||
}
|
||||
}
|
||||
|
||||
if( !useOCL )
|
||||
#endif
|
||||
{
|
||||
Mat descriptors = _descriptors.getMat();
|
||||
computeOrbDescriptors(imagePyramid, layerInfo, layerScale,
|
||||
keypoints, descriptors, pattern, dsize, WTA_K);
|
||||
keypoints, descriptors, pattern, dsize, wta_k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ORB::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);
|
||||
CV_Assert(firstLevel >= 0);
|
||||
return makePtr<ORB_Impl>(nfeatures, scaleFactor, nlevels, edgeThreshold,
|
||||
firstLevel, wta_k, scoreType, patchSize, fastThreshold);
|
||||
}
|
||||
|
||||
void ORB::computeImpl( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const
|
||||
String ORB::getDefaultName() const
|
||||
{
|
||||
(*this)(image, Mat(), keypoints, descriptors, true);
|
||||
return (Feature2D::getDefaultName() + ".ORB");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user