Common Interfaces for Feature Detection and Descriptor Extraction

Both detectors and descriptors in OpenCV have wrappers with common interface that enables to switch easily between different algorithms solving the same problem. All objects that implement keypoint detectors inherit FeatureDetector interface. Descriptors that are represented as vectors in a multidimensional space can be computed with DescriptorExtractor interface. DescriptorMatcher interface can be used to find matches between two sets of descriptors. GenericDescriptorMatch is a more generic interface for descriptors. It does not make any assumptions about descriptor representation. Every descriptor with DescriptorExtractor interface has a wrapper with GenericDescriptorMatch interface (see VectorDescriptorMatch). There are descriptors such as one way descriptor and ferns that have GenericDescriptorMatch interface implemented, but do not support DescriptorExtractor.

FeatureDetector

FeatureDetector

Abstract base class for 2D image feature detectors.

class FeatureDetector
{
public:
    void detect( const Mat& image, vector<KeyPoint>& keypoints,
                 const Mat& mask=Mat() ) const;

    virtual void read( const FileNode& fn ) {};
    virtual void write( FileStorage& fs ) const {};

protected:
    ...
};

cv::FeatureDetector::detect

void FeatureDetector::detect(const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat()) const

Detect keypoints in an image.

Parameters:
  • 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.

cv::FeatureDetector::read

void FeatureDetector::read(const FileNode& fn)

Read feature detector from file node.

Parameter:fn – File node from which detector will be read.

cv::FeatureDetector::write

void FeatureDetector::write(FileStorage& fs) const

Write feature detector to file storage.

Parameter:fs – File storage in which detector will be written.

FastFeatureDetector

FastFeatureDetector

Wrapping class for feature detection using FAST() method.

class FastFeatureDetector : public FeatureDetector
{
public:
    FastFeatureDetector( int _threshold = 1, bool _nonmaxSuppression = true );

    virtual void read (const FileNode& fn);
    virtual void write (FileStorage& fs) const;

protected:
        ...
};

GoodFeaturesToTrackDetector

GoodFeaturesToTrackDetector

Wrapping class for feature detection using goodFeaturesToTrack() method.

class GoodFeaturesToTrackDetector : public FeatureDetector
{
public:
    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

MserFeatureDetector

Wrapping class for feature detection using MSER() class.

class MserFeatureDetector : public FeatureDetector
{
public:
    MserFeatureDetector( CvMSERParams params = cvMSERParams () );
    MserFeatureDetector( int delta, int minArea, int maxArea, float maxVariation,
                         float minDiversity, int maxEvolution, double areaThreshold,
                         double minMargin, int edgeBlurSize );

    virtual void read (const FileNode& fn);
    virtual void write (FileStorage& fs) const;

protected:
        ...
}

StarFeatureDetector

StarFeatureDetector

Wrapping class for feature detection using StarDetector() class.

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:
        ...
}

SiftFeatureDetector

SiftFeatureDetector

Wrapping class for feature detection using SIFT() class.

class SiftFeatureDetector : public FeatureDetector
{
public:
    SiftFeatureDetector( double threshold=SIFT::DetectorParams::GET_DEFAULT_THRESHOLD(),
                 double edgeThreshold=SIFT::DetectorParams::GET_DEFAULT_EDGE_THRESHOLD(),
                 int nOctaves=SIFT::CommonParams::DEFAULT_NOCTAVES,
                 int nOctaveLayers=SIFT::CommonParams::DEFAULT_NOCTAVE_LAYERS,
                 int firstOctave=SIFT::CommonParams::DEFAULT_FIRST_OCTAVE,
                 int angleMode=SIFT::CommonParams::FIRST_ANGLE );

    virtual void read (const FileNode& fn);
    virtual void write (FileStorage& fs) const;

protected:
        ...
}

SurfFeatureDetector

SurfFeatureDetector

Wrapping class for feature detection using SURF() class.

class SurfFeatureDetector : public FeatureDetector
{
public:
    SurfFeatureDetector( double hessianThreshold = 400., int octaves = 3,
                         int octaveLayers = 4 );

    virtual void read (const FileNode& fn);
    virtual void write (FileStorage& fs) const;

protected:
        ...
}

DescriptorExtractor

DescriptorExtractor

Abstract base class for computing descriptors for image keypoints.

