當進行跟蹤時或者其他類型的用到關鍵點及其描述符的分析時,通常需要做三件事情:第一個是根據一些關鍵點的定義搜尋圖像并查找該圖像中的所有關鍵點;第二個是為發現的每個關鍵字建立一個描述符;第三個是通過将所找到的關鍵點的描述符與一些現有的描述符集進行比較,看看是否可以找到比對項。
在跟蹤應用程式中,最後一步涉及查找序列的一幀圖像中的特征,并嘗試将其與前一幀中的特征進行比對。在目标檢測應用程式中,人們通常會在一些(潛在的廣泛)資料庫中搜尋“已知”特征的“已知”與各個目标或目标類相關聯的特征。
對于這些層中的每一個,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();對于每個函數,有兩個不同的變形 - 一個用于識别(需要一個特征清單并使用經過訓練的字典),另一個用于跟蹤(需要兩個特征清單)。
部分定義:
classcv::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]