openCV-SIFT簡介(尺度不變特徵變換)

目標

在這一章當中,

  • 我們將瞭解SIFT算法的概念
  • 我們將學習如何找到SIFT關鍵點和描述符。

理論

在之前的幾章中,我們看到了一些角點探測器,如Harris等。它們是旋轉不變的,這意味著,即使圖像旋轉,我們也可以找到相同的角落。很明顯,因為角落在旋轉圖像中也是角落。但是縮放呢?如果圖像縮放,角落可能不是角落。例如,檢查下面的簡單圖像。當在同一窗口中放大時,小窗口內的小圖像中的角是平坦的。所以哈里斯的角點受尺度影響。

openCV-SIFT簡介(尺度不變特徵變換)

因此,在2004年,不列顛哥倫比亞大學的D.Lowe在他的論文中提出了一種新的算法,尺度不變特徵變換(SIFT),從尺度不變關鍵點獲取獨特圖像特徵,它提取關鍵點並計算其描述符。*(該論文易於理解,被認為是SIFT上最好的材料。本文只是該論文的簡要解釋)*。

SIFT算法可以將一幅圖像映射(變換)為一個局部特徵向量集;特徵向量具有平移、縮放、旋轉不變性,同時對光照變化、仿射及投影變換也有一定的不變性。SIFT算法的實質是在不同的尺度空間上查找關鍵點,並計算出關鍵點的方向。所查找到的關鍵點是一些十分突出,不會因光照,仿射變換和噪音等因素而變化的點,如角點、邊緣點、暗區的亮點及亮區的暗點等。

SIFT算法主要涉及四個步驟。我們將逐一看到它們。

  1. 高斯差分(DoG)濾波:搜索所有尺度上的圖像位置。通過高斯微分函數來識別潛在的對於尺度和旋轉不變的興趣點。
  2. 尺度空間的極值檢測和關鍵點位置確定:對DoG金字塔中的每一層,進行尺度空間的極值檢測(極大值和極小值),把每一個極值點作為候選點,在每個候選的位置上,通過一個擬合精細的模型來確定位置和尺度。關鍵點的選擇依據於它們的穩定程度。
  3. 關鍵點方向確定:基於圖像局部的梯度方向,分配給每個關鍵點位置一個或多個方向。所有後面的對圖像數據的操作都相對於關鍵點的方向、尺度和位置進行變換,從而提供對於這些變換的不變性。
  4. 構建關鍵點特徵描述符:在每個關鍵點周圍的內,在選定的尺度上測量圖像局部的梯度。這些梯度被變換成一種表示,這種表示允許比較大的局部形狀的變形和光照變化。

1.尺度空間極值檢測

從上圖可以看出,我們不能使用同一個窗口來檢測不同比例的關鍵點。小角落可以。但要檢測更大的角落,我們需要更大的窗口。為此,使用縮放空間過濾。其中,對於具有各種σ的圖像,找到高斯拉普拉斯算子值(LoG)。LoG充當斑點檢測器,其檢測由於σ的變化而導致的各種尺寸的斑點。簡而言之,σ充當尺度的縮放參數。例如,在上圖中,具有低σ的高斯核時對於小的角點,而高σ值適合較大的角落。因此,我們可以找到整個比例和空間的局部最大值,它給出了一個(x,y,σ)的列表,這意味著在對應的σ尺度範圍處存在潛在的關鍵點(x,y)。

但是這個LoG開銷很大,因此SIFT算法使用高斯差分,這是LoG的近似值。獲得高斯差異作為具有兩個不同σ的圖像的高斯模糊的差異,讓它成為σ和ķσ。對於高斯金字塔中的圖像的不同八度音程,完成該過程。它在下圖中表示:

openCV-SIFT簡介(尺度不變特徵變換)

找到此DoG後,將搜索圖像以查找超出比例和空間的局部極值。例如,將圖像中的一個像素與其8個鄰居以及下一個比例中的9個像素和先前比例中的9個像素進行比較。如果它是一個局部極值,它是一個潛在的關鍵點。它基本上意味著關鍵點最好以該比例表示。如下圖所示:

openCV-SIFT簡介(尺度不變特徵變換)

針對不同的參數,本文給出了一些經驗數據,可以概括為:八度值= 4,等級數= 5,初始σ= 1.6,k=√2 等作為最佳值。

2.關鍵點本地化