class DescriptorExtractor
{
public:
    virtual void compute( const Mat& image, vector<KeyPoint>& keypoints,
                          Mat& descriptors ) const = 0;

    virtual void read (const FileNode &fn) {};
    virtual void write (FileStorage &fs) const {};

protected:
    ...
};

In this interface we assume a keypoint descriptor can be represented as a dense, fixed-dimensional vector of some basic type. Most descriptors used in practice follow this pattern, as it makes it very easy to compute distances between descriptors. Therefore we represent a collection of descriptors as a Mat() , where each row is one keypoint descriptor.

cv::DescriptorExtractor::compute

void DescriptorExtractor::compute(const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors) const

Compute the descriptors for a set of keypoints in an image. Must be implemented by the subclass.

Parameters:
  • image – The image.
  • keypoints – The keypoints. Keypoints for which a descriptor cannot be computed are removed.
  • descriptors – The descriptors. Row i is the descriptor for keypoint i.

cv::DescriptorExtractor::read

void DescriptorExtractor::read(const FileNode& fn)

Read descriptor extractor from file node.

Parameter:fn – File node from which detector will be read.

cv::DescriptorExtractor::write

void DescriptorExtractor::write(FileStorage& fs) const

Write descriptor extractor to file storage.

Parameter:fs – File storage in which detector will be written.

SiftDescriptorExtractor

SiftDescriptorExtractor

Wrapping class for descriptors computing using SIFT() class.

class SiftDescriptorExtractor : public DescriptorExtractor
{
public:
    SiftDescriptorExtractor(
             double magnification=SIFT::DescriptorParams::GET_DEFAULT_MAGNIFICATION(),
             bool isNormalize=true, bool recalculateAngles=true,
             int nOctaves=SIFT::CommonParams::DEFAULT_NOCTAVES,
             int nOctaveLayers=SIFT::CommonParams::DEFAULT_NOCTAVE_LAYERS,
             int firstOctave=SIFT::CommonParams::DEFAULT_FIRST_OCTAVE,
             int angleMode=SIFT::CommonParams::FIRST_ANGLE );

    virtual void compute( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors) const;

    virtual void read (const FileNode &fn);
    virtual void write (FileStorage &fs) const;
protected:
    ...
}

SurfDescriptorExtractor

SurfDescriptorExtractor

Wrapping class for descriptors computing using SURF() class.

class SurfDescriptorExtractor : public DescriptorExtractor
{
public:
    SurfDescriptorExtractor( int nOctaves=4,
                             int nOctaveLayers=2, bool extended=false );

    virtual void compute( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors) const;

    virtual void read (const FileNode &fn);
    virtual void write (FileStorage &fs) const;

protected:
    ...
}

DescriptorMatcher

DescriptorMatcher

Abstract base class for matching two sets of descriptors.

class DescriptorMatcher
{
public:
    void add( const Mat& descriptors );
    // Index the descriptors training set.
    void index();
    void match( const Mat& query, vector<int>& matches ) const;
    void match( const Mat& query, const Mat& mask,
                vector<int>& matches ) const;
    virtual void clear();
protected:
   ...
};

cv::DescriptorMatcher::add

void DescriptorMatcher::add(const Mat& descriptors)

Add descriptors to the training set.

Parameter:descriptors – Descriptors to add to the training set.

cv::DescriptorMatcher::match

_ _ ````

void DescriptorMatcher::match(const Mat& query, vector<int>& matches) const
Find the best match for each descriptor from a query set. In one version

of this method the mask is used to describe which descriptors can be matched.descriptors1[i]can be matched with descriptors2[j]only if mask.at<char>(i,j)is non-zero.

void DescriptorMatcher::match(const Mat& query, const Mat& mask, vector<int>& matches) const
Parameters:
  • query – The query set of descriptors.
  • matches – Indices of the closest matches from the training set
  • mask – Mask specifying permissible matches.

cv::DescriptorMatcher::clear

void DescriptorMatcher::clear()
Clear training keypoints.

BruteForceMatcher

BruteForceMatcher

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.

template<class Distance>
class BruteForceMatcher : public DescriptorMatcher
{
public:
    BruteForceMatcher( Distance d = Distance() ) : distance(d) {}

protected:
    ...
}

For efficiency, BruteForceMatcher is templated on the distance metric. For float descriptors, a common choice would be L2<float> . Class L2 is defined as:

