1.1 簡介
在圖像處理領域中,特徵點又被稱爲興趣點或者角點,它通常具有旋轉不變性和光照不變性和視角不變性等優點,是圖像的重要特徵之一,常被應用到目標匹配、目標跟蹤、三維重建等應用中。點特徵主要指圖像中的明顯點,如突出的角點、邊緣端點、極值點等等,用於點特徵提取的算子稱爲興趣點提取(檢測)算子,常用的有Harris角點檢測、FAST特徵檢測、SIFT特徵檢測及SURF特徵檢測。
本次博客較爲常用而且較爲基礎的Harris角點檢測算法,它的思想以及數學理論能夠很好地幫助我們瞭解興趣點檢測的相關原理。
1.2內容介紹
1.2.1基礎知識
1.角點
使用一個滑動窗口在下面三幅圖中滑動,可以得出以下結論:
- 左圖表示一個平坦區域,在各方向移動,窗口內像素值均沒有太大變化;
- 中圖表示一個邊緣特徵(Edges),如果沿着水平方向移動(梯度方向),像素值會發生跳變;如果沿着邊緣移動(平行於邊緣) ,像素值不會發生變化;
- 右圖表示一個角(Corners),不管你把它朝哪個方向移動,像素值都會發生很大變化。
所以,右圖是一個角點。
2.角點類型
下圖展示了不同角點的類型,可以發現:如果使用一個滑動窗口以角點爲中心在圖像上滑動,存在朝多個方向上的移動會引起該區域的像素值發生很大變化的現象。
3.圖像梯度
“像素值發生很大變化”這一現象可以用圖像梯度進行描述。在圖像局部內,圖像梯度越大表示該局部內像素值變化越大(灰度的變化率越大)。 而圖像的梯度在數學上可用微分或者導數來表示。對於數字圖像來說,相當於是二維離散函數求梯度,並使用差分來近似導數: 在實際操作中,對圖像求梯度通常是考慮圖像的每個像素的某個鄰域內的灰度變化,因此通常對原始圖像中像素某個鄰域設置梯度算子,然後採用小區域模板進行卷積來計算,常用的有Prewitt算子、Sobel算子、Robinson算子、Laplace算子等。
1.2.1 Harris角點檢測算法原理
1. 算法思想
算法的核心是利用局部窗口在圖像上進行移動,判斷灰度是否發生較大的變化。如果窗口內的灰度值(在梯度圖上)都有較大的變化,那麼這個窗口所在區域就存在角點。
這樣就可以將 Harris 角點檢測算法分爲以下三步:
- 當窗口(局部區域)同時向 x (水平)和 y(垂直) 兩個方向移動時,計算窗口內部的像素值變化量 ;
- 對於每個窗口,都計算其對應的一個角點響應函數 ;
- 然後對該函數進行閾值處理,如果 ,表示該窗口對應一個角點特徵。
2. 第一步 — 建立數學模型
第一步是通過建立數學模型,確定哪些窗口會引起較大的灰度值變化。 讓一個窗口的中心位於灰度圖像的一個位置,這個位置的像素灰度值爲 ,如果這個窗口分別向 和 方向移動一個小的位移和,到一個新的位置 ,這個位置的像素灰度值就是
就是窗口移動引起的灰度值的變化值。
設爲位置處的窗口函數,表示窗口內各像素的權重,最簡單的就是把窗口內所有像素的權重都設爲1,即一個均值濾波核。
當然,也可以把 設定爲以窗口中心爲原點的高斯分佈,即一個高斯核。如果窗口中心點像素是角點,那麼窗口移動前後,中心點的灰度值變化非常強烈,所以該點權重係數應該設大一點,表示該點對灰度變化的貢獻較大;而離窗口中心(角點)較遠的點,這些點的灰度變化比較小,於是將權重係數設小一點,表示該點對灰度變化的貢獻較小。
則窗口在各個方向上移動 所造成的像素灰度值的變化量公式如下:
若窗口內是一個角點,則的計算結果將會很大。
爲了提高計算效率,對上述公式進行簡化,利用泰勒級數展開來得到這個公式的近似形式:
對於二維的泰勒展開式公式爲:
則 爲:
其中和是的微分(偏導),在圖像中就是求 和 方向的梯度圖:
將代入可得:
提出 u 和 v ,得到最終的近似形式:
其中矩陣M爲:
最後是把實對稱矩陣對角化處理後的結果,可以把R看成旋轉因子,其不影響兩個正交方向的變化分量。
經對角化處理後,將兩個正交方向的變化分量提取出來,就是 λ1 和 λ2(特徵值)。 這裏利用了線性代數中的實對稱矩陣對角化的相關知識,有興趣的同學可以進一步查閱相關資料。
3. 第二步—角點響應函數R
現在我們已經得到 的最終形式,別忘了我們的目的是要找到會引起較大的灰度值變化的那些窗口。
灰度值變化的大小則取決於矩陣M,M爲梯度的協方差矩陣。在實際應用中爲了能夠應用更好的編程,所以定義了角點響應函數R,通過判定R大小來判斷像素是否爲角點。
計算每個窗口對應的得分(角點響應函數R定義):
其中 是矩陣的行列式, 是矩陣的跡。
和 是矩陣的特徵值, 是一個經驗常數,在範圍 (0.04, 0.06) 之間。
的值取決於的特徵值,對於角點很大,平坦的區域很小,邊緣的爲負值。
4. 第三步—角點判定
根據 R 的值,將這個窗口所在的區域劃分爲平面、邊緣或角點。爲了得到最優的角點,我們還可以使用非極大值抑制。
注意:Harris 檢測器具有旋轉不變性,但不具有尺度不變性,也就是說尺度變化可能會導致角點變爲邊緣。想要尺度不變特性的話,可以關注SIFT特徵。
因爲特徵值 λ1 和 λ2 決定了 R 的值,所以我們可以用特徵值來決定一個窗口是平面、邊緣還是角點:
平面::該窗口在平坦區域上滑動,窗口內的灰度值基本不會發生變化,所以 值非常小,在水平和豎直方向的變化量均較小,即 和 都較小,那麼 λ1 和 λ2 都較小;
邊緣:值爲負數,僅在水平或豎直方向有較大的變化量,即 和 只有一個較大,也就是 λ1>>λ2 或 λ2>>λ1;
角點: 值很大,在水平、豎直兩個方向上變化均較大的點,即 和 都較大,也就是 λ1 和 λ2 都很大。
如下圖所示:
4. 第三步—角點判定
根據 R 的值,將這個窗口所在的區域劃分爲平面、邊緣或角點。爲了得到最優的角點,我們還可以使用非極大值抑制。
注意:Harris 檢測器具有旋轉不變性,但不具有尺度不變性,也就是說尺度變化可能會導致角點變爲邊緣。想要尺度不變特性的話,可以關注SIFT特徵。
因爲特徵值 λ1 和 λ2 決定了 R 的值,所以我們可以用特徵值來決定一個窗口是平面、邊緣還是角點:
平面::該窗口在平坦區域上滑動,窗口內的灰度值基本不會發生變化,所以 值非常小,在水平和豎直方向的變化量均較小,即 和 都較小,那麼 λ1 和 λ2 都較小;
邊緣:值爲負數,僅在水平或豎直方向有較大的變化量,即 和 只有一個較大,也就是 λ1>>λ2 或 λ2>>λ1;
角點:[公式] 值很大,在水平、豎直兩個方向上變化均較大的點,即 和 都較大,也就是 λ1 和 λ2 都很大。
如下圖所示:
Harris 角點檢測的結果是帶有這些分數 R 的灰度圖像,設定一個閾值,分數大於這個閾值的像素就對應角點。
1.5 基於OpenCV的實現
1. API
在opencv中有提供實現 Harris 角點檢測的函數 cv2.cornerHarris,我們直接調用的就可以,非常方便。
函數原型:cv2.cornerHarris(src, blockSize, ksize, k[, dst[, borderType]])
對於每一個像素 (x,y),在 (blockSize x blockSize) 鄰域內,計算梯度圖的協方差矩陣 ,然後通過上面第二步中的角點響應函數得到結果圖。圖像中的角點可以爲該結果圖的局部最大值。
即可以得到輸出圖中的局部最大值,這些值就對應圖像中的角點。
參數解釋:
src - 輸入灰度圖像,float32類型
blockSize - 用於角點檢測的鄰域大小,就是上面提到的窗口的尺寸
ksize - 用於計算梯度圖的Sobel算子的尺寸
k - 用於計算角點響應函數的參數k,取值範圍常在0.04~0.06之間
import cv2 as cv
from matplotlib import pyplot as plt
import numpy as np
# detector parameters
block_size = 3
sobel_size = 3
k = 0.06
image = cv.imread('E:/python-project/deep-learning/picture/test1.jpg')
print(image.shape)
height = image.shape[0]
width = image.shape[1]
channels = image.shape[2]
print("width: %s height: %s channels: %s"%(width, height, channels))
gray_img = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
# modify the data type setting to 32-bit floating point
gray_img = np.float32(gray_img)
# detect the corners with appropriate values as input parameters
corners_img = cv.cornerHarris(gray_img, block_size, sobel_size, k)
# result is dilated for marking the corners, not necessary
kernel = cv.getStructuringElement(cv.MORPH_RECT,(3, 3))
dst = cv.dilate(corners_img, kernel)
# Threshold for an optimal value, marking the corners in Green
#image[corners_img>0.01*corners_img.max()] = [0,0,255]
for r in range(height):
for c in range(width):
pix=dst[r,c]
if pix>0.05*dst.max():
cv2.circle(image,(c,r),5,(0,0,255),0)
image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
plt.imshow(image)
plt.show()
結果:
1.3 總結
Harris角點檢測的性質可總結如下:
- 閾值決定角點的數量
- Harris角點檢測算子對亮度和對比度的變化不敏感(光照不變性)
在進行Harris角點檢測時,使用了微分算子對圖像進行微分運算,而微分運算對圖像密度的拉昇或收縮和對亮度的擡高或下降不敏感。換言之,對亮度和對比度的仿射變換並不改變Harris響應的極值點出現的位置,但是,由於閾值的選擇,可能會影響角點檢測的數量。
- Harris角點檢測算子具有旋轉不變性 Harris角點檢測算子使用的是角點附近的區域灰度二階矩矩陣。而二階矩矩陣可以表示成一個橢圓,橢圓的長短軸正是二階矩矩陣特徵值平方根的倒數。當特徵橢圓轉動時,特徵值並不發生變化,所以判斷角點響應值也不發生變化,由此說明Harris角點檢測算子具有旋轉不變性。
- Harris角點檢測算子不具有尺度不變性 尺度的變化會將角點變爲邊緣,或者邊緣變爲角點,Harris的理論基礎並不具有尺度不變性。