HOG(Histogram of Oriented Gradients)——方向梯度直方圖,是一種表示圖像特征量的方法,特征量是表示圖像的狀態等的向量集合。
在圖像識別(圖像是什么)和檢測(物體在圖像的哪個位置)中,我們需要:
- 從圖像中獲取特征量(特征提取);
- 基於特征量識別和檢測(識別和檢測);
由於深度學習通過卷積網絡自動執行特征提取和識別,所以看不到HOG,但在深度學習變得流行之前,HOG經常被用作特征量表達。
獲得HOG算法如下:
- 圖像灰度化,然后在x方向和y方向上求出亮度的梯度:
- x方向:

- y方向:

- x方向:
- 從g_x和g_y確定梯度幅值和梯度方向:
- 梯度幅值:

- 梯度方向:

- 梯度幅值:
- 將梯度方向[0,180]進行9等分量化。也就是說,對於[0,20]量化為index 0,對於[20,40]量化為index 1......
- 將圖像划分為N x N個區域(該區域稱為cell),並作出cell內上一步得到的index的直方圖。
- C x C個cell被稱為一個block,對每個block內的cell的直方圖通過下面的式子進行歸一化。由於歸一化過程中窗口一次移動一個cell來完成,因此一個cell會被歸一化多次,通常ε=1。

- 以上,求出HOG特征值。
- 將得到的特征量可視化。為 cell 內的每個 index 的方向畫一條線段,並且值越大,線段越白,
值越小,線段越黑。
import cv2
import numpy as np
import matplotlib.pyplot as plt
# get HOG
def HOG(img):
# Grayscale
def BGR2GRAY(img):
gray = 0.2126 * img[..., 2] + 0.7152 * img[..., 1] + 0.0722 * img[..., 0]
return gray
# Magnitude and gradient
def get_gradXY(gray):
H, W = gray.shape
# padding before grad
gray = np.pad(gray, (1, 1), 'edge')
# get grad x
gx = gray[1:H+1, 2:] - gray[1:H+1, :W]
# get grad y
gy = gray[2:, 1:W+1] - gray[:H, 1:W+1]
# replace 0 with
gx[gx == 0] = 1e-6
return gx, gy
# get magnitude and gradient
def get_MagGrad(gx, gy):
# get gradient maginitude
magnitude = np.sqrt(gx ** 2 + gy ** 2)
# get gradient angle
gradient = np.arctan(gy / gx)
gradient[gradient < 0] = np.pi / 2 + gradient[gradient < 0] + np.pi / 2
return magnitude, gradient
# Gradient quantization
def quantization(gradient):
# prepare quantization table
gradient_quantized = np.zeros_like(gradient, dtype=np.int)
# quantization base
d = np.pi / 9
# quantization
for i in range(9):
gradient_quantized[np.where((gradient >= d * i) & (gradient <= d * (i + 1)))] = i
return gradient_quantized
# get gradient histogram
def gradient_histogram(gradient_quantized, magnitude, N=8):
# get shape
H, W = magnitude.shape
# get cell num
cell_N_H = H // N
cell_N_W = W // N
histogram = np.zeros((cell_N_H, cell_N_W, 9), dtype=np.float32)
# each pixel
for y in range(cell_N_H):
for x in range(cell_N_W):
for j in range(N):
for i in range(N):
histogram[y, x, gradient_quantized[y * 4 + j, x * 4 + i]] += magnitude[y * 4 + j, x * 4 + i]
return histogram
# histogram normalization
def normalization(histogram, C=3, epsilon=1):
cell_N_H, cell_N_W, _ = histogram.shape
## each histogram
for y in range(cell_N_H):
for x in range(cell_N_W):
#for i in range(9):
histogram[y, x] /= np.sqrt(np.sum(histogram[max(y - 1, 0) : min(y + 2, cell_N_H),
max(x - 1, 0) : min(x + 2, cell_N_W)] ** 2) + epsilon)
return histogram
# 1. BGR -> Gray
gray = BGR2GRAY(img)
# 1. Gray -> Gradient x and y
gx, gy = get_gradXY(gray)
# 2. get gradient magnitude and angle
magnitude, gradient = get_MagGrad(gx, gy)
# 3. Quantization
gradient_quantized = quantization(gradient)
# 4. Gradient histogram
histogram = gradient_histogram(gradient_quantized, magnitude)
# 5. Histogram normalization
histogram = normalization(histogram)
return histogram
# draw HOG
def draw_HOG(img, histogram):
# Grayscale
def BGR2GRAY(img):
gray = 0.2126 * img[..., 2] + 0.7152 * img[..., 1] + 0.0722 * img[..., 0]
return gray
def draw(gray, histogram, N=8):
# get shape
H, W = gray.shape
cell_N_H, cell_N_W, _ = histogram.shape
## Draw
out = gray[1 : H + 1, 1 : W + 1].copy().astype(np.uint8)
for y in range(cell_N_H):
for x in range(cell_N_W):
cx = x * N + N // 2
cy = y * N + N // 2
x1 = cx + N // 2 - 1
y1 = cy
x2 = cx - N // 2 + 1
y2 = cy
h = histogram[y, x] / np.sum(histogram[y, x])
h /= h.max()
for c in range(9):
#angle = (20 * c + 10 - 90) / 180. * np.pi
# get angle
angle = (20 * c + 10) / 180. * np.pi
rx = int(np.sin(angle) * (x1 - cx) + np.cos(angle) * (y1 - cy) + cx)
ry = int(np.cos(angle) * (x1 - cx) - np.cos(angle) * (y1 - cy) + cy)
lx = int(np.sin(angle) * (x2 - cx) + np.cos(angle) * (y2 - cy) + cx)
ly = int(np.cos(angle) * (x2 - cx) - np.cos(angle) * (y2 - cy) + cy)
# color is HOG value
c = int(255. * h[c])
# draw line
cv2.line(out, (lx, ly), (rx, ry), (c, c, c), thickness=1)
return out
# get gray
gray = BGR2GRAY(img)
# draw HOG
out = draw(gray, histogram)
return out
# Read image
img = cv2.imread("../baby.png").astype(np.float32)
# get HOG
histogram = HOG(img)
# draw HOG
out = draw_HOG(img, histogram)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()