template<typename T>
struct Accumulator
{
    typedef T Type;
};

template<> struct Accumulator<unsigned char>  { typedef unsigned int Type; };
template<> struct Accumulator<unsigned short> { typedef unsigned int Type; };
template<> struct Accumulator<char>   { typedef int Type; };
template<> struct Accumulator<short>  { typedef int Type; };

/*
 * Squared Euclidean distance functor
 */
template<class T>
struct L2
{
    typedef T ValueType;
    typedef typename Accumulator<T>::Type ResultType;

    ResultType operator()( const T* a, const T* b, int size ) const;
    {
        ResultType result = ResultType();
        for( int i = 0; i < size; i++ )
        {
            ResultType diff = a[i] - b[i];
            result += diff*diff;
        }
        return sqrt(result);
    }
};

KeyPointCollection

KeyPointCollection

A storage for sets of keypoints together with corresponding images and class IDs

class KeyPointCollection
{
public:
    // Adds keypoints from a single image to the storage.
    // image    Source image
    // points   A vector of keypoints
    void add( const Mat& _image, const vector<KeyPoint>& _points );

    // Returns the total number of keypoints in the collection
    size_t calcKeypointCount() const;

    // Returns the keypoint by its global index
    KeyPoint getKeyPoint( int index ) const;

    // Clears images, keypoints and startIndices
    void clear();

    vector<Mat> images;
    vector<vector<KeyPoint> > points;

    // global indices of the first points in each image,
    // startIndices.size() = points.size()
    vector<int> startIndices;
};

GenericDescriptorMatch

GenericDescriptorMatch

Abstract interface for a keypoint descriptor.

class GenericDescriptorMatch
{
public:
    enum IndexType
    {
        NoIndex,
        KDTreeIndex
    };

    GenericDescriptorMatch() {}
    virtual ~GenericDescriptorMatch() {}

    virtual void add( KeyPointCollection& keypoints );
    virtual void add( const Mat& image, vector<KeyPoint>& points ) = 0;

    virtual void classify( const Mat& image, vector<KeyPoint>& points );
    virtual void match( const Mat& image, vector<KeyPoint>& points,
                        vector<int>& indices ) = 0;

    virtual void clear();
    virtual void read( const FileNode& fn );
    virtual void write( FileStorage& fs ) const;

protected:
    KeyPointCollection collection;
};

cv::GenericDescriptorMatch::add

KeyPointCollection() KeyPoint()

void GenericDescriptorMatch::add(KeyPointCollection& keypoints)
Adds keypoints to the training set (descriptors are supposed to be calculated here).

Keypoints can be passed using (with with corresponding images) or as a vector of from a single image.

param keypoints:
 Keypoints collection with corresponding images.
void GenericDescriptorMatch::add(const Mat& image, vector<KeyPoint>& points)
  • image The source image.
  • points Test keypoints from the source image.

cv::GenericDescriptorMatch::classify

void GenericDescriptorMatch::classify(const Mat& image, vector<KeyPoint>& points)

Classifies test keypoints.

Parameters:
  • image – The source image.
  • points – Test keypoints from the source image.

cv::GenericDescriptorMatch::match

void GenericDescriptorMatch::match(const Mat& image, vector<KeyPoint>& points, vector<int>& indices)

Matches test keypoints to the training set.

Parameters:
  • image – The source image.
  • points – Test keypoints from the source image.
  • indices – A vector to be filled with keypoint class indices.

cv::GenericDescriptorMatch::clear

void GenericDescriptorMatch::clear()
Clears keypoints storing in collection

cv::GenericDescriptorMatch::read

void GenericDescriptorMatch::read(const FileNode& fn)
Reads match object from a file node

cv::GenericDescriptorMatch::write

void GenericDescriptorMatch::write(FileStorage& fs) const
Writes match object to a file storage

VectorDescriptorMatch

VectorDescriptorMatch

Class used for matching descriptors that can be described as vectors in a finite-dimensional space.

template<class Extractor, class Matcher>
class VectorDescriptorMatch : public GenericDescriptorMatch
{
public:
    VectorDescriptorMatch( const Extractor& _extractor = Extractor(),
                           const Matcher& _matcher = Matcher() );
    ~VectorDescriptorMatch();

