OpenCV4学习笔记(41)——基于ORB特征提取描述算法的已知目标检测

在上次的笔记《OpenCV4学习笔记(40)》中,整理记录了关于ORB特征提取描述算法的一些使用方式,而今天正是要基于ORB算法来实现对图像中已知目标的检测。

实现步骤如下:

1、使用ORB特征提取描述算法来分别计算检测目标的模板图像和包含目标的待检测图像的特征描述子,要注意这一步骤非常重要,会影响到后续最佳匹配特征点对的获取;

2、通过暴力匹配算法来比对模板图像和待检测图像的特征描述子,并将两幅图像中的对应匹配的特征点对关联起来;

3、寻找对应特征点对中匹配程度比较高的那一部分点对,也就是我们所需要的最佳匹配特征点对;

4、利用最佳匹配特征点对中分别属于模板图像和待检测图像的两部分点集,来求取两部分点集之间的映射关系,也就是求取最佳匹配特征点坐标从模板图像变换到待检测图像时的变换矩阵;

5、将模板图像的四个边框点坐标,利用上面求得的变换矩阵,变换到待检测图像中的点坐标,这四个点连接起来所包围的区域就是目标存在于待检测图像中的区域。从而实现对已知目标的检测。

在第4步骤中,我们需要使用Mat H = findHomography()来获取两个平面坐标之间的变换矩阵,这个API在图像透视变换中也曾经使用过,其参数含义如下:
(1)参数srcPoints:原平面的坐标矩阵;
(2)参数dstPoints:目标平面的坐标矩阵;
(3)参数method:计算变换矩阵的方式,有以下几种可选方式:
默认方式: 0 - 利用所有点的常规方法
RANSAC - 基于RANSAC的鲁棒算法(常用)
LMEDS - 最小中值鲁棒算法
RHO - 基于PROSAC的鲁棒算法(常用)
(4)后续几个参数都是RANSAC和RHO两种方式的计算参数,直接设置为默认值即可;
(5)参数confidence:置信度,默认值0.99即可。

在第5步骤中,进行两个平面、也就是从模板图像的矩形顶点坐标映射到待检测图像中的检测框顶点坐标时,需要使用perspectiveTransform()这个API来实现,也就是进行透视变换,其参数含义为:

(1)参数src:输入的原平面坐标
(2)参数dst:输出的目标平面坐标
(3)参数m:两个平面坐标之间的变换矩阵,也就是上面得到的矩阵H。

