slam十四讲第七讲之特征提取和匹配代码讲解

slam十四讲第七讲之特征提取和匹配代码讲解

以下代码均是ubuntu20.04下完成,版本不一致之处也均已修改,在这个版本下的学习笔记比较少,希望我能帮大家填补一些坑。另外,本人学习过程中发现经常会忘记,特此记录学习过程与心得,希望能帮助和我一样刚刚入门的小萌新。若发现文中的错误也希望大家批评指正。

#include <iostream>
#include <opencv2/core/core.hpp>//处理图像的工具
#include <opencv2/features2d/features2d.hpp>//处理特征点信息
#include <opencv2/highgui/highgui.hpp>//作图绘制关键点圆圈和描述子信息
#include <chrono> //用于计时

using namespace std;//命名空间 类似python import ** as **(胡扯哈哈)
using namespace cv;

int main(int argc, char **argv) { //argc 输入参数的个数,argv 输入的参数
	if (argc != 3) {  // 系统本身加两张图片argc 表示传入数目
		cout << "输入图片一和图片二" << endl;
		return 1;
	}
	Mat img_1 = imread(argv[1], 1);//1 = CV_LOAD_IMAGE_COLOR unbuntu20的 所以用1 ; 表示以彩色图像形式读取argv中的参数信息,并且存贮于img_1中
	Mat img_2 = imread(argv[2], 1);//Mat 为 opencv 中的类 ,无需定义维度 ,自适应。另外,这里img_1和img_2存储了两张图像的颜色信息,其维度为2维,大小为480*640(这里存储数据的矩阵维度并非480*640,而是480*(640*3),因为要存储每个像素点的BGR信息,因此每个像素的信息对应1行和3列)。
	assert(img_1.data != nullptr && img_2.data != nullptr);//判断传入数据是否为图像

	std::vector<KeyPoint> keypoints_1, keypoints_2;//容器vector类型<keypoint>;存储角度 距离 分类 关键点坐标 金字塔层数等关键信息。 std:: 表示std的啥啥啥。。。
	Mat descriptors_1, descriptors_2;
	Ptr<FeatureDetector> detector = ORB::create();//定义FeatureDector ,调用ORB::create()可以处理图像信息
	Ptr<DescriptorExtractor> descriptor = ORB::create();
	Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");
	
	chrono::steady_clock::time_point t1 = chrono::steady_clock::now();// 开始计时
	detector -> detect(img_1, keypoints_1);
	detector -> detect(img_2, keypoints_2);//提取图像中的特征点放入 keypoint 中,dectector上面定义他的功能了
	descriptor -> compute(img_1, keypoints_1, descriptors_1);//提取图像特征点的描述子信息,存于descriptors中 
	descriptor->compute(img_2, keypoints_2, descriptors_2);
	chrono::steady_clock::time_point t2 = chrono::steady_clock::now();//计时结束
	chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);//作时间差,这个东西就复制粘贴就行,哈哈哈,一顿操作就那样。
	
	cout << "用时:" << time_used.count() << "seconds" << endl;//cout() 数字形式表示出来
	
	Mat outimg1;//定义输出图像
	drawKeypoints(img_1, keypoints_1, outimg1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);//画图
	imshow("ORB 特征", outimg1);//输出图像
	//waitKey(0);//没这个图你看不到,作用就是让图一直显示
	
	vector<DMatch> matches;//定义matches
  	t1 = chrono::steady_clock::now();//开始计时
 	matcher->match(descriptors_1, descriptors_2, matches);//描述信息放入matches
  	t2 = chrono::steady_clock::now();//结束计时
  	time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
  	cout << "match ORB cost = " << time_used.count() << " seconds. " << endl;

  //-- 第四步:匹配点对筛选
  // 计算最小距离和最大距离
  	auto min_max = minmax_element(matches.begin(), matches.end(),
                                [](const DMatch &m1, const DMatch &m2) { return m1.distance < m2.distance; });//遍历所以匹配点,,计算最小和最大距离放在列表中
  	double min_dist = min_max.first->distance;//最小距离取出
  	double max_dist = min_max.second->distance;//最大距离取出

 	printf("-- Max dist : %f \n", max_dist);
  	printf("-- Min dist : %f \n", min_dist);

  //当描述子之间的距离大于两倍的最小距离时,即认为匹配有误.但有时候最小距离会非常小,设置一个经验值30作为下限.
  	std::vector<DMatch> good_matches;
  	for (int i = 0; i < descriptors_1.rows; i++) { // 遍历所有描述子
    		if (matches[i].distance <= max(2 * min_dist, 30.0)) {//30为下限,大于最小距离两倍的点被去除
      	good_matches.push_back(matches[i]);//好点放入容器
    }
  }

	//以下同上
	Mat img_match;
	Mat img_goodmatch;
	drawMatches(img_1, keypoints_1, img_2, keypoints_2, matches, img_match);
	drawMatches(img_1, keypoints_1, img_2, keypoints_2, good_matches, img_goodmatch);
	imshow("all matches", img_match);
	imshow("good matches", img_goodmatch);
	waitKey(0);

	return 0;
}
	
	

以下为输出的结果:在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_51326570/article/details/112839378