    // Builds flann index
    void index();

    // Calculates descriptors for a set of keypoints from a single image
    virtual void add( const Mat& image, vector<KeyPoint>& keypoints );

    // Matches a set of keypoints with the training set
    virtual void match( const Mat& image, vector<KeyPoint>& points,
                        vector<int>& keypointIndices );

    // Clears object (i.e. storing keypoints)
    virtual void clear();

    // Reads object from file node
    virtual void read (const FileNode& fn);
    // Writes object to file storage
    virtual void write (FileStorage& fs) const;
protected:
    Extractor extractor;
    Matcher matcher;
};

OneWayDescriptorMatch

OneWayDescriptorMatch

Wrapping class for computing, matching and classification of descriptors using OneWayDescriptorBase() class.

class OneWayDescriptorMatch : public GenericDescriptorMatch
{
public:
    class Params
    {
    public:
        static const int POSE_COUNT = 500;
        static const int PATCH_WIDTH = 24;
        static const int PATCH_HEIGHT = 24;
        static float GET_MIN_SCALE() { return 0.7f; }
        static float GET_MAX_SCALE() { return 1.5f; }
        static float GET_STEP_SCALE() { return 1.2f; }

        Params( int _poseCount = POSE_COUNT,
                Size _patchSize = Size(PATCH_WIDTH, PATCH_HEIGHT),
                string _pcaFilename = string (),
                string _trainPath = string(),
                string _trainImagesList = string(),
                float _minScale = GET_MIN_SCALE(), float _maxScale = GET_MAX_SCALE(),
                float _stepScale = GET_STEP_SCALE() );

        int poseCount;
        Size patchSize;
        string pcaFilename;
        string trainPath;
        string trainImagesList;

        float minScale, maxScale, stepScale;
    };

    OneWayDescriptorMatch();

    // Equivalent to calling PointMatchOneWay() followed by Initialize(_params)
    OneWayDescriptorMatch( const Params& _params );
    virtual ~OneWayDescriptorMatch();

    // Sets one way descriptor parameters
    void initialize( const Params& _params, OneWayDescriptorBase *_base = 0 );

    // Calculates one way descriptors for a set of keypoints
    virtual void add( const Mat& image, vector<KeyPoint>& keypoints );

    // Calculates one way descriptors for a set of keypoints
    virtual void add( KeyPointCollection& keypoints );

    // Matches a set of keypoints from a single image of the training set.
    // A rectangle with a center in a keypoint and size
    // (patch_width/2*scale, patch_height/2*scale) is cropped from the source image
    // for each keypoint. scale is iterated from DescriptorOneWayParams::min_scale
    // to DescriptorOneWayParams::max_scale. The minimum distance to each
    // training patch with all its affine poses is found over all scales.
    // The class ID of a match is returned for each keypoint. The distance
    // is calculated over PCA components loaded with DescriptorOneWay::Initialize,
    // kd tree is used for finding minimum distances.
    virtual void match( const Mat& image, vector<KeyPoint>& points,
                            vector<int>& indices );

    // Classify a set of keypoints. The same as match, but returns point
    // classes rather than indices.
    virtual void classify( const Mat& image, vector<KeyPoint>& points );

    // Clears keypoints storing in collection and OneWayDescriptorBase
    virtual void clear ();

    // Reads match object from a file node
    virtual void read (const FileNode &fn);

    // Writes match object to a file storage
    virtual void write (FileStorage& fs) const;

protected:
    Ptr<OneWayDescriptorBase> base;
    Params params;
};

CalonderDescriptorMatch

CalonderDescriptorMatch

Wrapping class for computing, matching and classification of descriptors using RTreeClassifier() class.

class CV_EXPORTS CalonderDescriptorMatch : public GenericDescriptorMatch
{
public:
    class Params
    {
    public:
        static const int DEFAULT_NUM_TREES = 80;
        static const int DEFAULT_DEPTH = 9;
        static const int DEFAULT_VIEWS = 5000;
        static const size_t DEFAULT_REDUCED_NUM_DIM = 176;
        static const size_t DEFAULT_NUM_QUANT_BITS = 4;
        static const int DEFAULT_PATCH_SIZE = PATCH_SIZE;

