《视觉SLAM十四讲精品总结》5:VO——ORB特征提取和匹配

一、简介

视觉里程计法:提取、匹配图像特征点,然后估计两帧之间的相机运动,给后端提供较好的初始值。

角点的局限:例如:从远处上看上去是角点的地方,当相机走近后,可能就是角点了。或者,当旋转相机的时候,角点的外观会发生变换。 
进而,我们提出了SIFT,SURF,ORB特征。 

特征点由提取关键点和计算描述子两部分组成。

关键点:该特征点在图像的位置,具有朝向、大小的信息。

描述子:描述关键点周围像素信息的向量。

SIFT(尺度不变特征变换—Scale-Invariant Feature Transform):充分考虑图像变换过程中光照、尺度、旋转等变换,但计算量大。

FAST:只有关键点没有描述子,降低精度和健壮性,提升计算速度。

ORB:(Oriented FAST and Rotated BRIEF):改进了FAST 不具有方向性的问题,添加了尺度和旋转的特性。采用速度极快的二进制描述子BRIEF,

二、ORB特征(Oriented FAST and Rotated BRIEF)

两步骤:FAST角点提取+BRIEF描述子

1、FAST角点:

主要检测局部像素灰度变化明显的地方。思想:如果一个像素与邻域像素差别较大(过亮或者过暗),只需比较像素亮度大小。

1、在图像中选取像素p,假设他的亮度是IP 
2、设置一个阈值T,例如T=IP*20% 
3、以像素p为中心,选取半径为3的圆上的16个像素点, 这里的3应该是三个像素框 
4、如果在选取的圆上面,有连续N个点的亮度值大于IP+T(1.2*IP))或者小于IP-T(0.8*IP),那么像素p通常可以被认为是特征点(N通常取12,FAST-12,通常n取9和11,的时候,称为FAST-9和FAST-11) 

FAST-12算法:

添加预测试操作,于每个像素,直接检测在邻域圆上的第1,5,9,13个像素的亮度,只有当这四个像素当中有三个同时大于IP+T或者小于IP-T的时候,当前像素才有可能是是角点。

问题1:FAST特征点的数量很多,并且不是确定,而大多数情况下,我们希望能够固定特征点的数量。 

解决方法:在ORB当中,我们可以指定要提取的特征点数量。对原始的FAST角点分别计算Harris的响应值,然后选取前N个点具有最大相应值的角点,作为最终角点的集合。 

问题2:FAST角点不具有方向信息和尺度问题

解决方法:尺度不变性构建的图像的金字塔,并且从每一层上面来检测角点。旋转性是由灰度质心法实现。 

灰度质心法:质心是指以图像块灰度值作为权重的中心。(目标是为找找到方向

1、在一个小的图像块B中,定义图像块的矩为: 
这里写图片描述 
2、通过矩找到图像块的质心 
这里写图片描述 
3、连接图像块的几何中心o与质心C,得到一个oc的向量,把这个向量的方向定义特征点的方向 
这里写图片描述

2、BRIEF描述子

BRIEF是二进制描述子,它的描述向量是由许多个0和1组成,这里的0和1编码了关键点附近的两个像素p和q的大小关系,如果p>q,则取1 ;否则取0;p q 的挑选为随机选点。

三、特征匹配

通过对图像与地图之间的描述子进行准确匹配,为后续的姿态估计优化等操作减轻负担。

暴力匹配:对两帧图像中每一个特征点x(t)与所有的特征点x(t+1)测量描述子的距离,然后排序,取最近的一个作为匹配点。

描述子距离表明了两个特征之间的相似距离。

二进制描述子,使用汉明距离,指的是不同位数的个数。

快速近似最邻近算法(FLANN):适合匹配点数量多情况。

 

1、计算特征点和描述子

	if (argc != 3)
	{
		cout << "usage: feature_extraction img1 img2" << endl;
		return 1;
	}
	//1. 读取图像
	Mat img_1 = imread(argv[1], CV_LOAD_IMAGE_COLOR);
	Mat img_2 = imread(argv[2], CV_LOAD_IMAGE_COLOR);

	//1.1 初始化特征点和描述子和汉明距离
	std::vector<KeyPoint> keypoints_1, keypoints_2;//???特征点向量KeyPoint
	Mat descriptors_1, descriptors_2;//描述子用Mat存储
	Ptr<FeatureDetector> detector = ORB::create();//???Ptr模板类的FeatureDector类型
	Ptr<DescriptorExtractor> descriptor = ORB::create();//???ORB::create()
	// Ptr<FeatureDetector> detector = FeatureDetector::create(detector_name);
	// Ptr<DescriptorExtractor> descriptor = DescriptorExtractor::create(descriptor_name);
	Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");

	//1.2. 检测 Oriented FAST 特征点位置
	detector->detect(img_1, keypoints_1);//???detect函数
	detector->detect(img_2, keypoints_2);

	//1.3. 根据角点位置计算 BRIEF 描述子
	descriptor->compute(img_1, keypoints_1, descriptors_1);// ???computer函数
	descriptor->compute(img_2, keypoints_2, descriptors_2);

	//1.4. huigui模块,画出特征点????
	Mat outimg1;
	drawKeypoints(img_1, keypoints_1, outimg1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
	imshow("ORB特征点", outimg1);

2、对BRIEF描述子进行匹配

	//2. 对两幅图像中的BRIEF描述子进行匹配,使用 Hamming 距离
	vector<DMatch> matches;//???Dmatch类型
	//BFMatcher matcher ( NORM_HAMMING );
	matcher->match(descriptors_1, descriptors_2, matches);//???match函数

	//2.1 匹配点对筛选,最相似和最不相似的两组点之间的距离
	double min_dist = 10000, max_dist = 0;

	//2.2 迭代,找出所有匹配之间的最小距离和最大距离
	for (int i = 0; i < descriptors_1.rows; i++)
	{
		double dist = matches[i].distance;//获取当前点距离???
		if (dist < min_dist) min_dist = dist;
		if (dist > max_dist) max_dist = dist;
	}

	//2.3 输出最大距离和最小距离
	min_dist = min_element(matches.begin(), matches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance; })->distance;
	max_dist = max_element(matches.begin(), matches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance; })->distance;

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

3、匹配结果

	//3 匹配结果
	//当描述子之间的距离大于两倍的最小距离时,即认为匹配有误.
	//但有时候最小距离会非常小,设置一个经验值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))
		{
			good_matches.push_back(matches[i]);
		}
	}

	//3.1 绘制匹配结果
	Mat img_match;
	Mat img_goodmatch;
	//???drawMatches函数
	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("所有匹配点对", img_match);
	imshow("优化后匹配点对", img_goodmatch);

猜你喜欢

转载自blog.csdn.net/try_again_later/article/details/81604811