特徵檢測之Harris角點檢測

↑↑↑關注後"星標"Datawhale
每日干貨 & 每月組隊學習,不錯過
 Datawhale乾貨 
作者:王程偉,Datawhale成員,南昌航空大學
特徵點又叫興趣點或者角點。常被用於目標匹配,目標跟蹤,三維重建等應用中。點特徵主要指圖像中的明顯點,如突出的角點、邊緣端點、極值點等等。特徵點具有以下三種特性:旋轉不變性;光照不變性;視角不變性。用於點特徵提取的算子稱爲興趣點提取(檢測)算子。常用的有Harris角點檢測;FAST特徵檢測;SIFT特徵檢測;SURF特徵檢測。

預備數學

實對稱矩陣

如果有n階矩陣A,其矩陣的元素都爲實數,且矩陣A的轉置等於其本身,則稱A爲實對稱矩陣。

性質:

  • 實對稱矩陣A的不同特徵值對應的特徵向量是正交的;

  • n階實對稱矩陣A必可相似對角化,且相似對角陣上的元素即爲矩陣本身特徵值。

對角化:

優點:滿秩的對角方陣,可以直接看出特徵值,特徵向量等重要特徵。

卷積算子—Sobel算子

主要用於邊緣檢測,分別對水平和垂直方向上的邊緣敏感。對圖像任意一點使用會產生對應的梯度矢量或者其法矢量。對噪聲具有平滑抑制作用,但是得到的邊緣較粗,且可能出現僞邊緣。

該算子包含兩組3x3的矩陣,分別爲橫向及縱向,將之與圖像作平面卷積,即可分別得出橫向及縱向的亮度差分近似值。如果以A代表原始圖像,分別代表經橫向及縱向邊緣檢測的圖像,其公式如下:

梯度計算公式

梯度方向計算公式

如果等於零,代表圖像該處擁有縱向邊緣,左邊比右邊要暗。

基礎知識

1、角點

使用一個滑動窗口在下面三幅圖中滑動,可以得出以下結論:

  • 左圖表示一個平坦區域,在各方向移動,窗口內像素值均沒有太大變化;

  • 中圖表示一個邊緣特徵(Edges),如果沿着水平方向移動(梯度方向),像素值會發生跳變;如果沿着邊緣移動(平行於邊緣) ,像素值不會發生變化;

  • 右圖表示一個角(Corners),不管你把它朝哪個方向移動,像素值都會發生很大變化。

所以,右圖是一個角點。

2、角點類型 

下圖展示了不同角點的類型,可以發現:如果使用一個滑動窗口以角點爲中心在圖像上滑動,存在朝多個方向上的移動會引起該區域的像素值發生很大變化的現象。

3、圖像梯度 

“像素值發生很大變化”這一現象可以用圖像梯度進行描述。在圖像局部內,圖像梯度越大表示該局部內像素值變化越大(灰度的變化率越大)。而圖像的梯度在數學上可用微分或者導數來表示。對於數字圖像來說,相當於是二維離散函數求梯度,並使用差分來近似導數:

在實際操作中,對圖像求梯度通常是考慮圖像的每個像素的某個鄰域內的灰度變化,因此通常對原始圖像中像素某個鄰域設置梯度算子,然後採用小區域模板進行卷積來計算,常用的有Prewitt算子、Sobel算子、Robinson算子、Laplace算子等。

Harris角點檢測算法

1、算法思想 

算法的核心是利用局部窗口在圖像上進行移動,判斷灰度是否發生較大的變化。如果窗口內的灰度值(在梯度圖上)都有較大的變化,那麼這個窗口所在區域就存在角點。

這樣就可以將 Harris 角點檢測算法分爲以下三步:

  • 當窗口(局部區域)同時向 (水平)和 (垂直) 兩個方向移動時,計算窗口內部的像素值變化量

  • 對於每個窗口,都計算其對應的一個角點響應函數

  • 然後對該函數進行閾值處理,如果 ,表示該窗口對應一個角點特徵。

2、算法步驟 

第一步 — 建立數學模型 

第一步是通過建立數學模型,確定哪些窗口會引起較大的灰度值變化。讓一個窗口的中心位於灰度圖像的一個位置,這個位置的像素灰度值爲 ,如果這個窗口分別向 方向移動一個小的位移,到一個新的位置 ,這個位置的像素灰度值就是

就是窗口移動引起的灰度值的變化值。

爲位置處的窗口函數,表示窗口內各像素的權重,最簡單的就是把窗口內所有像素的權重都設爲1,即一個均值濾波核。

