天天看點

特征點尋找的基礎資料結構和函數

    當進行跟蹤時或者其他類型的用到關鍵點及其描述符的分析時,通常需要做三件事情:第一個是根據一些關鍵點的定義搜尋圖像并查找該圖像中的所有關鍵點;第二個是為發現的每個關鍵字建立一個描述符;第三個是通過将所找到的關鍵點的描述符與一些現有的描述符集進行比較,看看是否可以找到比對項。

    在跟蹤應用程式中,最後一步涉及查找序列的一幀圖像中的特征,并嘗試将其與前一幀中的特征進行比對。在目标檢測應用程式中,人們通常會在一些(潛在的廣泛)資料庫中搜尋“已知”特征的“已知”與各個目标或目标類相關聯的特征。

    對于這些層中的每一個,OpenCV提供了一個遵循“做東西的類”(函子)模型的泛化機制;對于這些階段中的每一個都有一個抽象基類,它為從其派生的一系列對象定義一個公共接口;最後每個派生類都實作一個特定的算法。

1、cv :: KeyPoint對象

class

cv::KeyPoint {

public

:   cv::Point2f pt;       // coordinates of the keypoint  

float

      size;     // diameter of the meaningful keypoint neighborhood  

float

      angle;    // computed orientation of the keypoint (-1 if none)  

float

      response; // response for which the keypoints was selected  

int

        octave;   // octave (pyramid layer) keypoint was extracted from  

int

        class_id; // object id, can be used to cluster keypoints by object   cv::KeyPoint(     cv::Point2f _pt,    

float

      _size,    

float

      _angle=-1,    

float

      _response=0,    

int

        _octave=0,    

int

        _class_id=-1   );   cv::KeyPoint(    

float

      x,    

float

      y,    

float

      _size,    

float

      _angle=-1,    

float

      _response=0,    

int

        _octave=0,    

int

        _class_id=-1   ); ... };

3種重載都包括了cv :: Point2f的資訊,此外還包括其他一些能夠說明“特征”的屬性。

2、cv :: Feature2D

class

 cv::Feature2D : 

