Advertisement

OpenCV4学习笔记(46)——特征提取与描述之AKAZE特征提取描述算法

阅读量:

在之前的笔记《OpenCV4学习笔记(38)》中,本人对经典的特征提取算法SIFT的工作原理进行了总结和整理。今天重点介绍了AKAZE特征算法的原理及其与SIFT的不同之处,并对两者在实际应用中的优劣势进行了分析比较。

AKAZE特征算法是一种增强版的SIFT特征算法,在构建尺度空间的过程中并未依赖高斯模糊技术。尽管没有采用高斯模糊来搭建尺度空间这一做法存在一定的局限性——由于其固有的缺陷可能导致信息丢失——因此转而采用了非线性扩散滤波技术来构建这一框架,并以此实现了对图像细节信息的有效捕捉与保留

在特征点识别过程中,AKAZE算法基于相似的策略定位特征点位置。具体而言,在同一金字塔层次的不同尺度下的一组图像中寻找最大特征点的位置和大小参数值。

然后,在特征描述子生成阶段中遵循与ORB(Optical Flow-based Robust Broad)算法相似的方式构建描述子(如需了解更多信息,请参阅《OpenCV4学习笔记(40)》)。然而,在ORB方法中采用了基于LDB(Low-Distortion Boundary)算法构建特征描寫子的方式;而AKAZE则采用了M-LDB(Modified LDB)算法构建特徴描寫子的方式。这种改进使得所提取的图像特性不仅具有旋转不变性而且实现了尺度不变性;相较于仅具备旋转不变性的LDB方法而言,M-L DB通过引入对图像缩放的适应机制,进一步提升了特徵的一致性和可靠性

基于AKAZE特征求取的方法生成了具有旋转抗变性和尺度抗变性的描述子,并具备光照无关性和空间一致性。相较于ORB和SIFT算法提取出的特徵而言,该方法生成的描述子在鲁棒性和独特性的同时具备更高的精度。

AKAZE算法作为一种性能优化版本的KAZE算法,在构建尺度空间方面采用了Fast Explicit Diffusion(FED)技术。由于盒子滤波能够很好地模拟高斯核函数,并且在速度提升方面具有显著优势同时易于实现其核心机制在于重复进行M次迭代每一次循环阶段包含N个显式的扩散步骤其中每个步骤的步长均为非线性变化即为不断调整以适应不同尺度特征提取的需求初始步长则源自于盒子滤波过程中的因式分解原理

虽然其速度有了一定的提升,但是仍然不足以胜任实时处理的需求。

在OpenCV库中已实现了并封装好了基于AKAZE算法的特征检测功能模块。通过调用auto akaze = AKAZE::create();即可方便地获取一个现成的AKAZE特征提取器实例。随后即可执行以下基本操作:首先进行图像特征提取;接着生成描述子;最后完成匹配。请查看下面的演示代码以更好地理解具体应用流程。

复制代码
    	Mat tem_image = imread("D:\ opencv_c++\ opencv_tutorial\ data\ images\ tem.jpg");
    	Mat dected_image = imread("D:\ opencv_c++\ opencv_tutorial\ data\ images\ miao.jpeg");
    	resize(tem_image, tem_image, Size(160,120));
    	resize(dected_image, dected_image, Size(600, 800));
    
    	auto akaze = AKAZE::create();
    	vector<KeyPoint> keyPoints_tem, keyPoints_dected;
    	Mat descriptors_tem, descriptors_dected;
    	akaze->detectAndCompute(tem_image, Mat(), keyPoints_tem, descriptors_tem, false);
    	akaze->detectAndCompute(dected_image, Mat(), keyPoints_dected, descriptors_dected, false);
    
    	auto matcher = DescriptorMatcher::create(DescriptorMatcher::MatcherType::BRUTEFORCE);
    	vector<DMatch> matches;
    	matcher->match(descriptors_tem, descriptors_dected, matches);
    
    	float maxdist = matches[0].distance;
    	for (int i = 0; i < matches.size(); i++)
    	{
    		if (maxdist < matches[i].distance)
    		{
    			maxdist = matches[i].distance;
    		}
    	}
    	float thresh = 0.6;
    	vector<DMatch> good_Matches;
    	vector<Point2f> temPoints, dectedPoints;
    	for (int j = 0; j < matches.size(); j++)
    	{
    		if (matches[j].distance < thresh * maxdist)
    		{
    			good_Matches.push_back(matches[j]);
    			temPoints.push_back(keyPoints_tem[matches[j].queryIdx].pt);
    			dectedPoints.push_back(keyPoints_dected[matches[j].trainIdx].pt);
    		}
    	}
    
    	if (0 == good_Matches.size())
    	{
    	cout << "不存在最佳匹配特征点" << endl;
    	return 0;
    	}
    
    	Mat result;
    	drawMatches(tem_image, keyPoints_tem, dected_image, keyPoints_dected, good_Matches, result, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    
    	Mat H;
    	H = findHomography(temPoints, dectedPoints, RHO);
    	int tem_width = tem_image.cols;
    	int tem_height = tem_image.rows;
    	vector<Point2f> tem_points(4), transform_points(4);
    	tem_points[0] = Point(tem_width, tem_height);
    	tem_points[1] = Point(0, tem_height);
    	tem_points[2] = Point(0, 0);
    	tem_points[3] = Point(tem_width, 0);
    
    	perspectiveTransform(tem_points, transform_points, H);
    
    	for (int k = 0; k < transform_points.size(); k++)
    	{
    		line(result, transform_points[k % 4] + Point2f(tem_width, 0), transform_points[ (k+1) % 4] + Point2f(tem_width, 0), Scalar(0, 255, 0), 1, 8, 0);
    	}
    
    	imshow("result", result);

在给定的代码环境中, 分别从一幅模板图和另一幅待检测图中实现AKAZE算法来提取并描述特征, 接着比较这两副图象的特征以发现它们之间高度相似的关键点位置, 最终确定了目标物体现在位于待检图中的特定位置。

下面是演示效果图:

在这里插入图片描述

拿自己脑袋做样本。。。不说啥了。。。
ε=ε=ε=┏(゜ロ゜;)┛

好的那本次笔记到此结束~

本人的一些笔记较为杂乱,在记录心得体悟的同时也会包含有自己心得体会以及网上查阅资料时摘抄下的知识内容。因此如有雷同之处这纯属我对前辈学习精神的一种致敬。如若有关于我的笔记内容侵犯您知识产权的情况请与我联系以便进行相应的删除处理非常感谢!

本人的一些笔记较为杂乱,在记录心得体悟的同时也会包含有自己心得体会以及网上查阅资料时摘抄下的知识内容。因此如有雷同之处这纯属我对前辈学习精神的一种致敬。如若有关于我的笔记内容侵犯您知识产权的情况请与我联系以便进行相应的删除处理非常感谢!

全部评论 (0)

还没有任何评论哟~