python opencv之SIFT演算法樣本,opencvsift
本文介紹了python opencv之SIFT演算法樣本,分享給大家,具體如下:
目標:
學習SIFT演算法的概念
學習在映像中尋找SIFT關鍵的和描述符
原理:
(原理部分自己找了不少文章,內容中有不少自己理解和整理的東西,為了方便快速理解內容和能夠快速理解原理,本文盡量不使用數學公式,僅僅使用文字來描述。本文中有很多引用別人文章的內容,僅供個人記錄使用,若有錯誤,請指正出來,萬分感謝)
之前的harris演算法和Shi-Tomasi 演算法,由於演算法原理所致,具有旋轉不變性,在靶心圖表片發生旋轉時依然能夠獲得相同的角點。但是如果對映像進行縮放以後,再使用之前的演算法就會檢測不出來,原理用一張圖表示(圖1):
(harris演算法和shi-tomasi演算法都是基於視窗中像素分布和變化的原理,在映像放大且視窗大小不發生變化的時,視窗中的像素資訊則會有很大的不同,造成無法檢測的結果)
SIFT特性:
- 獨特性,也就是特徵點可分辨性高,類似指紋,適合在海量資料中匹配。
- 多量性,提供的特徵多。
- 高速性,就是速度快。
- 可擴充,能與其他特徵向量聯合使用。
SIFT特點:
- 旋轉、縮放、平移不變性
- 解決映像仿射變換,投影變換的關鍵的匹配
- 光照影響小
- 目標遮擋影響小
- 雜訊景物影響小
SIFT演算法步驟:
- 尺度空間極值檢測
- 關鍵點定位
- 關鍵點方向參數
- 關鍵點描述符
- 關鍵點匹配
尺度空間極值檢測:
尺度空間的個人理解:
你找一張解析度1024×1024圖片,在電腦上觀看,十分清晰,但是圖片太大。現在把這圖片反正photoshop上,將解析度改成512×512,圖片看著依然很清晰,但是不可能像1024×1024的畫面那麼精細,只不過是因為人眼構造的原因,512×512圖片依然能讓你分辨出這是個什麼東西。
粗俗點說,尺度空間,就相當於一個圖片需要獲得多少解析度的量級。如果把一個圖片從原生解析度到,不停的對其解析度進行減少,然後將這些圖片摞在一起,可以看成一個四稜錐的樣式,這個東西就叫做影像金字塔(如,圖2)。
再回到尺度空間,在網路攝影機中,電腦無法分辨一個景物的尺度資訊。而人眼不同,除了人大腦裡已經對物體有了基本的概念(例如正常人在十幾米外看到蘋果,和在近距離看到蘋果,都能認出是蘋果)以外,人眼在距離物體近時,能夠獲得物體足夠多的特性,在距離物體遠時,能夠或略細節,例如,近距離看一個人臉能看到毛孔,距離遠了看不到毛孔等等。
在圖片資訊當中,解析度都是固定的,要想得到類似人眼的效果,就要把圖片弄成不同的解析度,製作成影像金字塔來類比人眼的功能,從而在其他圖片中進行特徵識別時,能夠像人眼睛一樣,即使要識別的物體尺寸變大或者變小,也能夠識別出來!
從圖1可以看出,如果如果映像變大,視窗大小還是以前的大小,則無法正確檢測出角點。那麼很自然的就能想到,如果圖片變大,咱們把視窗也放大不就行了? 這就需要上面提到的尺度空間發揮作用。
在SIFT當中,利用了一個叫做高斯核的方程來構建尺度空間,原因是高斯核函數是唯一多尺度空間的核。聽起來比較晦澀,個人理解為:
高斯核函數在之前的高斯濾波當中使用過,其原理就是利用高斯分布的特性,在以某一個點為中心要進行以某一個視窗大小進行模糊的操作。那麼,根據濾波的原理,距離中心像素點位置的距離越遠的像素點,需要“模糊化效果”的值就應該越少。那麼這個距離值的分配方法,就是利用滿足高斯核函數的分配方法,由中心,到四周,符合高斯核函數的“鐘型”曲線(從二維上看)。
那麼尺度空間中的高斯核也可以這麼理解,高斯核函數的參數有三個G(x,y,σ) ,在濾波當中,第三個參數σ在運算中是固定的一個值。而在尺度空間的構造當中,所謂的“尺度”,就是這個σ值變化,而x和y表示像素座標。σ的值越小,映像被平滑(被模糊)的越少,尺度也越小。所以,大尺度圖片可以對應成一個映像離遠處觀看,是個大致輪廓,小尺度圖片可以對應成離近處觀看,有更多細節。
構建尺度空間的目的是為了檢測出在不同的尺度下都存在的特徵點,如此可以獲得縮放不變性
其中利用映像I(x,y)與G(x,y,σ) 進行卷積運算,得到尺度空間L(x,y,σ),可以理解,所謂的“尺度空間”在這裡就是這個函數L(x,y,σ)
如果求取特徵點,可以使用一個叫做拉普拉斯運算元進行運算
但是,由於拉普拉斯運算元的效率太低,再SIFT演算法當中使用差分來代替。
高斯金字塔:
在建立尺度空間後,需要找到關鍵點,此時需要實現高斯金字塔的構造來實現關鍵點的求取。在高斯金字塔當中,“塔”的每一層都是映像,“塔”的高度就是上面提到的尺度σ。“塔”的每一層對應一個σ值,同時將高斯金字塔中的映像分成組,每組當中映像的尺寸相同,但是尺度σ不同。具體尺度之間的計算關係,先忽略,如所示:
高斯差分金字塔DOG:
每一組相鄰當中相鄰兩層的映像做差,得到的映像再“疊”成一個金字塔就是高斯差分金字塔DOG。
DOG局部特徵點檢測:
有了差分金字塔,現在便可以計算關鍵點(特徵點)。由於金字塔的模型不是二維模型,而是一個3D 模型,這裡計算極值的方法也不再是二維求取極值的方法。
計算一個某一個點是否是局部最大值,在離散的三維空間當中,以該點為中心,檢測它周圍的點。類似魔方的中心位置一樣,如中的“叉”就是待計算是否是局部極值點。
這裡說明,局部極值點都是在同一個組當中進行的,所以肯定有這樣的問題,某一組當中的第一個圖和最後一個圖層沒有前一張圖和下一張圖,那該怎麼計算? 解決辦法是,在用高斯模糊,在高斯金字塔多“模糊”出三張來湊數,所以在DOG中多出兩張。
關鍵點定位:
上面找到的關鍵點要進行處理,去除一些不好的特徵點,儲存下來的特徵點能夠滿足穩定性等條件。
主要是去掉DOG局部曲率非常不對稱的像素。
因為低對比的特徵點和邊界點對光照和雜訊變化非常敏感,所以要去掉。利用閾值的方法來限制,在opencv中為contrastThreshold。
去除低對比的特徵點:
使用泰勒公式對DOG函數空間進行擬合,去掉小於修正閾值的關鍵點。
去除不穩定的邊界點:
利用Hessian矩陣(就是求導數的矩陣),利用邊緣梯度的方向上主曲率值比較大,而沿著邊緣方向則主曲率值較小的原理,將主曲率限制為某個值。滿足該值條件的點留下,反之去除。
關鍵點設定方向參數:
每個關鍵點設定方向以後可以獲得旋轉不變性。
擷取關鍵點所在尺度空間的鄰域,然後計算該地區的梯度和方向,根據計算得到的結果建立方向長條圖,長條圖的峰值為主方向的參數,其他高於主方向百分之80的方向被判定為輔助方向,這樣設定對穩定性有很大協助。
關鍵點描述符:
經過上面的步驟計算,每個關鍵點有三個資訊,位置、尺度、方向。所以具備平移、縮放、和旋轉不變性。
接下來對每個關鍵點用一組向量將這個關鍵點描述出來,使其不隨著光照、視角等等影響而改變。該描述符不但涉及關鍵點,而且還涉及到關鍵點周圍的像素,使其有更強的不變特性。
基本原理是選取關鍵點周圍16×16的像素地區,分成4個小塊,每個小塊建立8個bin的長條圖,這總共的128個資訊的向量就是關鍵點描述符的主要內容。此外還要測量,以達到光照、旋轉的穩定性。
關鍵點匹配:
分別對模板圖和即時圖建立關鍵點描述符集合,通過對比關鍵點描述符來判斷兩個關鍵點是否相同。128個資訊的向量使用歐氏距離來實現。
在關鍵點的匹配當中,使用的搜尋演算法為地區搜尋演算法當中最常用的k-d樹實現。
比較之後,需要在進行消除錯配點才算完成。
OpenCV 中的 SIFT:
關於opencv版本與SIFT演算法不能調用的問題:
SIFT演算法是一個有專利的演算法,在商業用途上是收費的。對於窮B學生,演算法的發明者還比較仁慈,可以使用。
不過,在python當中使用SIFT演算法和版本之間有不少關係,來源文件當中使用opencv版本是2.4.9版本,此版本可以隨意使用SIFT演算法。
但是,在opencv3當中就沒那麼幸運了,opencv中的很多特徵點提取演算法都和cv2中的庫分離開,必須要添加opencv-contrib才可以使用,本人使用的opencv版本是3.3.0,幾乎是最新的版本。
網上有一大堆教程關於如何在opencv當中如何添加opencv-contrib的教程,使用cmake,使用vs,啥的非常麻煩。
本人狗急跳牆,尋思在pip上面有沒有啥第三方的庫可以直接就將opencv-contrib這個庫。
結果,還真找到了 哈哈。
這下方便了,只要在你的控制台當中輸入
pip install opencv-contrib-python即可
如果pip安裝不上去
直接上官方上面下個輪子,然後pip安裝就能用了
網站在此!!!
import cv2import numpy as npimg = cv2.imread('1.jpg')gray= cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)sift = cv2.xfeatures2d.SIFT_create()kp = sift.detect(gray,None)#找到關鍵點img=cv2.drawKeypoints(gray,kp,img)#繪製關鍵點cv2.imshow('sp',img)cv2.waitKey(0)
返回的關鍵點是一個帶有很多不用屬性的特殊結構體,屬性當中有座標,方向、角度等等。
計算關鍵點描述符:
使用sift.compute()函數來進行計算關鍵點描述符
kp,des = sift.compute(gray,kp)
如果未找到關鍵點,可使用函數sift.detectAndCompute()直接找到關鍵點並計算。
在第二個函數中,kp為關鍵點列表,des為numpy的數組,為關鍵點數目×128
sift = cv2.xfeatures2d.SIFT_create()kp, des = sift.detectAndCompute(gray,None)
結果
以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。