OpenCV实现SIFT特征提取与匹配
前言
本文介紹如何利用OpenCV從兩幅圖像中提取定位精度較高的尺度不變特征變換(SIFT)特征,并結(jié)合特征匹配方法建立兩幅圖像的特征對應(yīng)關(guān)系。
1. 程序架構(gòu)
利用MFC實現(xiàn)了簡易的Demo程序以便交互操作,界面如下所示。首先為兩幅待匹配的圖像選擇正確的路徑,再指定擬提取的特征類型(SIFT、SURF、ORB等),以及特征匹配方法(Brute Force、Flann Based等),隨后點擊“顯示匹配點對”,即可呈現(xiàn)兩幅圖像中經(jīng)過精確匹配的SIFT特征對應(yīng)關(guān)系。此外,還可點擊“保存匹配結(jié)果”,將匹配得到的SIFT點對的像素坐標(biāo),以文件形式保存至指定路徑。
2. 特征提取
2.1. 讀取圖像
(1)從MFC EditBrowse Control控件中讀取圖像文件的路徑;
CString selectedPath1, selectedPath2; GetDlgItemText(IDC_MFCEDITBROWSE_Image1, selectedPath1); GetDlgItemText(IDC_MFCEDITBROWSE_Image2, selectedPath2);(2)將CString類型的文件路徑轉(zhuǎn)為cv::String類型,作為imread函數(shù)的輸入?yún)?shù);
USES_CONVERSION; cv::String cvStr1 = W2A(selectedPath1); cv::String cvStr2 = W2A(selectedPath2); Mat img1 = imread(cvStr1); Mat img2 = imread(cvStr2);(3)判斷圖像是否讀取成功,并將彩色圖像轉(zhuǎn)為灰度圖像。
if (img1.data == NULL || img2.data == NULL) {MessageBox(_T("Reading error"));return; }if (img1.channels() > 1) {cvtColor(img1, img1, COLOR_BGR2GRAY); }if (img2.channels() > 1) {cvtColor(img2, img2, COLOR_BGR2GRAY); }2.2. 檢測關(guān)鍵點
利用Opencv提供的SIFT檢測函數(shù),提取兩幅圖像中各自包含的關(guān)鍵點;
Ptr<SIFT> sift = SIFT::create(); vector<KeyPoint> keypoints1, keypoints2; sift->detect(img1, keypoints1); sift->detect(img2, keypoints2);2.3. 計算描述符
依據(jù)每幅圖像的關(guān)鍵點信息,計算對應(yīng)的描述符。
Mat descriptors1, descriptors2; sift->compute(img1, keypoints1, descriptors1); sift->compute(img2, keypoints2, descriptors2);3. 特征匹配
(1)結(jié)合從兩幅圖像中提取的關(guān)鍵點和描述符,尋找粗略匹配的SIFT點對;
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("FlannBased"); vector<vector<DMatch> > matchPoints; vector<Mat> trainDesc(1, descriptors1); matcher->add(trainDesc); matcher->train(); matcher->knnMatch(descriptors2, matchPoints, 2);(2)利用Lowe提出的誤匹配篩選方法,即當(dāng)候選匹配點對的最小距離小于次小距離的0.6倍時,才認為它們是正確匹配;
int trainIndex, queryIndex; vector<DMatch> candiMatchPoints; vector<Point2f> candiPts1, candiPts2; vector<KeyPoint> candiKeyPts1, candiKeyPts2; for (int i = 0; i < matchPoints.size(); i++) {if (matchPoints[i][0].distance < 0.6 * matchPoints[i][1].distance){candiMatchPoints.push_back(matchPoints[i][0]);trainIndex = matchPoints[i][0].trainIdx;queryIndex = matchPoints[i][0].queryIdx;candiKeyPts1.push_back(keypoints1[trainIndex]);candiKeyPts2.push_back(keypoints2[queryIndex]);candiPts1.push_back(keypoints1[trainIndex].pt);candiPts2.push_back(keypoints2[queryIndex].pt);} }(3)采用隨機抽樣一致方法進一步剔除誤匹配點對;
vector<uchar> ransacStatus; Mat funMat = findFundamentalMat(candiPts1, candiPts2, ransacStatus, FM_RANSAC);(4)記錄最終得到的正確匹配點對,以供顯示和保存。
int index = 0; vector<Point2f> matchPts1, matchPts2; vector<DMatch> goodMatchPoints; vector<KeyPoint> goodKeyPts1, goodKeyPts2; for (int i=0; i<candiMatchPoints.size(); i++) {if (ransacStatus[i] != 0){goodKeyPts1.push_back(candiKeyPts1[i]);goodKeyPts2.push_back(candiKeyPts2[i]);candiMatchPoints[i].queryIdx = index;candiMatchPoints[i].trainIdx = index;goodMatchPoints.push_back(candiMatchPoints[i]);matchPts1.push_back(candiKeyPts1[i].pt);matchPts2.push_back(candiKeyPts2[i].pt);index++;} }4. 結(jié)果顯示
在兩幅圖像中顯示特征匹配且剔除誤匹配之后的結(jié)果。
Mat img; drawMatches(img1, goodKeyPts1, img2, goodKeyPts2, goodMatchPoints, img); namedWindow("SIFT + Flann Based", 0); resizeWindow("SIFT + Flann Based", 1600, 600); imshow("SIFT + Flann Based", img); waitKey(0);5. 圖像測試
將手機從不同角度拍攝的兩張圖像導(dǎo)入程序,得到特征提取和匹配結(jié)果如下所示,可以看到兩種視角下的特征點對應(yīng)關(guān)系比較準(zhǔn)確。
(1)兩幅圖像的特征匹配關(guān)系:
(2)保存特征點對的像素坐標(biāo):
6. 參考資料
[1] D. G. Lowe. Distinctive image features from scale-invariant keypoints. International Journal of Computer Vision, 60: 91-110 (2004).
[2] SIFT原理參考:https://blog.csdn.net/zddblog/article/details/7521424
[3] OpenCV代碼實現(xiàn)參考:https://blog.csdn.net/hellohake/article/details/104930117
總結(jié)
以上是生活随笔為你收集整理的OpenCV实现SIFT特征提取与匹配的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AB相位编码器角度与速度计算
- 下一篇: vscode让html文件保存自动刷新浏