1. 程式人生 > >OpenCv-C++-BRISK特徵檢測與匹配

OpenCv-C++-BRISK特徵檢測與匹配

BRISK:Binary Robust Invariant Scalable Keypoints。它是一種二進位制的特徵描述運算元。它具有較好的旋轉不變性、尺度不變性,較好的魯棒性等。在對有較大模糊的影象配準時,BRISK演算法在其中表現最為出色。

演算法原理參考下面這篇文章,其中的表達描述的很清楚。
參考文章:https://blog.csdn.net/hujingshuang/article/details/47045497

特徵檢測與步驟:
1、構建尺度空間-------->高斯金字塔構建;
2、特徵點檢測;
3、FAST9-16尋找特徵點----------->連續9個點大於或小於當前值都被視為特徵點;
4、特徵點定位;
5、關鍵點描述子。

大體上來說,只要是涉及特徵點尋找的,都要保持旋轉不變性,尺度不變性,光照強度不變性等。只需要解決以上問題,特徵點的檢測就較為準確。

程式碼部分:

#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

using namespace cv;
using namespace std;


int main(int argc, char**argv)
{
	Mat img1 = imread("D:/test/box.png",IMREAD_GRAYSCALE);
	Mat img2 = imread("D:/test/box_in_scene.png", IMREAD_GRAYSCALE);
	if (!img1.data || !img2.data)
	{
		cout << "圖片未找到!!!" << endl;
		return -1;
	}
	imshow("img1_box", img1);
	imshow("img2_scene", img2);
	//用Brisk演算法去檢測特徵點
	vector<KeyPoint> keypoint_obj;
	vector<KeyPoint> keypoint_scene;
	double t1 = getTickCount();//計算執行時間

	Ptr<Feature2D> detect = BRISK::create();
	Mat desciptor_obj, descriptor_scene;
	//檢測並計算描述子
	detect->detectAndCompute(img1, Mat(), keypoint_obj, desciptor_obj);
	detect->detectAndCompute(img2, Mat(), keypoint_scene, descriptor_scene);

	double t2 = getTickCount();
	double t = (t2 - t1) * 1000 / getTickFrequency();
	//匹配描述子,這裡使用FLANN匹配,也可以使用(BF)暴力匹配
	vector<DMatch> matches;
	FlannBasedMatcher fbmatcher(new flann::LshIndexParams(20, 10, 2));
	//匹配描述子
	fbmatcher.match(desciptor_obj, descriptor_scene, matches);
	vector<DMatch> goodmatches;//找到最優匹配點
	double minDist = 1000;
	double maxDist = 0;//初始化
	
	for (int i = 0; i < desciptor_obj.rows; i++)
	{
		double dist = matches[i].distance;
		if (dist > maxDist)
		{
			maxDist = dist;
		}
		if (dist < minDist)
		{
			minDist = dist;
		}


	}
	for (int i = 0; i < desciptor_obj.rows; i++)
	{
		double dist = matches[i].distance;
		//比最小距離還小的就是最優匹配點
		if (dist < max(2 * minDist, 0.02))
		{
			goodmatches.push_back(matches[i]);

		}
	}
	Mat resultImg;
	drawMatches(img1, keypoint_obj, img2, keypoint_scene, goodmatches, resultImg,
		Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
	imshow("BRISK Matches demo",resultImg);
	printf("BRISK 執行時間為(ms):%f",t);

	//使用透視矩陣畫出匹配物體
	vector<Point2f> obj;
	vector<Point2f> scene_in_obj;
	
	for (size_t i= 0; i < goodmatches.size(); i++) 
	{
		obj.push_back(keypoint_obj[goodmatches[i].queryIdx].pt);
		scene_in_obj.push_back(keypoint_scene[goodmatches[i].trainIdx].pt);

	}
	//生成透視矩陣
	Mat H = findHomography(obj, scene_in_obj, RANSAC);

	vector<Point2f>obj_corner(4);
	vector<Point2f>scene_corner(4);
	obj_corner[0] = Point(0, 0);
	obj_corner[1] = Point(img1.cols, 0);
	obj_corner[2] = Point(img1.cols,img1.rows);
	obj_corner[3] = Point(0, img1.rows);

	//透視變換
	perspectiveTransform(obj_corner, scene_corner, H);
	Mat pptfImg = resultImg.clone();
	line(pptfImg, scene_corner[0] + Point2f(img1.cols, 0), scene_corner[1] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
	line(pptfImg, scene_corner[1] + Point2f(img1.cols, 0), scene_corner[2] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
	line(pptfImg, scene_corner[2] + Point2f(img1.cols, 0), scene_corner[3] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
	line(pptfImg, scene_corner[3] + Point2f(img1.cols, 0), scene_corner[0] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
	imshow("pptfImg demo",pptfImg);

	waitKey(0);
	return 0;

}

執行結果:
在這裡插入圖片描述

在這裡插入圖片描述

演算法執行效率:
在這裡插入圖片描述

可以看到,BRISK演算法的執行效率大概在3秒左右,上一篇文章所提到的KAZE大概在2秒左右,AKAZE則更少,雖然BRISK效率慢了點,但是在影象配準應用中,速度比較:SIFT<SURF<BRISK<FREAK<ORB,在對有較大模糊的影象配準時,BRISK演算法在其中表現最為出色。