您的位置:首页 > Web前端

opencv3.1.0 特征点检测与图像匹配(features2d、xfeatures2d)

2016-08-08 16:45 483 查看
特征检测与匹配,在物体检测,视觉跟踪,三维重建等领域都有广泛的应用。所以学习features2d、xfeatures2d中函数的使用,很有必要。

1、得到特征点与特征点描述(SIFT SURF ORB  AKAZE)

(1)SIFT

#include <opencv2\xfeatures2d\nonfree.hpp>
vector<KeyPoint> key_points;
Mat descriptor;
Ptr<Feature2D> sift = xfeatures2d::SIFT::create(0, 3, 0.04, 10);
sift->detectAndCompute(image, noArray(), key_points, descriptor);


(2)SURF(可以认为是尺度不变特征变换sift的加速版)

#include <opencv2\xfeatures2d\nonfree.hpp>
Ptr<Feature2D> surf = xfeatures2d::SURF::create();
surf->detectAndCompute(image, noArray(), key_points, descriptor);


(3)ORB(实际来看,速度很快,但效果并不一定好)

#include <opencv2\features2d\features2d.hpp>
Ptr<ORB> orb = ORB::create(5000);
orb->detectAndCompute(image, noArray(), key_points, descriptor);


(4)AKAZE(与ORB在同一个hpp中)

#include <opencv2\features2d\features2d.hpp>
Ptr<AKAZE> akaze = AKAZE::create();
akaze->detectAndCompute(image, noArray(), key_points, descriptor);
2、特征点匹配的几种方法

(1)与ORB结合使用,效果较好

void match_features_knn(Mat& query, Mat& train, vector<DMatch>& 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<float>(i, 0) < 0.6*matchdistance.at<float>(i, 1))
{
DMatch dmatches(matchindex.at<int>(i, 0),i, matchdistance.at<float>(i, 0));
matches.push_back(dmatches);
}
}
}


(2)个人感觉这种方法,效果与暴力匹配法没啥区别,但是被注释掉的方法,效果不好

void match_features_FLANN(Mat& query, Mat& train, vector<DMatch>& matches)
{
FlannBasedMatcher matcher;

/*vector<DMatch> 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<vector<DMatch>> 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]);
}

}


(3)也叫暴力匹配法,此种方法结合sift、surf用的比较多

void match_features(Mat& query, Mat& train, vector<DMatch>& matches)
{
vector<vector<DMatch>> 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<cv::KeyPoint>& queryKeypoints,const std::vector<cv::KeyPoint>& trainKeypoints,
float reprojectionThreshold,std::vector<cv::DMatch>& matches,cv::Mat& homography)
{
const int minNumberMatchesAllowed = 8;
if (matches.size() < minNumberMatchesAllowed)
return false;
// Prepare data for cv::findHomography
std::vector<cv::Point2f> srcPoints(matches.size());
std::vector<cv::Point2f> 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<unsigned char> inliersMask(srcPoints.size());
homography = cv::findHomography(srcPoints,dstPoints,CV_FM_RANSAC,reprojectionThreshold,inliersMask);
std::vector<cv::DMatch> inliers;
for (size_t i = 0; i<inliersMask.size(); i++)
{
if (inliersMask[i])
inliers.push_back(matches[i]);
}
matches.swap(inliers);
return matches.size() > minNumberMatchesAllowed;
}


效果如下所示(没有发现匹配不对的点)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: