原文請移步知乎:https://zhuanlan.zhihu.com/p/40960756
python實現:
實現
基於python的scikit-image庫提供了HOG特征提取的接口:
from skimage import feature as ft features = ft.hog(image, # input image orientations=ori, # number of bins pixels_per_cell=ppc, # pixel per cell cells_per_block=cpb, # cells per blcok block_norm = 'L1', # block norm : str {‘L1’, ‘L1-sqrt’, ‘L2’, ‘L2-Hys’} transform_sqrt = True, # power law compression (also known as gamma correction) feature_vector=True, # flatten the final vectors visualise=False) # return HOG map
參數說明:
image: input image, 輸入圖像
orientation: 指定bin的個數. scikit-image 實現的只有無符號方向.
(根據反正切函數的到的角度范圍是在-180°~ 180°之間, 無符號是指把 -180°~0°這個范圍統一加上180°轉換到0°~180°范圍內. 有符號是指將-180°~180°轉換到0°~360°范圍內.)
也就是說把所有的方向都轉換為0°~180°內, 然后按照指定的orientation數量划分bins. 比如你選定的orientation= 9, 則bin一共有9個, 每20°一個:
[0°~20°, 20°~40°, 40°~60° 60°~80° 80°~100°, 100°~120°, 120°~140°, 140°~160°, 160°~180°]
pixels_per_cell : 每個cell的像素數, 是一個tuple類型數據,例如(20,20)
cell_per_block : 每個BLOCK內有多少個cell, tuple類型, 例如(2,2), 意思是將block均勻划分為2x2的塊
block_norm: block 內部采用的norm類型.
transform_sqrt: 是否進行 power law compression, 也就是gamma correction. 是一種圖像預處理操作, 可以將較暗的區域變亮, 減少陰影和光照變化對圖片的影響.
feature_vector: 將輸出轉換為一維向量.
visualise: 是否輸出HOG image, (應該是梯度圖)
scikit-image 版的HOG 沒有進行cell級別的gaussian 平滑, 原文對cell進行了gamma= 8pix的高斯平滑操作.
二. HOG實例講解(以下所有的系統參數都是按照上述論文實驗得出的最佳結果確定的)
- 圖像預處理
包括伽馬校正和灰度化。這是可選的步驟,因為實驗證明做不做影響不大。伽馬校正是減少光度對實驗的影響。灰度化是將彩色圖片變成灰度圖。其實彩色圖片也可以直接處理。不過是分別對三通道的顏色值進行梯度計算,最后選擇梯度最大的那個。為簡單起見,假設輸入為灰度圖,同時大小是64*128(這個大小是上面論文的大小,也可以自己確定不同的大小,但是實驗效果就不能得到保證)。
2.計算每一個像素點的梯度值,得到梯度圖(規模和原圖大小一樣)
對於像素點A,要計算水平梯度和豎直梯度,如上圖,水平梯度 =30-20=10,豎直梯度
=64-32=32.
那么總的梯度強度值g和梯度方向 將按照以下公式計算:
梯度方向將會取絕對值,因此梯度方向的范圍是0-180度。取絕對值的原因是這樣效果更好。
3.計算梯度直方圖
按照第二步的計算,每一個像素點都會有兩個值:梯度強度/梯度方向。
現在就計算梯度直方圖,這是一個關鍵步驟也是HOG能夠work的原因。
梯度直方圖是在一個8*8的cell里面計算的。那么在8*8的cell里面就會有8*8*2=128個值,2是包括了梯度強度和梯度方向。通過統計形成梯度直方圖,128個值將會變成9個值,大大降低了計算量,同時又對光照等環境變化更加地robust。
首先,我將0-180度分成9個bins,分別是0,20,40...160。然后統計每一個像素點所在的bin。請看下圖:
左上圖是8*8的梯度方向值,右上圖是8*8的梯度強度值,下圖是9個bins。
先看兩個藍色圈圈。因為藍圈的方向是80度,大小是2,所以該點就投給80這個bin;
再看兩個紅色圈圈。因為紅色圈圈的方向是10,大小是4,因為10距離0點為10,距離20點為也為10,那么有一半的大小是投給0這個bin,還有一半的大小(即是2)投給20這個bin。
那么統計完64個點的投票數以后,每個bin就會得到一個數值,可以得到一個直方圖,在計算機里面就是一個大小為9的數組。
從上圖可以看到,更多的點的梯度方向是傾向於0度和160度,也就是說這些點的梯度方向是向上或者向下,表明圖像這個位置存在比較明顯的橫向邊緣。因此HOG是對邊角敏感的,由於這樣的統計方法,也是對部分像素值變化不敏感的,所以能夠適應不同的環境。
4. 對16*16大小的block歸一化
歸一化的目的是降低光照的影響。
歸一化的方法是向量的每一個值除以向量的模長。
比如對於一個(128,64,32)的三維向量來說,模長是
那么歸一化后的向量變成了(0.87,0.43,0.22)
那么16*16大小的block是怎么來的?
請看下圖:

綠色方塊是8*8大小的cell,藍色方塊就是由4個cell組成的block。作者提出要對block進行normalize。那么由於一個cell就會有大小為9的vector,四個cell就有36大小的vector。對block進行normalize就是對這大小為36的vector進行歸一化。
而每一個block將按照上圖籃框移動的方式進行迭代截取。
5.得到HOG特征向量
每一個16*16大小的block將會得到36大小的vector。那么對於一個64*128大小的圖像,按照上圖的方式提取block,將會有7個水平位置和15個豎直位可以取得,所以一共有7*15=105個block,所以我們整合所有block的vector,形成一個大的一維vector的大小將會是36*105=3780。
得到HOG特征向量,就可以用來可視化和分類了。對於這么大的HOG特征,SVM就排上用場了。
文章就寫到這里,謝謝閱讀。