一旦找到潛在的關鍵點位置,就必須對其進行細化以獲得更準確的結果。他們使用泰勒級數擴展的尺度空間來獲得更準確的極值位置,並且如果此極值處的強度小於閾值(根據論文為0.03),則將其拒絕。此閾值在OpenCV中稱為contrastThreshold DoG對邊緣的響應更高,因此也需要去除邊緣。為此,使用類似於Harris角點檢測器的概念。他們使用2x2 Hessian矩陣(H)來計算主曲率。我們從Harris角點檢測器得知,對於邊緣,一個特徵值大於另一個。所以這裡他們使用了一個簡單的函數

如果此比率大於閾值(在OpenCV中稱為edgeThreshold),則丟棄該關鍵點。在論文中給出的建議值為10。因此,它消除了任何低對比度關鍵點和邊緣關鍵點,剩下的是強烈的興趣點。

3.定向分配

現在,為每個關鍵點分配方向,以實現圖像旋轉的不變性。根據比例在關鍵點位置周圍進行鄰域計算,並且在該區域中計算梯度大小和方向。創建了包含360度的36個方向直方圖。(它由梯度幅度和高斯加權圓窗加權σ加權等於關鍵點尺度的1.5倍。採用直方圖中的最高峰,並且還考慮任何高於其的80%的峰來計算方向。它創建具有相同位置和比例但不同方向的關鍵點。它有助於匹配的穩定性。

4.關鍵點描述符

現在創建了關鍵點描述符。在關鍵點周圍採用16x16鄰域。它分為16個4x4大小的子塊。對於每個子塊,創建8個方向直方圖。因此總共有128個bin值可用。它表示為形成關鍵點描述符的向量。除此之外,還採取了一些措施來實現對照明變化,旋轉等的魯棒性。

5.關鍵點匹配

通過識別它們的最近鄰居來匹配兩個圖像之間的關鍵點。但在某些情況下,第二個最接近的匹配可能非常接近第一個,它可能由於噪音或其他原因而發生。在那種情況下,採用最近距離與第二最近距離的比率。如果它大於0.8,則拒絕它們。根據論文,它消除了大約90%的錯誤匹配,而丟棄了只有5%的正確匹配。

所以這是SIFT算法的總結。有關更多詳細信息和理解,強烈建議閱讀原始論文。記住一件事,這個算法是專利的。所以這個算法包含在opencv contrib repo中

OpenCV中的SIFT

現在讓我們看看OpenCV中提供的SIFT功能。讓我們從關鍵點檢測開始並繪製它們。首先,我們必須構造一個SIFT對象。我們可以向它傳遞不同的參數,這些參數是可選的,它們在文檔中有很好的解釋。

import numpy as np
import cv2 as cv
img = cv.imread('home.jpg')
gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)
sift = cv.xfeatures2d.SIFT_create()
kp = sift.detect(gray,None)
img = cv.drawKeypoints(gray,kp,img)
cv.imwrite('sift_keypoints.jpg',img)

sift.detect()函數查找圖像中的關鍵點。如果只想搜索圖像的一部分,則可以傳遞蒙版。每個關鍵點都是一個特殊的結構,它有許多屬性,如(x,y)座標,有意義鄰域的大小,指定方向的角度,指定關鍵點強度的響應等。

OpenCV還提供cv.drawKeyPoints() 函數,該函數在關鍵點的位置上繪製小圓圈。如果你向它傳遞一個標誌cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS,它將繪製一個大小為keypoint的圓圈,它甚至會顯示它的方向。見下面的例子。

img=cv.drawKeypoints(gray,kp,img,flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv.imwrite('sift_keypoints.jpg',img)

請參閱以下兩個結果:

openCV-SIFT簡介(尺度不變特徵變換)

現在要計算描述符,OpenCV提供了兩種方法。

  1. 由於您已經找到了關鍵點,因此可以調用sift.compute() 來計算我們找到的關鍵點的描述符。例如:kp, des = sift.compute(gray, kp)
  2. 如果您沒有找到關鍵點,請使用函數sift.detectAndCompute()在一個步驟中直接查找關鍵點和描述符。

我們將看到第二種方法:

sift = cv.xfeatures2d.SIFT_create()
kp, des = sift.detectAndCompute(gray,None)

這裡kp是關鍵點列表,des是numpy數組的shape,Number_of_Keypoints ×128。所以我們得到了關鍵點,描述符等。

原文:https://docs.opencv.org/3.4.1/da/df5/tutorial_py_sift_intro.html

拓展閱讀:https://blog.csdn.net/jancis/article/details/80824793


分享到:


相關文章: