OpenCv-C++-BRISK特徵檢測與匹配
阿新 • • 發佈:2018-12-23
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演算法在其中表現最為出色。