OpenCV4学习笔记(41)——ORB特征提取描述算法

今天要整理记录的笔记内容是特征算法中比较常用的一种——ORB特征提取描述算法,顾名思义,ORB算法包含了对特征点的提取和描述这两个部分。而在上次的博文《OpenCV4学习笔记(39)》中,记录了FAST特征提取算法和BRIEF特征描述算法,而今天的ORB算法正是这两者的融合升级。

ORB(Oriented FAST and Rotated BRIEF)算法是一种快速特征点提取和描述的算法。这个算法是由Ethan Rublee, Vincent Rabaud, Kurt Konolige以及Gary R.Bradski在2011年一篇名为《ORB:An Efficient Alternative to SIFT or SURF》的文章中提出。

ORB算法分为两部分,分别是特征点提取和特征点描述。

特征提取部分是由FAST(Features from Accelerated Segment Test)算法发展来的,特征点描述是根据BRIEF(Binary Robust IndependentElementary Features)特征描述算法改进的。ORB特征是将FAST特征点的检测方法与BRIEF特征描述子结合起来,并在它们原来的基础上做了改进与优化。尤其是对于BRIEF算法,在ORB算法中针对其不具有旋转不变性这个缺点,做了针对性优化。

可以说,ORB特征算法是SIFT算法处于专利保护期时的一个高效替代算法,当然现在的SIFT算法已经过了专利保护了,在OpenCV4.3.0版本中已经能够使用了而且不需要自己编译。(虽然我用的还是4.2.0,懒得下载。。。)

ORB特征提取描述算法的流程大概可以分为以下几部分:
1、基于FAST算法提取关键点;
2、基于Harris算法(寻找在x、y两个方向上都有比较大变化的点,当某点在x和y方向上的二次导数值比较大时,则该点可以认为是特征点)筛选匹配分数高的关键点;
3、对图像进行金字塔变换;
4、计算关键点中心和角度方向;
5、基于BRIEF算法计算关键点的二值描述子;
6、基于贪心算法过滤低相关性像素块。

在OpenCV中封装了ORB算法的特征检测器,我们通过auto orb = ORB::create()来创建OBR特征检测器指针,可以使用auto智能指针来自动判断返回值类型。其中,create()的参数如下:

1、参数nfeatures:检测到的最大特征点数;
2、参数scaleFactor:金字塔缩放比例,是一个大于1的float类型数值,默认值为1.2;
scaleFactor == 2表示经典图像金字塔,每一层图像尺寸是上一层图像尺寸的1/2,但是如此大的缩放比例将大大降低特征匹配分数;
缩放比例越大、所需金字塔层数越少、速度更快、特征点匹配的精度更低,缩放比例越小(越接近1)、所需金字塔层数越多、速度更慢、特征点匹配精度更高;
3、参数nlevels:图像金字塔层数,一般与scaleFactor成反比,默认值为8;
4、参数edgeThreshold:未检测到特征的边框的大小,应该与patchSize参数大致匹配;
5、参数firstLevel:存放原图像的金字塔等级;如果在金字塔中间层存放原图像,则该层前面的金字塔层将会存放原图像的放大图像;
6、参数WTA_K: 产生定向的BRIEF描述子的每个元素的点数,默认值为2;
7、参数scoreType:使用的匹配分数计算方式;默认的HARRIS_SCORE:表示使用Harris算法对特征点的匹配分数进行排序(分数被写入KeyPoint :: score并用于保留最佳特征点);FAST_SCORE:产生的稳定关键点会稍差一些,但计算速度会稍快一些。
8、参数patchSize:计算定向的BRIEF描述子使用的邻域大小;在较高的金字塔层上,特征覆盖的感知图像区域将更大,默认值为31。
9、参数fastThreshold:FAST算法提取特征点的阈值,默认值为20。

创建ORB特征检测器后,使用orb->detectAndCompute()来检测特征点并且计算特征点的特征描述子,其参数含义如下:

1、参数image:输入的待检测图像;
2、参数mask:针对输入图像的掩膜;
3、参数keyPoints:输出的特征点集;是一个KeyPoint类型的向量;
4、参数descriptors:输出的用于描述特征点集的二值描述子。

