前言
在提取了影象的特徵點,並形成特徵描述子後,我們往往需要對兩張(本質上是兩個mat)進行特徵點匹配·,opencv提供的匹配方法有兩種,分別是flann以及暴力匹配。暴力匹配思路最為簡單,就是圖1的乙個特徵描述子a,與圖2的所有特徵描述子均進行一次距離計算(一般為歐氏距離),距離最小的點即為a點在圖2的匹配點。flann我沒有詳細的了解,據說是基於概率的思想,只找到乙個差不多相近的點,而不是距離最近的點。暴力匹配雖然精準,但是慢,另外,也會出現一定數量的錯誤匹配點。為盡可能地剔除錯誤匹配點,2nn演算法應運而生。
什麼是2nn?
2nn演算法全稱是 two neareast neighbour ,即兩個與目標點最相近的點。2nn演算法通過衡量最近距離,與次近(第二接近)距離的比值,來判斷該點是否為匹配點,具體公式如下
換句話說,現在不僅僅要求兩個關鍵點之間的距離最近,同時還要求最近的點與次近的點不能太相似(兩者比值越接近1,約相似嘛),滿足了這個條件,我們才說這兩個點是匹配的。
但為什麼這樣做會有效呢?
我的理解是「設定了一定的區分度」,舉例來說,特徵點a的最近特徵點為b(候選特徵點),此近特徵點為c,如果a-b的距離跟a-c的距離差不多,那麼究竟是b是特徵點,還是c是特徵點呢?在這種模稜兩可的情況下,演算法很可能就會產生了錯配。2nn演算法很好地結局兩者之間的關係,如果兩者很像,說明c也很可能是a的匹配點,那你憑什麼選擇b呢?所以就乾脆b也不選了吧!!!杜絕一切風險!!!
相關模版類
keypoint類
這是opencv中用來儲存關鍵點的乙個模版
class keypoint
dmatch類
這是opencv用來儲存匹配好一對關鍵點,原型為:
class cv_exports_w_****** dmatch
;
每乙個dmatch物件儲存的是一對匹配好的特徵點的資訊,那儲存了什麼資訊呢?
2nn的**實現
void twonn_matcher(vector& matches, mat des1, mat des2, const float min_ration)
cout << "k_matches:" << k_matches.size() << endl; //測試用的
cout << "matches:" << matches.size() << endl;
}
opencv中knnmatch()方法可以返回k個最近的特徵點,2nn中我們就設定為2,應該注意的是,匹配結果應該儲存在
std::vectork_matches;而不是std::vector ,這也很好理解,乙個關鍵點有最近跟次近兩個點嘛。
實驗結果
直接暴力匹配
使用2nn:
可見,使用2nn能有效地消除錯誤匹配點
閾值對關鍵點數量的影響
在2nn中,我們需要乙個閾值來衡量最近距離與次近距離的關係,那這個閾值對匹配特徵數目有什麼影響嗎?
在上圖中,暴力匹配獲得的匹配特徵點為779對
在使用2nn後,我分別使用了0.6666,0.6,0.3,以及0.8
實驗結果為163、126、22、246。可見,閾值設定越接近1,找到的匹配點越多(有可能使是錯的匹配點),反之越少。
SIFT特徵檢測 最近鄰近似匹配 2NN優化
import math from matplotlib import pyplot as plt import matplotlib matplotlib inline book l cv2.imread images book l.png book r cv2.imread images book...
OpenCV2簡單的特徵匹配
特徵的匹配大致可以分為3個步驟 特徵的提取 計算特徵向量 特徵匹配 對於3個步驟,在opencv2中都進行了封裝。所有的特徵提取方法都實現featuredetector介面,descriptorextractor介面則封裝了對特徵向量 特徵描述符 的提取,而所有特徵向量的匹配都繼承了descript...
OpenCV2簡單的特徵匹配
特徵的匹配大致可以分為3個步驟 特徵的提取 計算特徵向量 特徵匹配 對於3個步驟,在opencv2中都進行了封裝。所有的特徵提取方法都實現featuredetector介面,descriptorextractor介面則封裝了對特徵向量 特徵描述符 的提取,而所有特徵向量的匹配都繼承了descript...