我是靠谱客的博主 疯狂衬衫,最近开发中收集的这篇文章主要介绍opencv特征匹配完成后筛选匹配点方法,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

        时间有限,本人在csdn上看到了三种匹配完成后筛选匹配点的方法,(csdn的搬运工,啥也不懂),若有其他的方法,欢迎交流指正。

1、第一种方法:

            最简单的利用经验值筛选最小距离4倍的matches或者小于最大距离的0.6倍;

vector<cv::DMatch> good_matches;
double min_distance = 9999;
for (size_t i = 0; i < matches.size(); i++) {
if (matches[i].distance < min_distance) {
min_distance = matches[i].distance;
}
}
for (size_t i = 0; i < matches.size(); i++) {
if (matches[i].distance < 4 * min_distance) {
good_matches.push_back(matches[i]);
}
}

2、第二种方法:

        SIFT的作者Lowe提出了比较最近邻距离与次近邻距离的SIFT匹配方式:取一幅图像中的一个SIFT关键点,并找出其与另一幅图像中欧式距离最近的前两个关键点,在这两个关键点中,如果最近的距离除以次近的距离得到的比率ratio少于某个阈值T,则接受这一对匹配点。因为对于错误匹配,由于特征空间的高维性,相似的距离可能有大量其他的错误匹配,从而它的ratio值比较高。显然降低这个比例阈值T,SIFT匹配点数目会减少,但更加稳定,反之亦然。

Lowe推荐ratio的阈值为0.8,但作者对大量任意存在尺度、旋转和亮度变化的两幅图片进行匹配,结果表明ratio取值在0. 4~0. 6 之间最佳,小于0. 4的很少有匹配点,大于0. 6的则存在大量错误匹配点,所以建议ratio的取值原则如下:

ratio=0. 4:对于准确度要求高的匹配;

ratio=0. 6:对于匹配点数目要求比较多的匹配;

ratio=0. 5:一般情况下。

FlannBasedMatcher matcher;
vector<vector<DMatch> > matchePoints;
vector<DMatch> GoodMatchePoints;
matcher.knnMatch(imageDesc1, imageDesc2, matchePoints, 2);
// Lowe's algorithm,获取优秀匹配点
for (int i = 0; i < matchePoints.size(); i++){
if (matchePoints[i][0].distance < 0.6 * matchePoints[i][1].distance) {
GoodMatchePoints.push_back(matchePoints[i][0]);
}
}

     FlannBasedMatcher 默认的KD-tree,自身带train,knnmatch应该用的是机器学习的knn算法,此外源码中还有radiusMatch,没去试,感兴趣的可以尝试一下。

3、第三种方法:

     通过RANSAC方法计算透视变换矩阵来筛选符合相同透视的特征点,这样做可以去除很多错误的匹配。

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;
}
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);

4、第四种方法:

    RANSAC 消除误匹配特征点 主要分为三个部分:
       1)根据matches将特征点对齐,将坐标转换为float类型
       2)使用求基础矩阵方法 findFundamentalMat,得到RansacStatus
       3)根据RansacStatus来将误匹配的点也即RansacStatus[i]=0的点删除

    不知道和第三种有什么区别,用的都是RANSAC 算法消除误匹配,但提取的函数不一样。

//根据matches将特征点对齐,将坐标转换为float类型
vector<KeyPoint> R_keypoint1,R_keypoint2;
for (size_t i=0;i<matches.size();i++)
{
R_keypoint1.push_back(keypoint1[matches[i].queryIdx]);
R_keypoint2.push_back(keypoint2[matches[i].trainIdx]);
//这两句话的理解:R_keypoint1是要存储img1中能与img2匹配的特征点,
//matches中存储了这些匹配点对的img1和img2的索引值
}
//坐标转换
vector<Point2f>p1,p2;
for (size_t i=0;i<matches.size();i++)
{
p1.push_back(R_keypoint1[i].pt);
p2.push_back(R_keypoint2[i].pt);
}
//利用基础矩阵剔除误匹配点
vector<uchar> RansacStatus;
Mat Fundamental= findFundamentalMat(p01,p02,RansacStatus,FM_RANSAC);
vector<KeyPoint> RR_keypoint1,RR_keypoint2;
vector<DMatch> RR_matches;
//重新定义RR_keypoint 和RR_matches来存储新的关键点和匹配矩阵
int index=0;
for (size_t i=0;i<matches.size();i++)
{
if (RansacStatus[i]!=0)
{
RR_keypoint1.push_back(R_keypoint1[i]);
RR_keypoint2.push_back(R_keypoint2[i]);
matches[i].queryIdx=index;
matches[i].trainIdx=index;
RR_matches.push_back(matches[i]);
index++;
}
}
Mat img_RR_matches;
drawMatches(img01,RR_keypoint1,img2,RR_keypoint2,RR_matches,img_RR_matches);
imshow("After RANSAC Image",img_RR_matches);

 

欢迎交流。

参考博客:

1.https://blog.csdn.net/weixin_33709609/article/details/85933024

2.https://blog.csdn.net/u010141147/article/details/9464571

3.https://blog.csdn.net/u011582199/article/details/82626629

最后

以上就是疯狂衬衫为你收集整理的opencv特征匹配完成后筛选匹配点方法的全部内容,希望文章能够帮你解决opencv特征匹配完成后筛选匹配点方法所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部