# 方向梯度直方图HOG
# 1.关于HOG
HOG是2005年发表的论文Histograms of Oriented Gradients for Human Detection (opens new window)中提出的,方向梯度直方图Histograms of Oriented Gradients
用于早期的行人检测方法,文章至今引用已超过41500
次,是一种非常经典的提取图像特征的方法。要想计算HOG
需要先计算图像的梯度。
# 2.计算x,y方向的梯度 和
图像可以看成是离散二元函数
离散二元函数的偏导数可以使用有限差分来近似计算,图像偏导可写成如下形式:
上面是前向差分求梯度,还可以使用后向差分,
除了前向差分/后向差分外,还可以使用中心差分:
可以使用OpenCV
种的Sobel
函数来求图像的梯度:
grad_x = cv2.Sobel(image, ddepth, 1, 0, ksize=1, borderType=cv2.BORDER_DEFAULT)
上面代码dx=1,dy=0
表示求图像x
方向的一阶导数,ksize=1
表示使用的是1x3
的卷积核,如下:
grad_y = cv2.Sobel(image, ddepth, 0, 1, ksize=1, borderType=cv2.BORDER_DEFAULT)
上面代码dx=0,dy=1
表示求图像y
方向的一阶导数,ksize=1
表示使用的是3x1
的卷积核,如下:
borderType
表示的是对图像边沿的处理方式,OpenCV
中给出的图像边沿处理方式有:
如下图,是一幅图像x,y
方向梯度求解的过程
求得
使用OpenCV
中提供的函数可以很方便的求得上面的两个值:
mag, angle = cv2.cartToPolar(np.float64(grad_x), np.float64(grad_y), angleInDegrees=True)
到这里就计算得到了图像的梯度,下面开始介绍方向梯度直方图。
# 3.计算HOG
得到一幅图像的梯度后,接下来将图像分成cwxch
大小的cell
,cw
和ch
通常取为8x8
,cw
和ch
的选择要结合自己的图像数据,HOG
最早应用在行人识别上,图像大小为64×128
,因此8x8
的cell
足以用来表示人体的特征,如人脸
等。
对于图像的每个8x8
的cell
,取对应的梯度幅值和角度,如下图:
将梯度角度分成bins
份来绘制8x8 cell
中的梯度直方图,如分成9
份,对应的角度分别为0,20,40,60,...160
。上图中间的小图中,箭头表示梯度方向,箭头长度表示梯度幅值的大小。右边的图中梯度角度的范围为[0, 180]
,只表示是水平边沿还是垂直边沿,并不判断上下左右,被称为"无符号梯度"。
如上图表示一个cell
梯度直方图的生成过程,蓝色位置,角度为80
,幅值为2
,加到对应直方图向量上,红色位置,角度为10
,幅值为4
,分到0处的梯度幅值165
幅度为85
时,将幅值对应到0度和160度上算直方图,分到0处的梯度幅值cell
的梯度直方图如下:
根据前面介绍的梯度计算过程,可知梯度幅度受光照影响大,当灰度值变大时,梯度值也会跟着变大,为了减小光照的影响,可以对梯度直方图做归一化。
对彩色像素L2
范数的归一化过程为:
上面,当向量变成
HOG
的计算中,会将2x2
个前面介绍的8x8 cell
组合到一起成block
,将每个cell
的直方图向量拼接到一起,作为这个block
的特征向量。前面介绍的每个cell
的直方图包含9
个bin
,组合后每个block
包含36
个bin,对这个36
个元素的向量使用L2
范数归一化得到每个block
的特征向量。
# 4.skimage计算HOG
代码来自skimage手册
import matplotlib.pyplot as plt
from skimage.feature import hog
from skimage import data, exposure
image = data.astronaut()
fd, hog_image = hog(image, orientations=8, pixels_per_cell=(16, 16),
cells_per_block=(1, 1), visualize=True, channel_axis=-1)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4), sharex=True, sharey=True)
ax1.axis('off')
ax1.imshow(image, cmap=plt.cm.gray)
ax1.set_title('Input image')
# Rescale histogram for better display
hog_image_rescaled = exposure.rescale_intensity(hog_image, in_range=(0, 10))
ax2.axis('off')
ax2.imshow(hog_image_rescaled, cmap=plt.cm.gray)
ax2.set_title('Histogram of Oriented Gradients')
plt.show()