下面看一下代码演示:

	Mat tem = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\a.png");
	flip(tem, tem, 0);
	resize(tem, tem, Size(), 1.5, 1.5);
	Mat test = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\abc.png");
	//创建OBR对象指针,使用auto智能指针来自动判断返回值类型
	auto orb = ORB::create(100, 1.6, 8, 31, 0, 2, ORB::HARRIS_SCORE, 31, 20);	
	//通过ORB算法检测两幅图像中的特征点,并计算各自的二值描述子
	vector<KeyPoint> keyPoints_tem, keyPoints_test;
	Mat descriptors_tem, descriptors_test;
	orb->detectAndCompute(tem, Mat(), keyPoints_tem, descriptors_tem, false);
	orb->detectAndCompute(test, Mat(), keyPoints_test, descriptors_test, false);
	//特征匹配是通过使用合适的相似度度量比较特征描述子来执行的。
	//定义特征描述子匹配器
	Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::MatcherType::BRUTEFORCE);
	//参数MatcherType:匹配器类型,这里使用MatcherType::BRUTEFORCE(暴力匹配算法)

	vector<DMatch> matches;
	//通过描述子匹配器,对两幅图像的描述子进行匹配,也就是将两幅图像中的对应特征点进行匹配;输出的是一个DMatch结构体向量,其每一个DMatch结构体包含一组对应特征点的信息。
	matcher->match(descriptors_tem, descriptors_test, matches, Mat());

	float maxdist = 0;
	for (int i = 0; i < matches.size(); i++)
	{
		//寻找匹配特征点对中匹配质量最差的点对,也就是匹配距离最远的点对,获取该最大距离值
		maxdist = max(maxdist, matches[i].distance);	
	}

	vector<DMatch> good_matches;
	for (int j = 0; j < matches.size(); j++)
	{
		//如果匹配特征点对中,某个点对的匹配距离小于某个阈值(可以是最大距离值乘以一个小于1的系数),则可以认为是高度匹配的特征点对
		if (matches[j].distance < 0.18 * maxdist)		
		{
			good_matches.push_back(matches[j]);
		}
	}

	//将两幅图像之间的高度匹配的对应特征点使用连线绘制出来,输出一幅将两幅图像拼接起来再进行连线的图像
	//Scalar::all(-1)是选择随机颜色
	Mat result;
	drawMatches(tem, keyPoints_tem, test, keyPoints_test, good_matches, result, Scalar::all(-1), Scalar::all(-1));
	imshow("result", result);

在上述代码中,对两幅图像进行ORB特征提取和描述,并通过描述子匹配器对两幅图像的描述子进行匹配,也就是将两幅图像中的对应特征点进行匹配,输出的是一个DMatch结构体向量,向量中每一个DMatch结构体包含一组对应特征点的信息。

注意:对于与ORB特征描述子类似的二进制描述子而言,在匹配时采用NORM_HANMING来作为度量距离;而对于类似SIFT、SURF之类的非二进制描述子而言,一般常用NORM_L2作为距离度量,也可以选用NORM_L1

在进行匹配的特征点对中,如果某个点对的匹配距离小于某个阈值(可以是最大距离值乘以一个小于1的系数),则可以认为该点对是高度匹配的特征点对,然后我们就可以将两幅图像之间的高度匹配的对应特征点通过连线绘制出来,并输出一幅将两幅图像拼接起来再进行对应特征点连线的图像。

下面是进行匹配的模板图和匹配图:
OpenCV4学习笔记(41)——ORB特征提取描述算法_第1张图片
OpenCV4学习笔记(41)——ORB特征提取描述算法_第2张图片
这里,我把“A”给抠了出来,而且把它给旋转了180度,并且放大1.5倍,下面看看匹配的结果:

OpenCV4学习笔记(41)——ORB特征提取描述算法_第3张图片
可以看到,ORB算法在设置一定参数后,找到了三个高度匹配的特征点对,通过人眼观察可以判断这些匹配特征点是正确匹配的。也就是说,对于一幅放大且旋转了的模板图,ORB算法也能够提取出效果比较好的特征点。

如果我们不进行匹配,而是想知道特征点的分布和方向,可以将找到的特征点及其方向完全可视化出来,代码演示如下:

	//绘制每幅图像的关键点
	drawKeypoints(tem, keyPoints_tem, tem, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
	drawKeypoints(test, keyPoints_test, test, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
	//参数flag:DEFAULT:只绘制特征点的坐标点,显示在图像上就是一个个小圆点,每个小圆点的圆心坐标都是特征点的坐标;
	//				  DRAW_OVER_OUTIMG:函数不创建输出的图像, 而是直接在输出图像变量空间绘制, 要求本身输出图像变量是初始化好了;
	//				 NOT_DRAW_SINGLE_POINTS:单独的特征点不被绘制;
	//				 DRAW_RICH_KEYPOINTS:绘制带有方向信息的特征点,用一个带有指向的圆来表示特征点。

	imshow("tem", tem);
	imshow("test", test);

看一下效果图:
OpenCV4学习笔记(41)——ORB特征提取描述算法_第4张图片
效果图中,每个特征点绘制出来都是一个圆,而每个圆都带有一条作为指向的半径。

好了,今天关于ORB特征提取描述算法的记录就到此为止,下次的笔记就基于ORB算法提取出的特征描述子来实现图像中的已知目标检测,下次见啦~

PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!

你可能感兴趣的:(学习笔记,计算机视觉,c++,opencv)