Task4:HOG特征描述算子-行人检测
1 简介
HOG(Histogram of Oriented Gradients)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。通过计算和统计图像局部区域的梯度方向直方图来构成特征。Hog特征结合SVM分类器已经被广泛应用于图像识别中,在图像手工特征提取方面具有里程碑式的意义,在行人检测中获得了极大的成功。
HOG是对图像局部的梯度幅值和方向进行投票统计,从而形成基于梯度特性的直方图,最后将局部特征拼接起来作为总特征。即将图像划分为多个子块,每个子块内的特征进行联合拼接得到总特征。
2 相关流程
HOG结合SVM的工作流程如下图:
第一步输入图像并预处理,第二步计算像素点的梯度幅值和方向,第三步投票统计形成梯度直方图,第四步对blocks进行归一化,第五步将收集到HOG特征放到SVM进行监督学习,通过以上步骤实现行人检测。
2.1 图像预处理
图像预处理主要包含灰度化和Gamma变换,灰度化是可选操作,其实灰度图像和彩色图像均可以计算梯度图,但是彩色图需要先对三通道颜色值分别计算梯度,然后将梯度值最大的那个通道作为该像素点的梯度。
使用伽马矫正调节图像对比度,降低光照不均匀和局部阴影对图像的影响,即将图像恢复到接近人眼看到的图像。伽马矫正公式如下:
f
(
I
)
=
I
γ
f(I)=I^\gamma
f(I)=Iγ
其中
I
I
I为 输入图像,
γ
\gamma
γ为幂指数,
上图为
γ
\gamma
γ取不同的值时对应的输入输出曲线,
1)当
γ
>
1
\gamma>1
γ>1时,输入图像的高灰度值区域动态范围变大,则低灰度值区域对比度降低,高灰度值区域对比度增强,图像整体灰度变暗;
2)当
γ
<
1
\gamma<1
γ<1时,输入图像的低灰度值区域动态范围变大,则低灰度值区域对比度增强,高灰度值区域对比度降低,图像整体灰度变亮;
参考代码
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('task4.jpg', 0)
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
img2 = np.power(img/float(np.max(img)),5/2.2)
cv2.imshow("result", img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.2 计算图像梯度
计算图像水平方向和垂直方向梯度需要使用特定的梯度算子对输入图像进行滤波实现,常用算子有Sobel、Prewitt算子、Roberts算子等等。
利用Sobel算子求取图像水平方向和垂直方向梯度。
S
x
=
[
1
2
1
0
0
0
−
1
−
2
−
1
]
S_x=\begin{bmatrix}1 & 2 & 1\\\\0 &0 & 0\\\\\\-1 &-2 &-1\end{bmatrix}
Sx=⎣⎢⎢⎢⎢⎢⎢⎡10−120−210−1⎦⎥⎥⎥⎥⎥⎥⎤
S
y
=
[
1
0
−
1
2
0
−
2
1
0
−
1
]
S_y=\begin{bmatrix}1 & 0 & -1\\\\2 &0 & -2\\\\\\1 &0 &-1\end{bmatrix}
Sy=⎣⎢⎢⎢⎢⎢⎢⎡121000−1−2−1⎦⎥⎥⎥⎥⎥⎥⎤
G
x
=
I
(
x
,
y
)
∗
S
x
G_x=I(x,y)*S_x
Gx=I(x,y)∗Sx
G
y
=
I
(
x
,
y
)
∗
S
y
G_y=I(x,y)*S_y
Gy=I(x,y)∗Sy
由图像水平方向和垂直方向梯度得到图像梯度幅值和角度
M
(
x
,
y
)
=
G
x
2
(
x
,
y
)
+
G
y
2
(
x
,
y
)
M(x,y)=\sqrt{G_x^2(x,y)+G_y^2(x,y)}
M(x,y)=Gx2(x,y)+Gy2(x,y)
θ
=
a
r
c
t
a
n
(
G
y
/
(
G
x
)
\theta=arctan(G_y/(G_x)
θ=arctan(Gy/(Gx)
如上图所示,图像梯度方向与边缘方向是相互正交。
参考代码
import cv2
import numpy as np
# Read image
img = cv2.imread('airplane.jpg')
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)
print("gx:")
print(gx)
print("gy:")
print(gy)
# 计算合梯度的幅值和⽅向(⻆度)
mag, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True)
print("mag:")
print(mag)
print("angle:")
print(angle)
print(gx.shape,gy.shape,mag.shape,angle.shape)
2.3 计算梯度直方图
将图像分成若干个
8
∗
8
8*8
8∗8的子块,先将图像压缩至
64
x
128
64x128
64x128的尺寸,图像就被分成
8
∗
16
8*16
8∗16个
8
∗
8
8*8
8∗8的子块,计算所有子块的梯度直方图。
上图为划分示意图,中间图像为一个子块的梯度矢量,箭头朝向代表梯度方向,箭头大小代表梯度大小。
对整个子块进行投票统计得到由9个数值组成的向量—梯度方向图。
2.4 Block 归一化
参考代码
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
if __name__ == '__main__':
src = cv.imread("test2.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)
print(rects, weights)
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()
致谢
感谢Datawhale提供的资料和帮助