OpenCV-Python SIFT尺度不變特徵變換 | 三十九

2020-02-13     人工智慧遇見磐創

目標

在這一章當中,

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

理論

在前兩章中,我們看到了一些像Harris這樣的拐角檢測器。它們是旋轉不變的,這意味著即使圖像旋轉了,我們也可以找到相同的角。很明顯,因為轉角在旋轉的圖像中也仍然是轉角。但是縮放呢?如果縮放圖像,則拐角可能不是角。例如,檢查下面的簡單圖像。在同一窗口中放大小窗口中小圖像中的拐角時,該角是平坦的。因此,Harris拐角不是尺度不變的。

因此,在2004年,不列顛哥倫比亞大學的D.Lowe在他的論文《尺度不變關鍵點中的獨特圖像特徵》中提出了一種新算法,即尺度不變特徵變換(SIFT),該算法提取關鍵點並計算其描述算符。 (改論文易於理解,被認為是學習SIFT的最佳材料。因此,本文只是該論文的簡短摘要)。 SIFT算法主要包括四個步驟。 我們將一一看到它們。

SIFT算法主要包括四個步驟。我們將一一看到它們。

1. 尺度空間極值檢測

從上圖可以明顯看出,我們不能使用相同的窗口來檢測具有不同比例的關鍵點。即便小拐角可以。但是要檢測更大的拐角,我們將需要更大的窗口。為此,使用了比例空間濾波。在其中,找到具有各種$σ$值的圖像的高斯拉普拉斯運算元。LoG用作斑點檢測器,可檢測由於$σ$的變化而導致的各種大小的斑點。簡而言之,$σ$用作縮放參數。例如,在上圖中,低$σ$的高斯核對於較小的拐角給出較高的值,而高$σ$的高斯核對於較大的拐角而言非常合適。因此,我們可以找到整個尺度和空間上的局部最大值,這給了我們$(x,y,σ)$值的列表,這意味著在$(x,y)$在$σ$尺度上有一個潛在的關鍵點。

但是這種LoG代價昂貴,因此SIFT算法使用的是高斯差值,它是LoG的近似值。高斯差是作為具有兩個不同$σ$的圖像的高斯模糊差而獲得的,設為$σ$和$kσ$。此過程是針對高斯金字塔中圖像的不同八度完成的。如下圖所示:

一旦找到該DoG,便會在圖像上搜索比例和空間上的局部極值。例如,將圖像中的一個像素與其8個相鄰像素以及下一個比例的9個像素和前一個比例的9個像素進行比較。如果是局部極值,則可能是關鍵點。從根本上說,關鍵點是最好的代表。如下圖所示:

對於不同的參數,本文給出了一些經驗數據,可以概括為:octaves=4,縮放尺度=5,初始$σ=1.6$,$k=sqrt{2}$等作為最佳值。

2. 關鍵點定位

一旦找到潛在的關鍵點位置,就必須對其進行優化以獲取更準確的結果。他們使用了標度空間的泰勒級數展開來獲得更精確的極值位置,如果該極值處的強度小於閾值(根據論文為0.03),則將其拒絕。在OpenCV DoG中,此閾值稱為ContrastThreshold,它對邊緣的響應較高,因此也需要刪除邊緣。

為此,使用類似於哈里斯拐角檢測器的概念。他們使用2x2的Hessian矩陣(H)計算主曲率。從哈里斯拐角檢測器我們知道,對於邊緣,一個特徵值大於另一個特徵值。因此,這裡他們使用了一個簡單的函數。

如果該比率大於一個閾值(在OpenCV中稱為edgeThreshold),則該關鍵點將被丟棄。論文上寫的值為10。

因此,它消除了任何低對比度的關鍵點和邊緣關鍵點,剩下的就是很可能的目標點。

3. 方向分配

現在,將方向分配給每個關鍵點,以實現圖像旋轉的不變性。根據比例在關鍵點位置附近採取鄰域,並在該區域中計算梯度大小和方向。創建了一個具有36個覆蓋360度的bin的方向直方圖(通過梯度幅度和$σ$等於關鍵點比例的1.5的高斯加權圓窗加權)。提取直方圖中的最高峰,並且將其超過80%的任何峰也視為計算方向。它創建的位置和比例相同但方向不同的關鍵點。它有助於匹配的穩定性。

4. 關鍵點描述

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

5. 關鍵點匹配

通過識別兩個圖像的最近鄰,可以匹配兩個圖像之間的關鍵點。但是在某些情況下,第二個最接近的匹配可能非常接近第一個。它可能是由於噪音或其他原因而發生的。在那種情況下,採用最接近距離與第二最接近距離之比。如果大於0.8,將被拒絕。根據論文,它可以消除大約90%的錯誤匹配,而僅丟棄5%的正確匹配。因此,這是SIFT算法的總結。有關更多詳細信息和理解,強烈建議閱讀原始論文。記住一件事,該算法已申請專利。所以這個算法包含在opencv contrib repo中

OpenCV中的SIFT

現在,讓我們來看一下OpenCV中可用的SIFT功能。讓我們從關鍵點檢測開始並進行繪製。首先,我們必須構造一個SIFT對象。我們可以將不同的參數傳遞給它,這些參數是可選的,它們在docs中已得到很好的解釋。

import numpy as npimport cv2 as cvimg = 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.DRAWMATCHESFLAGSDRAWRICH_KEYPOINTS傳遞給它,它將繪製一個具有關鍵點大小的圓,甚至會顯示其方向。請參見以下示例。

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

查看下面的結果:

現在要計算描述符,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是一個形狀為$NumberofKeypoints×128$的數字數組。

這樣我們得到了關鍵點,描述符等。現在我們想看看如何在不同圖像中匹配關鍵點。我們將在接下來的章節中學習。

文章來源: https://twgreatdaily.com/sNQLQnABgx9BqZZItnNS.html