数字图像处理学习笔记(三):ORB算法(尺度不变特征变换)Oriented FAST and Rotated BRIEF
數字圖像處理學習筆記(三):ORB算法(尺度不變特征變換)Oriented FAST and Rotated BRIEF
一、概述
參考:特征點匹配+特征檢測方法匯總
ORB的全稱是Oriented FAST and Rotated BRIEF,是目前來說非常好的能夠進行的實時的圖像特征提取和描述的算法,它改進了FAST特征提取算法,并使用速度極快的二進制描述子BRIEF。
針對FAST特征提取的算法的一些確定,ORB也做了相應的改進。
- 使用非最大值抑制,在一定區域內僅僅保留響應極大值的角點,避免FAST提取到的角點過于集中。
- FAST提取到的角點數量過多且不是很穩定,ORB中可以指定需要提取到的角點的數量N,然后對FAST提取到的角點分別計算Harris響應值,選擇前N個具有最大響應值的角點作為最終提取到的特征點集合。
- FAST提取到的角點不具有尺度信息,在ORB中使用圖像金字塔,并且在每一層金字塔上檢測角點,以此來保持尺度的不變性。
- FAST提取到的角點不具有方向信息,在ORB中使用灰度質心法(Intensity Centroid)來保持特征的旋轉不變性。
FAST-12算法:
添加預測試操作,于每個像素,直接檢測在鄰域圓上的第1,5,9,13個像素的亮度,只有當這四個像素當中有三個同時大于IP+T或者小于IP-T的時候,當前像素才有可能是是角點。
- 問題1:FAST特征點的數量很多,并且不是確定,而大多數情況下,我們希望能夠固定特征點的數量。
解決方法:在ORB當中,我們可以指定要提取的特征點數量。對原始的FAST角點分別計算Harris的響應值,然后選取前N個點具有最大相應值的角點,作為最終角點的集合。
- 問題2:FAST角點不具有方向信息和尺度問題。
解決方法:尺度不變性構建的圖像的金字塔,并且從每一層上面來檢測角點。旋轉性是由灰度質心法實現。
灰度質心法:質心是指以圖像塊灰度值作為權重的中心。(目標是為了找到方向)
1)在一個小的圖像塊B中,定義圖像塊的矩為:
2)通過矩找到圖像塊的質心
3)連接圖像塊的幾何中心o與質心C,得到一個oc的向量,把這個向量的方向定義特征點的方向
OpenCV提供了兩種Matching方式:
? Brute-force matcher (cv::BFMatcher)1)暴力方法找到點集1中每個descriptor在點集2中距離最近的descriptor;找尋到的距離最小就認為匹配
2)浮點描述子-歐氏距離;二進制描述符-漢明距離。
3)詳細描述:在第一幅圖像中選取一個關鍵點然后依次與第二幅圖像的每個關鍵點進行(描述符)距離測試,最后返回距離最近的關鍵點
1)快速最近鄰搜索算法尋找(用快速的第三方庫近似最近鄰搜索算法)
2)是一個對大數據集和高維特征進行最近鄰搜索的算法的集合,在面對大數據集時它的效果要好于BFMatcher。
3)使用FLANN匹配需要傳入兩個字典參數:
-
一個參數是IndexParams,對于SIFT和SURF,可以傳入參數index_params=dict(algorithm=FLANN_INDEX_KDTREE, trees=5)。
對于ORB,可以傳入參數
index_params=dict(algorithm=FLANN_INDEX_LSH, table_number=6, key_size=12, multi_probe_level=1)。 -
第二個參數是SearchParams,可以傳入參數search_params=dict(checks=100),它來指定遞歸遍歷的次數,值越高結果越準確,但是消耗的時間也越多。
如下所示:
-
normType:它是用來指定要使用的距離測試類型,默認值為cv2.Norm_L2,這很適合SIFT和SURF等(c2.NORM_L1也可)。對于使用二進制描述符的ORB、BRIEF和BRISK算法等,要使用cv2.NORM_HAMMING,
這樣就會返回兩個測試對象之間的漢明距離。如果ORB算法的參數設置為WTA_K==3或4,normType就應該設置成cv2.NORM_HAMMING2。 -
crossCheck:默認值為False。如果設置為True,匹配條件就會更加嚴格,只有到A中的第i個特征點與B中的第j個特征點距離最近,并且B中的第j個特征點到A中的第i個特征點也是最近時才會返回最佳匹配(i,j),
即這兩個特征點要互相匹配才行。
BFMatcher對象有兩個方法BFMatcher.match()和BFMatcher.knnMatch()。第一個方法會返回最佳匹配。第二個方法為每個關鍵點返回k個最佳匹配,其中k是由用戶設定的。
cv2.drawMatches()來繪制匹配的點,它會將兩幅圖像先水平排列,然后在最佳匹配的點之間繪制直線。
如果前面使用的是BFMatcher.knnMatch(),現在可以使用函數cv2.drawMatchsKnn為每個關鍵點和它的個最佳匹配點繪制匹配線,如果要選擇性繪制就要給函數傳入一個掩模。
特征點的匹配后的優化
特征的匹配是針對特征描述子進行的,上面提到特征描述子通常是一個向量,兩個特征描述子的之間的距離可以反應出其相似的程度,也就是這兩個特征點是不是同一個。
根據描述子的不同,可以選擇不同的距離度量。如果是浮點類型的描述子,可以使用其歐式距離;對于二進制的描述子(BRIEF)可以使用其漢明距離(兩個不同二進制之間的漢明距離指的是兩個二進制串不同位的個數)。
有了計算描述子相似度的方法,那么在特征點的集合中如何尋找和其最相似的特征點,這就是特征點的匹配了。最簡單直觀的方法就是上面使用的:暴力匹配方法(Brute-Froce Matcher),計算某一個特征點描述子與其他所有特征點描述子之間的距離,然后將得到的距離進行排序,取距離最近的一個作為匹配點。這種方法簡單粗暴,其結果也是顯而易見的,通過上面的匹配結果,也可以看出有大量的錯誤匹配,這就需要使用一些機制來過濾掉錯誤的匹配。
-
交叉匹配
針對暴力匹配,可以使用交叉匹配的方法來過濾錯誤的匹配。交叉過濾的思想很簡單,再進行一次匹配,反過來使用被匹配到的點進行匹配,如果匹配到的仍然是第一次匹配的點的話,就認為這是一個正確的匹配。舉例來說就是,假如第一次特征點A使用暴力匹配的方法,匹配到的特征點是特征點B;反過來,使用特征點B進行匹配,如果匹配到的仍然是特征點A,則就認為這是一個正確的匹配,否則就是一個錯誤的匹配。OpenCV中BFMatcher已經封裝了該方法,創建BFMatcher的實例時,第二個參數傳入true即可,BFMatcher bfMatcher(NORM_HAMMING,true)。 -
KNN匹配
K近鄰匹配,在匹配的時候選擇K個和特征點最相似的點,如果這K個點之間的區別足夠大,則選擇最相似的那個點作為匹配點,通常選擇K = 2,也就是最近鄰匹配。對每個匹配返回兩個最近鄰的匹配,如果第一匹配和第二匹配距離比率足夠大(向量距離足夠遠),則認為這是一個正確的匹配,比率的閾值通常在2左右。 -
RANSAC
隨機采樣一致性(RANSAC)可過濾掉錯誤的匹配,該方法利用匹配點計算兩個圖像之間單應矩陣,并分解得到位姿R,t,通過三角測量來得到兩個關聯特征對應的3D點,將3D點按照當前估計的位姿進行投影,也就是重投影,然后利用重投影誤差(觀測到得投影位置(像素坐標)與3D點進行重投影的位置之差)來判定某一個匹配是不是正確的匹配。
OpenCV中封裝了求解單應矩陣的方法findHomography,可以為該方法設定一個重投影誤差的閾值,可以得到一個向量mask來指定那些是符合該重投影誤差的匹配點對(Inliers),以此來剔除錯誤的匹配,
二、示例
openCV處理流程:
1)讀取圖像
2)獲取檢測器的實例
3)在OpenCV3中重新的封裝了特征提取的接口,可統一的使用Ptr detector = FeatureDetector::create()來得到特征提取器的一個實例,所有的參數都提供了默認值,也可以根據具體的需要傳入相應的參數。
4)在得到特征檢測器的實例后,可調用的detect方法檢測圖像中的特征點的具體位置,檢測的結果保存在vector向量中。
5)有了特征點的位置后,調用compute方法來計算特征點的描述子,描述子通常是一個向量,保存在Mat中。
6)得到了描述子后,可調用匹配算法進行特征點的匹配。上面代碼中,使用了opencv中封裝后的暴力匹配算法BFMatcher,該算法在向量空間中,將特征點的描述子一一比較,選擇距離(上面代碼中使用的是Hamming距離)較小的一對作為匹配點。
7)繪制結果
- 漢明距離小于最小距離的兩倍
選擇已經匹配的點對的漢明距離不大于最小距離的兩倍作為判斷依據,如果不大于該值則認為是一個正確的匹配,過濾掉;大于該值則認為是一個錯誤的匹配。
DMatch類存放匹配結果
struct DMatch { int queryIdx; //此匹配對應的查詢圖像的特征描述子索引int trainIdx; //此匹配對應的訓練(模板)圖像的特征描述子索引int imgIdx; //訓練圖像的索引(若有多個)float distance; //兩個特征向量之間的歐氏距離,越小表明匹配度越高。bool operator < (const DMatch &m) const; }; #include <opencv2/opencv.hpp>using namespace cv; using namespace std;int main() {// 0 讀取圖像Mat img1 = imread("F:/C++/2. OPENCV 3.1.0/TEST/w.jpg",1);Mat img2 = imread("F:/C++/2. OPENCV 3.1.0/TEST/e.jpg",1);// 1 初始化特征點和描述子,ORBstd::vector<KeyPoint> keypoints1, keypoints2; // 定義關鍵點(特征點)Mat descriptors1, descriptors2; // 定義描述子Ptr<ORB> orb = ORB::create();// 2 、提取 Oriented FAST 特征點orb->detect(img1, keypoints1);orb->detect(img2, keypoints2);// 3 、根據角點位置計算 BRIEF 描述子orb->compute(img1, keypoints1, descriptors1);orb->compute(img2, keypoints2, descriptors2);// // 4、繪制特征關鍵點. // Mat img_keypoints_1; // Mat img_keypoints_2; // drawKeypoints( img1, keypoints1, img_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT ); // drawKeypoints( img2, keypoints2, img_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DEFAULT ); // // 5、顯示效果圖 // imshow("特征點檢測效果圖1", img_keypoints_1 ); // imshow("特征點檢測效果圖2", img_keypoints_2 );// 6、對兩幅圖像中的BRIEF描述子進行匹配,使用 Hamming 距離// DMatch類存放匹配結果:matches中保存著匹配關系vector<DMatch> matches;// 暴力匹配算法:找到點集1中每個descriptor在點集2中距離(hamming distance)最近的descriptor;找尋到的距離最小就認為匹配BFMatcher bfmatcher(NORM_HAMMING,true);// 匹配函數bfmatcher.match(descriptors1, descriptors2, matches);// 7、匹配對篩選:選擇 hamming距離小于最小距離的兩倍的特征點double min_dist = 1000, max_dist = 0;// 找出所有匹配之間的最大值和最小值for (int i = 0; i < descriptors1.rows; i++){double dist = matches[i].distance;//漢明距離在matches中if (dist < min_dist)min_dist = dist;if (dist > max_dist)max_dist = dist;}// 當描述子之間的匹配大于2倍的最小距離時,即認為該匹配是一個錯誤的匹配。// 但有時描述子之間的最小距離非常小,可以設置一個經驗值作為下限vector<DMatch> good_matches;for (int i = 0; i < descriptors1.rows; i++){if (matches[i].distance <= max(2 * min_dist, 30.0))good_matches.push_back(matches[i]);}// 8、繪制匹配結果Mat img_match;drawMatches(img1, keypoints1, img2, keypoints2, good_matches, img_match);imshow("所有匹配點對", img_match);結果:
總結
以上是生活随笔為你收集整理的数字图像处理学习笔记(三):ORB算法(尺度不变特征变换)Oriented FAST and Rotated BRIEF的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab与ie交互
- 下一篇: C++常见的转义符