        Params( const RNG& _rng = RNG(),
                const PatchGenerator& _patchGen = PatchGenerator(),
                int _numTrees=DEFAULT_NUM_TREES,
                int _depth=DEFAULT_DEPTH,
                int _views=DEFAULT_VIEWS,
                size_t _reducedNumDim=DEFAULT_REDUCED_NUM_DIM,
                int _numQuantBits=DEFAULT_NUM_QUANT_BITS,
                bool _printStatus=true,
                int _patchSize=DEFAULT_PATCH_SIZE );
        Params( const string& _filename );

        RNG rng;
        PatchGenerator patchGen;
        int numTrees;
        int depth;
        int views;
        int patchSize;
        size_t reducedNumDim;
        int numQuantBits;
        bool printStatus;

        string filename;
    };

    CalonderDescriptorMatch();
    CalonderDescriptorMatch( const Params& _params );
    virtual ~CalonderDescriptorMatch();
    void initialize( const Params& _params );

    virtual void add( const Mat& image, vector<KeyPoint>& keypoints );
    virtual void match( const Mat& image, vector<KeyPoint>& keypoints,
                        vector<int>& indices );
    virtual void classify( const Mat& image, vector<KeyPoint>& keypoints );

    virtual void clear ();
    virtual void read( const FileNode &fn );
    virtual void write( FileStorage& fs ) const;

protected:
        ...
};

FernDescriptorMatch

FernDescriptorMatch

Wrapping class for computing, matching and classification of descriptors using FernClassifier() class.

class FernDescriptorMatch : public GenericDescriptorMatch
{
public:
    class Params
    {
    public:
        Params( int _nclasses=0,
                int _patchSize=FernClassifier::PATCH_SIZE,
                int _signatureSize=FernClassifier::DEFAULT_SIGNATURE_SIZE,
                int _nstructs=FernClassifier::DEFAULT_STRUCTS,
                int _structSize=FernClassifier::DEFAULT_STRUCT_SIZE,
                int _nviews=FernClassifier::DEFAULT_VIEWS,
                int _compressionMethod=FernClassifier::COMPRESSION_NONE,
                const PatchGenerator& patchGenerator=PatchGenerator() );

        Params( const string& _filename );

        int nclasses;
        int patchSize;
        int signatureSize;
        int nstructs;
        int structSize;
        int nviews;
        int compressionMethod;
        PatchGenerator patchGenerator;

        string filename;
    };

    FernDescriptorMatch();
    FernDescriptorMatch( const Params& _params );
    virtual ~FernDescriptorMatch();
    void initialize( const Params& _params );

    virtual void add( const Mat& image, vector<KeyPoint>& keypoints );
    virtual void match( const Mat& image, vector<KeyPoint>& keypoints,
                        vector<int>& indices );
    virtual void classify( const Mat& image, vector<KeyPoint>& keypoints );

    virtual void clear ();
    virtual void read( const FileNode &fn );
    virtual void write( FileStorage& fs ) const;

protected:
        ...
};

cv::drawMatches

void drawMatches(const Mat& img1, const vector<KeyPoint>& keypoints1, const Mat& img2, const vector<KeyPoint>& keypoints2, const vector<int>& matches, Mat& outImg, const Scalar& matchColor = Scalar::all(-1), const Scalar& singlePointColor = Scalar::all(-1), const vector<char>& matchesMask = vector<char>(), int flags = DrawMatchesFlags::DEFAULT)
This function draws matches of keypints from two images on output image.

Match is a line connecting two keypoints (circles).

param img1:First source image.
  • keypoints1 Keypoints from first source image.
  • img1 Second source image.
  • keypoints2 Keypoints from second source image.
  • matches Matches from first image to second one, i.e. keypoints1[i] has corresponding point keypoints2[matches[i]]
  • outImg Output image. Its content depends on flags value what is drawn in output image. See below possible flags bit values.
  • matchColor Color of matches (lines and connected keypoints). If matchColor ==Scalar::all(-1) color will be generated randomly.
  • singlePointColor Color of single keypoints (circles), i.e. keypoints not having the matches. If singlePointColor ==Scalar::all(-1) color will be generated randomly.
  • matchesMask Mask determining which matches will be drawn. If mask is empty all matches will be drawn.
  • flags Each bit of flags sets some feature of drawing. Possible flags bit values is defined by DrawMatchesFlags, see below.
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 image, matches and single keypoints will be drawn.
          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.
        };
};