文章目录
HOG特征
Histogram of Oriented Gradients 直译过来就是向量梯度直方图,用来记录边缘特征,包括梯度值和梯度方向
1. 数据预处理
输入的图片像素维度可以是任意的,但是识别的一个个小模块一般都是有长宽1:2限制的,可以是100×200, 128×256,或1000×2000。如下图所示,整张图片大小是720×475,框出来的模块是100×200, 我们把它等比放缩到64×128。
预处理还有包括伽马校正和灰度化。这是可选的步骤,因为实验证明做不做影响不大。伽马校正是减少光度对实验的影响。灰度化是将彩色图片变成灰度图。其实彩色图片也可以直接处理。不过是分别对三通道的颜色值进行梯度计算,最后选择梯度最大的那个。
当然也可以不选择进行灰度处理。
2. 计算梯度大小和方向
- 若进行灰度处理,求梯度大小和方向
![](https://i-blog.csdnimg.cn/blog_migrate/8dcb6bd19382d2deab64c327f81101a8.png)
对于像素点A,要计算水平梯度和竖直梯度,如上图,水平梯度 g x = 30 − 20 = 10 g_x=30-20=10 gx=30−20=10,竖直梯度 g y = 64 − 32 = 32 g_y =64-32=32 gy=64−32=32.
那么总的梯度强度值g和梯度方向将按照以下公式计算:
g
=
g
x
2
+
g
y
2
g=\sqrt{g^2_x+g^2_y}
g=gx2+gy2
θ
=
a
r
c
t
a
n
g
y
g
x
\theta=arctan\frac{g_y}{g_x}
θ=arctangxgy
梯度方向将会取绝对值,因此梯度方向的范围是0-180度。取绝对值的原因是变为0-180区间,不用0-360是实验过程中前者效果更好,有些程序HOG特征也可以取0-360。
- 若不进行灰度处理
为了计算HOG描述符,我们需要首先计算水平和垂直梯度;毕竟,我们想要计算梯度的直方图。这很容易通过下面的核函数来过滤图像。
通过在内核大小为1的OpenCV中使用Sobel算子,我们也可以得到同样的结果。代码如下
# Read image
im = cv2.imread('bolt.png')
im = np.float32(im) / 255.0
# Calculate gradient
gx = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=1)
gy = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=1)
对于彩色图像,计算三个通道的梯度。像素处的梯度幅值为三个通道的梯度幅值的最大值,角度为最大梯度对应的角度
返回结果如下,左边是x方向上的梯度,中间图是y方向上的,而右图是这两个方向叠加的也就是
g
=
g
x
2
+
g
y
2
g=\sqrt{g^2_x+g^2_y}
g=gx2+gy2
梯度图像删除了很多不必要的信息(如固定的彩色背景),但保留了轮廓。在梯度图像里,你依然可以清楚的看到有一个人在图片中。
![](https://i-blog.csdnimg.cn/blog_migrate/17435e1cacadfc321acf759f176d1432.png)
3. 计算8×8cells的梯度直方图
![](https://i-blog.csdnimg.cn/blog_migrate/aab1fbf16ae4f0f3dddc5b910e7fb8bc.png)
我们划分为8×8的cells,我们来计算下里面包含的数,本来8×8的cells里面有8x8x3 = 192个像素值,然后每个像素值可以计算出两个值(梯度大小和方向),加起来是8x8x2 = 128个数。
但是为什么8×8 patch ?为什么不32×32 ?对于行人检测来说,将一个行人的照片中的8×8细胞按比例放大到64×128,其大小足以捕捉到有趣的特征(如脸部、头顶等),就是说8×8可以比较好的保留脸部特征,而32×32划分太小了,容易造成最后的特征数据量过大。
接着,我们需要把计算得到的8×8梯度大小和方向矩阵,整合在一起成1×9的一个新变量。我们根据梯度方向(0-180°)分为9个bin,分别是0、20…、160,接着对应统计梯度大小累计值。
具体来说,我们看蓝色的圈圈,这个像素梯度方向是80,大小为2,那我们就把大小2填到80的格子中去,再看两个红色圈圈。因为红色圈圈的方向是10,大小是4,因为10距离0点为10,距离20点为也为10,那么有一半的大小是投给0这个bin,还有一半的大小(即是2)投给20这个bin。如下图所示
还有一个细节需要注意。如果这个角大于160度,它在160和180之间,我们知道这个角等于0和180度。所以在下面的例子中,165度角的像素对0度和160度角的贡献度是成比例的。
统计完8×8cells里面64个点的投票数以后,每个bin就会得到一个数值,可以得到一个直方图,在计算机里面就是一个大小为9的数组。
4. 16×16 Block Normalization即block归一化
![](https://i-blog.csdnimg.cn/blog_migrate/81d141034df4627af2dd0e410f1108df.gif)
为了减少亮度带来的影响,比如说你通过将所有像素值除以2来使图像变暗,渐变幅度将改变一半,因此你梯度值和梯度大小这些都会少一半,我们就采取归一化的手段,就是同时除以模长,例如(1,1,1,1)归一化就是(0.25,0.25,0.25,0.25)。
现在我们知道了如何归一化向量,你可能会想,在计算HOG时,可以简单地直接除以模长来归一化9×1直方图。但是一个更好是对一个更大的16×16块进行标准化。
具体来说,我们用2×2的大方块扫过整张图,每个绿色小方块实际上是8*8大小的cell,所以蓝色方块就是由4个cell组成的block,也就是16×16大小的cell。而之前我们把8×8的拿出来计算再整合得到了9×1,那么16×16大小的cell得到的就是36×1向量,我们把这个进行归一化。然后将窗口移动8个像素(参见动画),并在此窗口上计算一个归一化的36×1向量,然后重复这个过程。
5. 得到HOG特征向量,计算维度
一个64×128的图片部分,8×8像素值划分,水平位置8个,竖直位置16个绿色小方块,每个绿色小方块包含8×8个像素值。接着16×16像素值划分,有7个水平位置和15个垂直蓝色小方块,总共7 × 15 = 105个蓝色小方块,每个蓝色小方块最后生成36×1维向量,因此最后我们得到一个36×105 = 3780维的向量。
可视化HOG
图像的HOG描述符通常通过在8×8cell中绘制9×1标准化直方图来可视化,每个绿色小方块我们刚才都得到了9×1的向量,然后这个向量根据数值可以画出直方图,我们再把直方图放上去。你会注意到直方图的主要方向捕捉了人的形状,特别是躯干和腿部周围。
参考:
https://learnopencv.com/histogram-of-oriented-gradients/
https://zhuanlan.zhihu.com/p/40960756 (知乎)