前阵子推进毕设,通过各种教材、论文和博客的调研,总算对视觉SLAM有了一个比较宏观的了解,摘录归纳了许多特征提取和跟踪的算法,最后初步方案决定为对ORB-SLAM展开研究。
赶紧花时间去补习了一下C++,用了半天配置完了OpenCV3.4的环境,又用了近一整天时间快速翻完了毛星云的《OpenCV3编程入门》,跑了跑里面的例程,发现简直友好度爆炸。这每一章的内容,不管是图像滤波也好,图像分割也好,图像修复也好,哪怕是特征检测,都差不多是——输入图片>>运用对应的函数处理图片>>输出图片的过程。函数的具体原理基本不用搞懂,OpenCV全部集成好了,很容易就能跑个demo出来。
但是后面想要自己写代码,肯定要深入研究具体理论。这里先记录一份自己第一次跑出ORB特征点检测和匹配的成果。
下面是代码,主要来源:https://www.cnblogs.com/Jessica-jie/p/8622449.html。
#include<iostream>
#include<vector>
#include<opencv2\core\core.hpp>
#include<opencv2\features2d\features2d.hpp>
#include<opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img1 = imread("img01.jpg");
Mat img2 = imread("img02.jpg");
// 1. 初始化
vector<KeyPoint> keypoints1, keypoints2;
Mat descriptors1, descriptors2;
Ptr<ORB> orb = ORB::create();
// 2. 提取特征点
orb->detect(img1, keypoints1);
orb->detect(img2, keypoints2);
// 3. 计算特征描述符
orb->compute(img1, keypoints1, descriptors1);
orb->compute(img2, keypoints2, descriptors2);
// 4. 对两幅图像的BRIEF描述符进行匹配,使用BFMatch,Hamming距离作为参考
vector<DMatch> matches;
BFMatcher bfMatcher(NORM_HAMMING);
bfMatcher.match(descriptors1, descriptors2, matches);
// 5. 展示
Mat ShowMatches;
drawMatches(img1, keypoints1, img2, keypoints2, matches, ShowMatches);
imshow("matches", ShowMatches);
waitKey(0);
return 0;
}
下面是运行结果,采用暴力匹配:计算某一个特征点描述子与其他所有特征点描述子之间的距离,然后将得到的距离进行排序,取距离最近的一个作为匹配点。
这个方法太简单粗暴了,可以采用一定原则去优化一下,比如:汉明距离小于最小距离的两倍。
在第四步后面添加如下代码:
// 匹配对筛选
double min_dist = 1000, max_dist = 0;
// 找出所有匹配之间的最大值和最小值
for (int i = 0; i < descriptors1.rows; i++)
{
double dist = matches[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}
// 当描述子之间的匹配不大于2倍的最小距离时,即认为该匹配是一个错误的匹配。
// 但有时描述子之间的最小距离非常小,可以设置一个经验值作为下限
vector<DMatch> good_matches;
for (int i = 0; i < descriptors1.rows; i++)
{
if (matches[i].distance <= max(2 * min_dist, 30.0))
good_matches.push_back(matches[i]);
}
然后把画出匹配的函数参数,改成筛选后的匹配(good_matches)。
drawMatches(img1, keypoints1, img2, keypoints2, good_matches, ShowMatches);
再次编译运行,发现结果好了很多: