OpenCV4學習筆記(46)——特徵提取與描述之AKAZE特徵提取描述算法

在之前的筆記《OpenCV4學習筆記(38)》中,整理記錄了我本人對於經典特徵算法——SIFT算法一些流程的理解,而今天要整理的是SIFT算法的其中一種改進算法,也即AKAZE特徵算法。

AKAZE特徵算法是SIFT特徵算法的一種改進版本,但不使用高斯模糊來構建尺度空間,因爲高斯模糊具有丟失邊緣信息的缺點,進而採用非線性擴散濾波來構建尺度空間,從而保留圖像更多的邊緣特徵。

在特徵點提取階段,AKAZE算法採用與SIFT算法類似的提取特徵點方式,即在同一金字塔層內的不同尺度的一組圖像中尋找最大特徵點。

然後在特徵描述子生成階段,採用與ORB特徵算法類似的方法生成描述子(可參閱《OpenCV4學習筆記(40)》),但ORB算法中採用LDB特徵描述算法來生成特徵描述子,而AKAZE採用 M-LDB特徵描述算法來生成描述子,使得最終得到的特徵具有旋轉不變性。M-LDB特徵描述算法是基於LDB特徵描述算法並針對圖像的旋轉和縮放進行改進,相比LDB具有旋轉不變性和尺度不變性,進一步提高了特徵的魯棒性。

通過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特徵提取和描述,然後將兩幅圖像的特徵進行匹配,從而得到兩幅圖像之間高度匹配的特徵點,進而定位出模板圖像中的目標物體在待檢測圖像中的位置。

下面是演示效果圖:
在這裏插入圖片描述
拿自己腦袋做樣本。。。不說啥了。。。
ε=ε=ε=┏(゜ロ゜;)┛

好的那本次筆記到此結束~

PS:本人的註釋比較雜,既有自己的心得體會也有網上查閱資料時摘抄下的知識內容,所以如有雷同,純屬我向前輩學習的致敬,如果有前輩覺得我的筆記內容侵犯了您的知識產權,請和我聯繫,我會將涉及到的博文內容刪除,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章