下面看一下具体的代码演示:

	//读取模板图像和待检测图像
	Mat tem = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\tem.jpg");
	resize(tem, tem, Size(160,120));
	Mat test = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\miao.jpeg");
	resize(test, test, Size(600, 800));

	//分别对模板图像和待检测图像进行特征点提取和描述
	auto orb = ORB::create(500, 1.01, 20, 31, 0, 2, ORB::HARRIS_SCORE, 31, 20);
	vector<KeyPoint> keyPoints_tem, keyPoints_test;
	Mat descriptors_tem, descriptors_test;
	orb->detectAndCompute(tem, Mat(), keyPoints_tem, descriptors_tem);
	orb->detectAndCompute(test, Mat(), keyPoints_test, descriptors_test);

	if (0 == keyPoints_tem.size())
	{
		cout << "提取不到特征点" << endl;
		return 0;
	}

	//通过特征描述子匹配器,来计算两个描述子之间的匹配关系;输出的matches中每一个元素都包含一组对应特征点的信息
	auto matcher = DescriptorMatcher::create(DescriptorMatcher::MatcherType::BRUTEFORCE);
	vector<DMatch> matches;
	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> goodMatches;
	//判断是否为最佳匹配特征点的阈值;0.2~0.4左右,如果阈值过大会包含太多匹配错误的点,太小又会影响原图像和目标图像之间变换矩阵的计算
	float thresh = 0.35;			
	for (int j = 0; j < matches.size(); j++)
	{
		if (matches[j].distance < thresh * maxdist)
		{
			goodMatches.push_back(matches[j]);
		}
	}

	if (0 == goodMatches.size())
	{
		cout << "不存在最佳匹配特征点" << endl;
		return 0;
	}

	//将两幅图像之间的最佳匹配的对应特征点使用连线绘制出来,输出结果是将两幅图像拼接起来再进行对应特征点连线的图像
	Mat result;
	drawMatches(tem, keyPoints_tem, test, keyPoints_test, goodMatches, result, Scalar::all(-1), Scalar::all(-1));

	//将最佳匹配特征点集中属于模板图像和待检测图像的两部分点集分别用向量表示
	vector<Point2f> tem_point, test_point;
	for (int k = 0; k < goodMatches.size(); k++)
	{
		tem_point.push_back(keyPoints_tem[goodMatches[k].queryIdx].pt);
		//queryIdx:该最佳匹配特征点对中模板图像特征点在模板图像特征点集中的索引
		test_point.push_back(keyPoints_test[goodMatches[k].trainIdx].pt);
		//trainIdx:该最佳匹配特征点对中待检测图像特征点在待检测图像特征点集中的索引
		//keyPoints.pt  :返回该关键点的Point2f类型坐标
	}

	//计算模板图像和待检测图像之间的最佳匹配特征点的变换矩阵;计算两个平面之间的坐标变换矩阵
	Mat H = findHomography(tem_point, test_point, RHO);
	//参数srcPoints:原平面的坐标矩阵
	//参数dstPoints:目标平面的坐标矩阵
	//参数method:计算变换矩阵的方式,有以下几种可选方式:
	//																							默认方式   0 - 利用所有点的常规方法
	//																							RANSAC - 基于RANSAC的鲁棒算法(常用)
	//																							LMEDS - 最小中值鲁棒算法
	//																							RHO   - 基于PROSAC的鲁棒算法(常用)
	//后续几个参数都是RANSAC和RHO两种方式的计算参数,直接设置为默认值即可;
	//参数confidence:置信度,默认值0.99即可。

	//获取模板图像的边框坐标点,也就是需要检测的目标所在矩形范围
	vector<Point2f>tem_local_pt(4);
	tem_local_pt[0] = Point2f(0, 0);
	tem_local_pt[1] = Point2f(tem.cols, 0);
	tem_local_pt[2] = Point2f(tem.cols, tem.rows);
	tem_local_pt[3] = Point2f(0, tem.rows);

	//将模板图像中目标所在的区域范围坐标,透视变换到待检测图像中的区域范围坐标,该区域即是检测到的目标所在位置
	vector<Point2f>test_target_pt(4);
	perspectiveTransform(tem_local_pt, test_target_pt, H);			
	//参数src:输入的原平面坐标
	//参数dst:输出的目标平面坐标
	//参数m:两个平面坐标之间的变换矩阵

	//绘制目标所在区域;由于在拼接图像上绘制,所以区域坐标整体右移一个模板图像的宽度
	for (int n = 0; n < 4;n++)
	{
		line(result, test_target_pt[n % 4] + Point2f(tem.cols, 0) , test_target_pt[(n + 1) % 4] + Point2f(tem.cols, 0), Scalar(0, 255, 0), 1, LINE_AA, 0);
	}
	imshow("result", result);

下面是演示所使用的模板图像和待检测图像:
在这里插入图片描述
在这里插入图片描述
注意这里的模板图像是从测试图像中裁剪下来,并且经过了放缩的,其尺寸发生了一点变化。

然后通过ORB算法的特征提取和描述,并且寻找高度匹配特征点对后,找到在待检测图像中目标存在的位置,效果如下:
在这里插入图片描述

可见,我们将猫猫的脑袋比较准确的寻找了出来并且用矩形框标注,所以当有一个已知的目标,而且需要在其他图像中寻找是否存在该目标时,可以通过这种特征检测的方式来进行寻找。当然了,也可以通过其他特征检测算法来进行寻找,后续在做记录吧。今天的笔记就到此为止啦。

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

发布了49 篇原创文章 · 获赞 71 · 访问量 5139

猜你喜欢

转载自blog.csdn.net/weixin_45224869/article/details/105493000