CV下-HOG特徵描述算子


在深度學習之前非常流行的圖像特徵提取技術–方向梯度直方圖,簡稱HOG特徵。在行人檢測領域獲得極大成功。學習HOG特徵的思想有助於我們很好了解傳統圖像特徵描述和圖像識別方法。
學習內容:

  • 使用OpenCV的HOG算法實現行人檢測

1 HOG算法

1.1 HOG特徵簡介

HOG特徵是一種圖像局部特徵,其基本思想是對圖像局部的梯度幅值和反向進行投票統計,形成基於梯度特性的直方圖,然後將局部特徵拼接起來作爲總特徵。局部特徵在這裏指的的是將圖像劃分爲多個子塊(Block),每個Block內的特徵進行聯合以形成最終的特徵。、
HOG+SVM的工作流程如下:
輸入圖像---->Gamma矯正----->計算圖像梯度—>計算梯度直方圖—>Block特徵歸一化---->得到HOG特徵—SVM
首先對輸入的圖片進行預處理,然後計算像素點的梯度特性,包括梯度幅度和梯度方向。然後投票形成梯度直方圖,然後對blocks進行normalize,最後收集到HOG的feature(其實是一行多微的vector)放到SVM裏進行監督學習,從而實現行人的檢測。

1.2 HOG特徵原理

預處理包括灰度化和Gamma變換。
灰度處理是可選操作(一般都要進行灰度處理),因爲灰度圖像和彩色圖像都可以用於計算梯度圖。對於彩色圖像,先對三通道顏色值分別計算梯度,然後梯度值取最大的那個作爲該像素的梯度。
然後進行伽馬矯正,調節圖像對比度,減少光照對圖像的影響(包括光照不均和局部陰影),使過曝或者欠曝的的圖像恢復正常,更接近人眼看到的圖像。
伽馬矯正公式: ,I表示圖像(矩陣),gamma表示冪指數,、
該函數圖像如下圖所示:

由圖像可知,當gamma取不同的值對應的輸入輸出曲線

  • 當gamma<1時,輸入圖像的低灰度區域動態範圍變大,進而圖像低灰度值區域對比度得以增強;在高灰度值區域,動態範圍變小,進而圖像高灰度值區域對比度得以降低。最終,圖像整體的灰度變亮。
  • γ>1\gamma>1時,輸入圖像的高灰度值區域動態範圍變小,進而圖像低灰度值區域對比度得以降低;在高灰度值區域,動態範圍變大,進而圖像高灰度值區域對比度得以增強。 最終,圖像整體的灰度變暗。
    代碼實現
# 導入庫函數
import cv2 
import numpy as np
from matplotlib import pyplpt as plt

# 加載圖像和灰度化處理
img=cv2.imread("*.png",0)
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

img2=np.power(img/float(np.max(img),1/2,2))
plt.imshow(omg2)
plt.axis('off')
plt.show()

1.3 計算圖像梯度

爲了得到梯度直方圖,首先需要計算圖像水平方向和垂直方向梯度。一般使用特定的卷積覈對圖像濾波實現,可選用的卷積模板有:sobel算子,prewitt算子核Roberts模板等。

  • 一般採用soble算子,OpenCV也是如此,利用soble水平和垂直算子與輸入圖像卷積計算dxdxdydy

dx = f(x,y)* Sobelx(x,y)
dy = f(x,y)*Sobel(x,y)

進一步可以得到圖像梯度的幅值:
M(x,y)=(d2(x,y)+d2y(x,y))^1/2
爲了簡化計算,幅度可以做如下近似:
M(x,y)= | d^2(x,y)| + |d^2(x,y) |
角度爲:
這裏需要注意的是:梯度方向和圖像邊緣方向是互相正交的。

python 實現代碼:

import cv2 
import numpy as np 
# read image 
img =cv2.imread('*.ipg')
img = np.float32(img)/ 255.0 # 歸一化

# 計算x和y方向的梯度
gx = cv2.Sobel(img,cv2.CV_32F,1,0,ksize-1)
gy = cv2.Sobel(img,cv2.CV_32F,0,1,ksize-1)

# 計算合梯度的幅值和方向(角度)
mag,angle = cv2.cartToPolar(gx,gy,angleInDegrees=True) 


1.4 計算梯度直方圖

經過上一步計算,每一個像素點都會兩個值:梯度幅值/梯度方向。

在這一步中,圖像被分成若干個8×8的cell,例如我們將圖像resize至64x128的大小,那麼這幅圖像就被劃分爲8x16個8x8的cell單元,併爲每個8×8的cell計算梯度直方圖。當然,cell的劃分也可以是其他值:16x16,8x16等,根據具體的場景確定。
在計算梯度直方圖,我們爲什麼將圖像分成若干個cell?
這是因爲如果對一整張梯度圖逐像素計算,其中的有效特徵是非常稀疏的,不但運算量大,而且會受到一些噪聲干擾。於是我們就使用局部特徵描述符來表示一個更緊湊的特徵,計算這種局部cell上的梯度直方圖更具魯棒性。
【魯棒性】:
左圖是衣服64x128的圖像,被劃分爲8x16個8x8的cell;中間的圖像表示一個cell中的梯度矢量,箭頭朝向代表梯度方向,箭頭長度代表梯度大小。

1.5 Block歸一化

HOG特徵將8x8的一個局部區域作爲一個cell,再以2x2個cell作爲一組,稱爲一個block,也就是說一個block表示16x16的區域。
歸一化的目的是爲了降低光照的影響,因爲梯度對整體光照非常敏感,比如通過將所有像素值除以2來使圖像變暗,那麼梯度幅值將減小一半,因此直方圖中的值也將減小一半,我們就需要將直方圖“歸一化”。
歸一化的方法有很多:L1-norm、L2-norm、max/min等等,一般選擇L2-norm。

  • 計算方法
    例如對於一個[128,64,32]的三維向量來說,模長是1282+642+322=146.64\sqrt{128^2+64^2+32^2}=146.64,這叫做向量的L2範數。將這個向量的每個元素除以146.64就得到了歸一化向量 [0.87, 0.43, 0.22]。
    採用同樣的方法,一個cell有一個梯度方向直方圖,包含9個數值,一個block有4個cell,那麼一個block就有4個梯度方向直方圖,將這4個直方圖拼接成長度爲36的向量,然後對這個向量進行歸一化。
    而每一個block將按照上圖滑動的方式進行重複計算,直到整個圖像的block都計算完成。
    基於OpenCV實現
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

if __name__ == '__main__':
    src = cv.imread("*.jpg")
    cv.imshow("input", src)
    
    hog = cv.HOGDescriptor()
    hog.setSVMDetector(cv.HOGDescriptor_getDefaultPeopleDetector())
    # Detect people in the image
    (rects, weights) = hog.detectMultiScale(src,
                                            winStride=(2,4),
                                            padding=(8, 8),
                                            scale=1.2,
                                            useMeanshiftGrouping=False)
    for (x, y, w, h) in rects:
        cv.rectangle(src, (x, y), (x + w, y + h), (0, 255, 0), 2)

    cv.imshow("hog-detector", src)
    cv.imwrite("hog-detector.jpg",src)
    cv.waitKey(0)
    cv.destroyAllWindows()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章