特征检测与匹配,在物体检测,视觉跟踪,三维重建等领域都有广泛的应用。所以学习features2d、xfeatures2d中函数的使用,很有必要。
1、得到特征点与特征点描述(SIFT SURF ORB AKAZE)
(1)SIFT
#include
vector key_points;
Mat descriptor;
Ptr sift = xfeatures2d::SIFT::create(0, 3, 0.04, 10);
sift->detectAndCompute(image, noArray(), key_points, descriptor);
#include
Ptr surf = xfeatures2d::SURF::create();
surf->detectAndCompute(image, noArray(), key_points, descriptor);
(3)ORB(实际来看,速度很快,但效果并不一定好)
#include
Ptr orb = ORB::create(5000);
orb->detectAndCompute(image, noArray(), key_points, descriptor);
(4)AKAZE(与ORB在同一个hpp中)
#include
Ptr akaze = AKAZE::create();
akaze->detectAndCompute(image, noArray(), key_points, descriptor);
2、特征点匹配的几种方法
(1)与ORB结合使用,效果较好
void match_features_knn(Mat& query, Mat& train, vector& matches)
{
flann::Index flannIndex(query,flann::LshIndexParams(12,20,2),cvflann::FLANN_DIST_HAMMING);
Mat matchindex(train.rows,2,CV_32SC1);
Mat matchdistance(train.rows, 2, CV_32FC1);
flannIndex.knnSearch(train, matchindex, matchdistance,2,flann::SearchParams());
//根据劳氏算法
for (int i = 0; i < matchdistance.rows; i++)
{
if (matchdistance.at(i, 0) < 0.6*matchdistance.at(i, 1))
{
DMatch dmatches(matchindex.at(i, 0),i, matchdistance.at(i, 0));
matches.push_back(dmatches);
}
}
}
void match_features_FLANN(Mat& query, Mat& train, vector& matches)
{
FlannBasedMatcher matcher;
/*vector match;
matcher.match(query, train, match);
double max_dist = 0;
double min_dist = 100;
for (int i = 0; i < match.size(); i++)
{
double dist = match[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}
for (int i = 0; i < match.size(); i++)
{
if (match[i].distance < 2 * min_dist) matches.push_back(match[i]);
}*/
vector> knn_matches;
matcher.knnMatch(query, train, knn_matches, 2);
//获取满足Ratio Test的最小匹配的距离
float min_dist = FLT_MAX;
for (int r = 0; r < knn_matches.size(); ++r)
{
//Ratio Test
if (knn_matches[r][0].distance > 0.6*knn_matches[r][1].distance)
continue;
float dist = knn_matches[r][0].distance;
if (dist < min_dist) min_dist = dist;
}
matches.clear();
for (size_t r = 0; r < knn_matches.size(); ++r)
{
//排除不满足Ratio Test的点和匹配距离过大的点
if (
knn_matches[r][0].distance > 0.6*knn_matches[r][1].distance ||
knn_matches[r][0].distance > 5 * max(min_dist, 10.0f)
)
continue;
//保存匹配点
matches.push_back(knn_matches[r][0]);
}
}
void match_features(Mat& query, Mat& train, vector& matches)
{
vector> knn_matches;
BFMatcher matcher(NORM_L2);
matcher.knnMatch(query, train, knn_matches, 2);
//获取满足Ratio Test的最小匹配的距离
float min_dist = FLT_MAX;
for (int r = 0; r < knn_matches.size(); ++r)
{
//Ratio Test
if (knn_matches[r][0].distance > 0.6*knn_matches[r][1].distance)
continue;
float dist = knn_matches[r][0].distance;
if (dist < min_dist) min_dist = dist;
}
matches.clear();
for (size_t r = 0; r < knn_matches.size(); ++r)
{
//排除不满足Ratio Test的点和匹配距离过大的点
if (
knn_matches[r][0].distance > 0.6*knn_matches[r][1].distance ||
knn_matches[r][0].distance > 5 * max(min_dist, 10.0f)
)
continue;
//保存匹配点
matches.push_back(knn_matches[r][0]);
}
}
看下面的效果图,会发现大部分点都是匹配正确的。但是,依然有少部分点匹配的明显不正确。
3、进一步匹配(寻找源图与目标图像之间的透视变换)
bool refineMatchesWithHomography(const std::vector& queryKeypoints,const std::vector& trainKeypoints,
float reprojectionThreshold,std::vector& matches,cv::Mat& homography)
{
const int minNumberMatchesAllowed = 8;
if (matches.size() < minNumberMatchesAllowed)
return false;
// Prepare data for cv::findHomography
std::vector srcPoints(matches.size());
std::vector dstPoints(matches.size());
for (size_t i = 0; i < matches.size(); i++)
{
srcPoints[i] = trainKeypoints[matches[i].trainIdx].pt;
dstPoints[i] = queryKeypoints[matches[i].queryIdx].pt;
//srcPoints[i] = trainKeypoints[i].pt;
//dstPoints[i] = queryKeypoints[i].pt;
}
// Find homography matrix and get inliers mask
std::vector inliersMask(srcPoints.size());
homography = cv::findHomography(srcPoints,dstPoints,CV_FM_RANSAC,reprojectionThreshold,inliersMask);
std::vector inliers;
for (size_t i = 0; i minNumberMatchesAllowed;
}