在這一章當中,html
在最後幾章中,咱們看到了一些角落探測器,如哈里斯等。它們是旋轉不變的,這意味着,即便圖像旋轉了,咱們也能夠找到相同的角落。這是顯而易見的,由於角落在旋轉的圖像中也是角落。可是縮放呢?若是圖像縮放,角落可能不是角落。例如,請查看下面的簡單圖片。放大同一個窗口時,小窗口內的小圖像中的一個角落是平坦的。因此哈里斯的角落不是規模不變的。python
所以,2004年,不列顛哥倫比亞大學的D.Lowe在他的論文中提出了一種新的算法 - 尺度不變特徵變換(SIFT),該算法從尺度不變關鍵點獲取特徵圖像特徵,提取關鍵點並計算其描述符。(本文很容易理解,並被認爲是SIFT上最好的資料,因此這個解釋只是本文的一個簡短摘要)。算法
SIFT算法主要涉及四個步驟。咱們將逐一看到他們。數組
從上圖中能夠看出,咱們不能使用相同的窗口來檢測不一樣比例的關鍵點。小角落也行。但要檢測更大的角落,咱們須要更大的窗口。爲此,使用縮放空間濾波。其中,高斯拉普拉斯能夠找到具備各類值的圖像。LoG做爲一個斑點檢測器,能夠檢測因爲變化而產生的各類大小的斑點
。總之,
做爲縮放參數。例如,在上面的圖像中,低的高斯內核
爲小角部提供高值,而高斯內核高度
適合較大的角部。所以,咱們能夠在規模和空間中找到局部最大值,這給咱們一個
值列表,這意味着在(x,y)
規模上存在潛在的關鍵點。函數
可是這個LoG有點貴,因此SIFT算法使用高斯差分,這是LoG的近似值。高斯的差做爲圖像的高斯模糊的用兩種不一樣的差獲得,讓它
和
。這個過程是在高斯金字塔的不一樣八度的圖像中完成的。它在下面的圖像中表示:學習
一旦找到這個DoG,圖像就會在比例和空間上搜索到局部極值。例如,圖像中的一個像素與其8個鄰居以及下一個尺度的9個像素和先前尺度的9個像素相比較。若是它是一個局部極值,這是一個潛在的關鍵點。它基本上意味着這個關鍵點最能體如今這個尺度上。它顯示在下面的圖像中:spa
關於不一樣的參數,給出這能夠歸納爲,八度= 4,等級水平= 5,初始的數目的數目一些經驗數據,
等等做爲最佳值。code
一旦找到潛在的關鍵點位置,就必須對其進行改進以得到更準確的結果。他們使用泰勒級數展開的尺度空間來得到更精確的極值位置,而且若是這個極值的強度小於閾值(根據紙張爲0.03),它將被拒絕。該閾值在OpenCV中稱爲contrastThresholdhtm
DoG對邊緣有更高的響應,因此邊緣也須要去除。爲此,使用了相似於Harris角點檢測器的概念。他們用2×2 Hessian矩陣(H)來計算市政曲率。咱們從Harris角點檢測器知道,對於邊緣,一個特徵值比另外一個大。因此這裏他們使用了一個簡單的函數對象
若是此比率大於閾值(在OpenCV中稱爲edgeThreshold),則丟棄該關鍵點。在紙上給出10。
所以它消除了任何低對比度關鍵點和邊緣關鍵點,而且仍然存在強烈的興趣點。
如今爲每一個關鍵點分配一個方向以實現圖像旋轉的不變性。根據規模在關鍵點位置周圍採起鄰居關係,並在該地區計算梯度大小和方向。建立一個方向直方圖,其中36個方框覆蓋360度。(它經過梯度幅度和高斯加權圓窗口等於關鍵點尺度的1.5倍進行加權,得到直方圖中的最高峯值,而且任何高於80%的峯值也被認爲是計算方向,它建立關鍵點具備相同的位置和規模,但方向不一樣,有助於匹配的穩定性。
如今建立關鍵點描述符。關鍵點周圍有一個16x16的街區。它分爲16個4x4大小的子塊。對於每一個子塊,建立8個方向直方圖。因此共有128個bin值可用。它被表示爲造成關鍵點描述符的向量。除此以外,還採起了幾項措施來實現對光照變化,旋轉等的魯棒性。
兩幅圖像之間的關鍵點經過識別它們最近的鄰居來匹配。但在某些狀況下,第二個最接近的匹配可能很是接近第一個。這多是因爲噪音或其餘緣由。在那種狀況下,採用最近距離與第二近距離的比率。若是它大於0.8,則被拒絕。根據論文,它排除了大約90%的錯誤匹配,而丟棄只有5%的匹配正確。
因此這是SIFT算法的總結。欲瞭解更多細節和理解,強烈建議閱讀原文。記住一件事,這個算法是得到專利的。因此這個算法被包含在OpenCV中的非自由模塊中。
如今讓咱們看看OpenCV中提供的SIFT功能。讓咱們從關鍵點檢測開始並繪製它們。首先,咱們必須構建一個SIFT對象。咱們能夠將不一樣的參數傳遞給它,這些參數是可選的,而且在文檔中有很好的解釋。
import cv2 import numpy as np img = cv2.imread('home.jpg') gray= cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) sift = cv2.SIFT() kp = sift.detect(gray,None) img=cv2.drawKeypoints(gray,kp)
sift.detect()函數在圖像中查找關鍵點。若是您只想搜索圖像的一部分,則能夠傳遞掩碼。每一個關鍵點都是一個特殊的結構,它具備許多屬性,如它的(x,y)座標,有意義的鄰域的大小,指定其方向的角度,指定關鍵點強度的響應等。
OpenCV還提供cv2.drawKeyPoints()函數,用於繪製關鍵點位置上的小圓圈。若是你傳遞一個標誌cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS給它,它將繪製一個尺寸爲關鍵點的圓,它甚至會顯示它的方向。看下面的例子。
img=cv2.drawKeypoints(gray,kp,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) cv2.imwrite('sift_keypoints.jpg',img)
看到下面的兩個結果:
如今計算描述符,OpenCV提供了兩種方法。
kp,des = sift.compute(gray,kp)
咱們將看到第二種方法:
sift = cv2.SIFT() kp, des = sift.detectAndCompute(gray,None)
這裏kp將是一個關鍵點列表,des是一個形狀不規則的數組。
參考:
http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_sift_intro/py_sift_intro.html
轉載註明出處!!!