當然,也可以把 設定爲以窗口中心爲原點的高斯分佈,即一個高斯核。如果窗口中心點像素是角點,那麼窗口移動前後,中心點的灰度值變化非常強烈,所以該點權重係數應該設大一點,表示該點對灰度變化的貢獻較大;而離窗口中心(角點)較遠的點,這些點的灰度變化比較小,於是將權重係數設小一點,表示該點對灰度變化的貢獻較小。

則窗口在各個方向上移動所造成的像素灰度值的變化量公式如下:

爲了提高計算效率,對上述公式進行簡化,利用泰勒級數展開來得到這個公式的近似形式:

對於二維的泰勒展開式公式爲:

爲:

其中的微分(偏導),在圖像中就是求方向的梯度圖:

代入可得:


提出 ,得到最終的近似形式:


其中矩爲:

最後是把實對稱矩陣對角化處理後的結果,可以把R看成旋轉因子,其不影響兩個正交方向的變化分量。

經對角化處理後,將兩個正交方向的變化分量提取出來,就是 (特徵值)。這裏利用了線性代數中的實對稱矩陣對角化的相關知識,有興趣的同學可以進一步查閱相關資料。

第二步—角點響應函數R 

現在我們已經得到 的最終形式,別忘了我們的目的是要找到會引起較大的灰度值變化的那些窗口。

灰度值變化的大小則取決於矩陣爲梯度的協方差矩陣。在實際應用中爲了能夠應用更好的編程,所以定義了角點響應函數,通過判定大小來判斷像素是否爲角點。

計算每個窗口對應的得分(角點響應函數R定義):

其中

是矩陣的行列式,

是矩陣的跡。

是矩陣的特徵值, 是一個經驗常數,在範圍 (0.04, 0.06) 之間。

的值取決於的特徵值,對於角點很大,平坦的區域很小,邊緣的爲負值。

第三步—角點判定 

根據 的值,將這個窗口所在的區域劃分爲平面、邊緣或角點。爲了得到最優的角點,我們還可以使用非極大值抑制。

注意:Harris 檢測器具有旋轉不變性,但不具有尺度不變性,也就是說尺度變化可能會導致角點變爲邊緣。想要尺度不變特性的話,可以關注SIFT特徵。

因爲特徵值決定了 的值,所以我們可以用特徵值來決定一個窗口是平面、邊緣還是角點:

  • 平面::該窗口在平坦區域上滑動,窗口內的灰度值基本不會發生變化,所以值非常小,在水平和豎直方向的變化量均較小,即 都較小,那麼都較小;

  • 邊緣:值爲負數,僅在水平或豎直方向有較大的變化量,即只有一個較大,也就是

  • 角點:[公式] 值很大,在水平、豎直兩個方向上變化均較大的點,即都較大,也就是都很大。

如下圖所示:

Harris 角點檢測的結果是帶有這些分數 的灰度圖像,設定一個閾值,分數大於這個閾值的像素就對應角點。

3、算法性質 

Harris角點檢測的性質可總結如下:

1. 閾值決定角點的數量。

Harris角點檢測算子對亮度和對比度的變化不敏感(光照不變性) 在進行Harris角點檢測時,使用了微分算子對圖像進行微分運算,而微分運算對圖像密度的拉昇或收縮和對亮度的擡高或下降不敏感。換言之,對亮度和對比度的仿射變換並不改變Harris響應的極值點出現的位置,但是,由於閾值的選擇,可能會影響角點檢測的數量。

2. Harris角點檢測算子具有旋轉不變性。

Harris角點檢測算子使用的是角點附近的區域灰度二階矩矩陣。而二階矩矩陣可以表示成一個橢圓,橢圓的長短軸正是二階矩矩陣特徵值平方根的倒數。當特徵橢圓轉動時,特徵值並不發生變化,所以判斷角點響應值也不發生變化,由此說明Harris角點檢測算子具有旋轉不變性。

3. Harris角點檢測算子不具有尺度不變性。

尺度的變化會將角點變爲邊緣,或者邊緣變爲角點,Harris的理論基礎並不具有尺度不變性。

基於OpenCV的實現

在opencv中有提供實現 Harris 角點檢測的函數 cv2.cornerHarris,我們直接調用的就可以,非常方便。

函數原型:cv2.cornerHarris(src, blockSize, ksize, k[, dst[, borderType]])。

對於每一個像素,在(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('Scenery.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, cv2.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 = cv2.getStructuringElement(cv2.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, cv2.COLOR_BGR2RGB)
plt.imshow(image)
plt.show()

本文電子版 後臺回覆 角點檢測 獲取
“感謝你的分享,點贊,在看三連↓
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章