1. 程式人生 > 其它 >OpenCV-Python系列之SURF演算法

OpenCV-Python系列之SURF演算法

我們在上個教程討論了SIFT演算法用於檢測特徵點,SIFT演算法對旋轉、尺度縮放、亮度變化等保持不變性,對視角變換、仿射變化、噪聲也保持一定程度的穩定性,是一種非常優秀的區域性特徵描述演算法。但是其實時性相對不高。SURF(Speeded Up Robust Features)演算法改進了特徵了提取和描述方式,用一種更為高效的方式完成特徵點的提取和描述。

SURF演算法原理

SURF特徵檢測的步驟

1. 尺度空間的極值檢測:搜尋所有尺度空間上的影象,通過Hessian來識別潛在的對尺度和選擇不變的興趣點。

2. 特徵點過濾並進行精確定位。

3. 特徵方向賦值:統計特徵點圓形鄰域內的Harr小波特徵。即在60度扇形內,每次將60度扇形區域旋轉0.2弧度進行統計,將值最大的那個扇形的方向作為該特徵點的主方向。

4. 特徵點描述:沿著特徵點主方向周圍的鄰域內,取4×4個矩形小區域,統計每個小區域的Haar特徵,然後每個區域得到一個4維的特徵向量。一個特徵點共有64維的特徵向量作為SURF特徵的描述子。

構建Hessian

構建Hessian矩陣的目的是為了生成影象穩定的邊緣點(突變點),跟Canny、拉普拉斯邊緣檢測的作用類似,為特徵提取做準備。構建Hessian矩陣的過程對應著SIFT演算法中的DoG過程。

黑塞矩陣(Hessian Matrix)是由一個多元函式的二階偏導數構成的方陣,描述了函式的局部曲率。由德國數學家Ludwin Otto Hessian於19世紀提出。

對於一個影象I(x,y),其Hessian矩陣如下:

H矩陣的判別式是:

在構建Hessian矩陣前需要對影象進行高斯濾波,經過濾波後的Hessian矩陣表示式為:

其中(x,y)為畫素位置, L(x,y,σ)=G(σ)∗I(x,y),代表著影象的高斯尺度空間,是由影象和不同的高斯卷積得到。

我們知道在離散數學影象中,一階導數是相鄰畫素的灰度差:

二階導數是對一階導數的再次求導:

反過來看Hessian矩陣的判別式,其實就是當前點對水平方向二階偏導數乘以垂直方向二階偏導數再減去當前水平、垂直二階偏導的二次方:

通過這種方法可以為影象中每個畫素計算出其H行列式的決定值,並用這個值來判別影象區域性特徵點。Hession矩陣判別式中的L(x,y)是原始影象的高斯卷積,由於高斯核服從正太分佈,從中心點往外,係數越來越小,為了提高運算速度,SURF演算法使用了盒式濾波器來替代高斯濾波器L,所以在Lxy上乘了一個加權係數0.9,目的是為了平衡因使用盒式濾波器近似所帶來的誤差,則H矩陣判別式可表示為:

盒式濾波器和高斯濾波器的示意圖如下:

上面兩幅圖是9×9高斯濾波器模板分別在影象垂直方向上二階導數Lyy和Lxy對應的值,下邊兩幅圖是使用盒式濾波器對其近似,灰色部分的畫素值為0,黑色為-2,白色為1。

那麼為什麼盒式濾波器可以提高運算速度呢?這就涉及到積分圖的使用,盒式濾波器對影象的濾波轉化成計算影象上不同區域間畫素的加減運算問題,這正是積分圖的強項,只需要簡單積分查詢積分圖就可以完成。

構造尺度空間

同SIFT演算法一樣,SURF演算法的尺度空間由O組S層組成,不同的是,SIFT演算法下一組影象的長寬均是上一組的一半,同一組不同層影象之間尺寸一樣,但是所使用的尺度空間因子(高斯模糊係數σ)逐漸增大;而在SURF演算法中,不同組間影象的尺寸都是一致的,不同的是不同組間使用的盒式濾波器的模板尺寸逐漸增大,同一組不同層影象使用相同尺寸的濾波器,但是濾波器的尺度空間因子逐漸增大。如下圖所示:

特徵點過濾並進行精確定位

SURF特徵點的定位過程和SIFT演算法一致,將經過Hessian矩陣處理的每個畫素點(即獲得每個畫素點Hessian矩陣的判別式值)與其影象域(相同大小的影象)和尺度域(相鄰的尺度空間)的所有相鄰點進行比較,當其大於(或者小於)所有相鄰點時,該點就是極值點。如圖所示,中間的檢測點要和其所在影象的3×3鄰域8個畫素點,以及其相鄰的上下兩層3×3鄰域18個畫素點,共26個畫素點進行比較。

初步定位出特徵點後,再經過濾除能量比較弱的關鍵點以及錯誤定位的關鍵點,篩選出最終的穩定的特徵點:

計算特徵點主方向

SIFT演算法特徵點的主方向是採用在特徵點鄰域內統計其梯度直方圖,橫軸是梯度方向的角度,縱軸是梯度方向對應梯度幅值的累加,取直方圖bin最大的以及超過最大80%的那些方向作為特徵點的主方向。

而在SURF演算法中,採用的是統計特徵點圓形鄰域內的Harr小波特徵,即在特徵點的圓形鄰域內,統計60度扇形內所有點的水平、垂直Harr小波特徵總和,然後扇形以0.2弧度大小的間隔進行旋轉並再次統計該區域內Harr小波特徵值之後,最後將值最大的那個扇形的方向作為該特徵點的主方向。該過程示意圖如下:

生成特徵描述

在SIFT演算法中,為了保證特徵向量的旋轉不變性,先以特徵點為中心,在附近鄰域內將座標軸旋轉θ(特徵點的主方向)角度,然後提取特徵點周圍4×4個區域塊,統計每小塊內8個梯度方向,這樣一個關鍵點就可以產生128維的SIFT特徵向量。

SURF演算法中,也是提取特徵點周圍4×4個矩形區域塊,但是所取得矩形區域方向是沿著特徵點的主方向,而不是像SIFT演算法一樣,經過旋轉θθ角度。每個子區域統計25個畫素點水平方向和垂直方向的Haar小波特徵,這裡的水平和垂直方向都是相對主方向而言的。該Harr小波特徵為水平方向值之和、垂直方向值之和、水平方向值絕對值之和以及垂直方向絕對之和4個方向。該過程示意圖如下:

把這4個值作為每個子塊區域的特徵向量,所以一共有4×4×4=64維向量作為SURF特徵的描述子,比SIFT特徵的描述子減少了一半。

OpenCV中的SURF演算法

跟SIFT一樣,由於專利的原因,SURF目前也需要用低版本的OpenCV進行操作。

程式碼與SIFT的類似:

import numpy as np
import cv2
import matplotlib.pyplot as plt
 
img = cv2.imread('test32.jpg', 0)
 
surf = cv2.xfeatures2d.SURF_create(30000)
 
kp = surf.detect(img, None)
 
img2 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)
surf.setUpright(True)
surf.setHessianThreshold(40000)
kp = surf.detect(img, None)
img3 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)
 
plt.subplot(121), plt.imshow(img2),
plt.title('Dstination'), plt.axis('off')
plt.subplot(122), plt.imshow(img3),
plt.title('Dstination'), plt.axis('off')
plt.show()

結果如下:

目前我們也發現了,SIFT與SURF演算法都受到了專利保護,在高版本的OpenCV中無法使用,我們在之後會介紹一些免費的演算法。

天道酬勤 循序漸進 技壓群雄