public

 cv::Algorithm {

public

:  

virtual

void

detect(     cv::InputArray                   image,      // Image on which to detect     vector< cv::KeyPoint >&          keypoints,  // Array of found keypoints     cv::InputArray                   mask     = cv::noArray()   )

const

;  

virtual

void

detect(     cv::InputArrayOfArrays           images,     // Images on which to detect     vector<vector< cv::KeyPoint > >& keypoints,  // keypoints for each image     cv::InputArrayOfArrays           masks    = cv::noArray ()   )

const

;  

virtual

void

compute(     cv::InputArray image,                 // Image where keypoints are located     std::vector<cv::KeyPoint>& keypoints, // input/output vector of keypoints     cv::OutputArray descriptors );        // computed descriptors, M x N matrix,                                           // where M is the number of keypoints                                           // and N is the descriptor size  

virtual

void

compute(     cv::InputArrayOfArrays image,          // Images where keypoints are located     std::vector<std::vector<cv::KeyPoint> >& keypoints, //I/O vec of keypnts     cv::OutputArrayOfArrays descriptors ); // computed descriptors,                                            // vector of (Mi x N) matrices, where                                            // Mi is the number of keypoints in                                            // the i-th image and N is the                                             // descriptor size  

virtual

void

detectAndCompute(     cv::InputArray image,                 // Image on which to detect     cv::InputArray mask,                  // Optional region of interest mask      std::vector<cv::KeyPoint>& keypoints, // found or provided keypoints     cv::OutputArray descriptors,          // computed descriptors    

bool

useProvidedKeypoints=

false

);    // if true,                                           // the provided keypoints are used,                                           // otherwise they are detected  

virtual

int

descriptorSize()

const

;     // size of each descriptor in elements  

virtual

int

descriptorType()

const

;     // type of descriptor elements  

virtual

int

defaultNorm()

const

;        // the recommended norm to be used                                           // for comparing descriptors.                                           // Usually, it's NORM_HAMMING for                                            // binary descriptors and NORM_L2                                            // for all others.  

virtual

void

read(

const

cv::FileNode& );  

virtual

void

write( cv::FileStorage& )

const

;   ... };

    複雜的定義,注意Feature2D派生自alogorithm算法類。

a、如果它是一個單純的關鍵點檢測算法(如FAST),實際的實作可能隻是執行cv :: Feature2D :: detect(),; 

b、如果它是一個純特征描述算法(如FREAK),實際的實作可能隻是cv :: Feature2D :: compute();

c、在要求“完全解決”的算法的情況下,如SIFT,SURF,ORB,BRISK等,實際的實作就會是cv :: Feature2D :: detectAndCompute(),在這種情況下,detect()和compute()會被隐式地調用。

    對于具體每一種算法,查找關鍵點的實際方法當然對于cv :: Feature2D的許多可用派生類中的每一個都是不同的。

    值得注意的是,根據算法何時實作,許多關鍵點特征檢測器和提取器都設計在一起成為一個對象。在這種情況下,方法cv::Feature2D::detectAndCompute() 被實作。每當某個算法提供了detectAndCompute()時,強烈建議直接使用它,而不是在後續調用detect(),然後再使用compute()。原因很明顯,就是性能更好。

3、cv :: DMatch

尋找到的特征結果需要進行比對,以友善下一步的計算。

class

cv::DMatch {

public

:   DMatch();              // sets this->distance                           // to std::numeric_limits<float>::max()   DMatch(

int

_queryIdx,

int

_trainIdx,

float

_distance );   DMatch(

int

_queryIdx,

int

_trainIdx,

int

_imgIdx,

float

_distance );  

int

  queryIdx;        // query descriptor index  

int

  trainIdx;        // train descriptor index  

int

  imgIdx;          // train image index  

float

distance;  

bool

operator

<(

const

DMatch &m )

const

; // Comparison operator                                             // based on 'distance' }

    cv :: DMatch的資料成員是queryIdx,trainIdx,imgIdx和distance。前兩個辨識與每個圖像中的關鍵點清單比對的關鍵點。 imgIdx用于辨識在圖像和字典之間尋求比對的情況下訓練圖像來自的特定圖像。最後一個成員,distance,用來表示比對的品質。

4、cv :: DescriptorMatcher(關鍵點比對類)

    一般有兩種不同的情況:對于目辨別别的情況,我們需要首先用描述符的字典訓練比對器,然後才能向比對器呈現單個描述符清單,并告訴我們比對器存儲的哪個(如果有的話)關鍵點是與我們提供的清單中的那些相比對;對于跟蹤的情形,我們需要提供兩個描述符清單,然後比對器告訴我們它們之間的比對位置。 

    cv:DescriptorMatcher類接口提供了三個函數match(),knnMatch()和 radiusMatch();對于每個函數,有兩個不同的變形 - 一個用于識别(需要一個特征清單并使用經過訓練的字典),另一個用于跟蹤(需要兩個特征清單)。

部分定義:

class

cv::DescriptorMatcher {

public

:  

virtual

void

add( InputArrayOfArrays descriptors );  // Add train descriptors  

virtual

void

clear();                                // Clear train descriptors  

virtual

bool

empty()

const

;                          // true if no descriptors  

void

train();                                        // Train matcher  

virtual

bool

isMaskSupported()

const

= 0;            // true if supports masks  

const

vector<cv::Mat>& getTrainDescriptors()

const

;  // Get train descriptors   // methods to match descriptors from one list vs. "trained" set (recognition)   //  

void

match(     InputArray                    queryDescriptors,     vector<cv::DMatch>&           matches,     InputArrayOfArrays            masks           = noArray ()   );  

void

knnMatch(     InputArray                    queryDescriptors,     vector< vector<cv::DMatch> >& matches,    

int

                          k,     InputArrayOfArrays            masks           = noArray (),    

bool

                         compactResult   =

false

  );  

void

radiusMatch(     InputArray                    queryDescriptors,     vector< vector<cv::DMatch> >& matches,    

float

                        maxDistance,     InputArrayOfArrays            masks           = noArray (),    

bool

                         compactResult   =

false

  );   // methods to match descriptors from two lists (tracking)   //   // Find one best match for each query descriptor  

void

match(     InputArray                    queryDescriptors,     InputArray                    trainDescriptors,     vector<cv::DMatch>&           matches,     InputArray                    mask            = noArray ()   )

const

;   // Find k best matches for each query descriptor (in increasing    // order of distances)  

void

knnMatch(     InputArray                    queryDescriptors,     InputArray                    trainDescriptors,     vector< vector<cv::DMatch> >& matches,    

int

                          k,     InputArray                    mask            = noArray(),    

bool

                         compactResult   =

false

  )

const

;   // Find best matches for each query descriptor with distance less    // than maxDistance  

void

radiusMatch(     InputArray                    queryDescriptors,     InputArray                    trainDescriptors,     vector< vector<cv::DMatch> >& matches,    

float

                        maxDistance,     InputArray                    mask            = noArray (),    

bool

                         compactResult   =

false

  )

const

;  

virtual

void

read(

const

FileNode& );     // Reads matcher from a file node  

virtual

void

write( FileStorage& )

const

; // Writes matcher to a file storage  

virtual

cv::Ptr<cv::DescriptorMatcher> clone(           

bool

emptyTrainData=

false

    )

const

= 0;  

static

cv::Ptr<cv::DescriptorMatcher> create(           

const

string& descriptorMatcherType    ); ... };

    簡單比較,match()方法需要通常的cv :: Mat格式的單個關鍵點描述符清單queryDescriptors。在這種情況下,請記住每行代表單個描述符,每列是該描述符向量表示的一個次元。 

    knnMatch() 函數,它需要與match() 相同的清單描述符。然而,在這種情況下,對于查詢清單中的每個描述符,它将從字典中找到特定數量的最佳比對。

    第三種比對方法是radiusMatch()。 與搜尋k個最佳比對的k-最近鄰比對不同,半徑比對傳回了查詢描述符特定距離内的所有比對。

5、序列化

read()和write()方法分别對應cv :: FileNode和cv :: FileStorage格式的對象,并允許你從磁盤讀取和寫入比對器;

clone() 和create() 方法允許你分别建立一個描述符的副本或者通過名稱建立一個新的描述符;

感謝閱讀至此,希望有所幫助。

來自為知筆記(Wiz)

目前方向:圖像拼接融合、圖像識别

聯系方式:[email protected]