HOG特征提取
如果可以还是要看第一手资料,看原始论文,避免被人误导。
原论文:Histograms of Oriented Gradients for Human Detection
详细信息可以参考其博士论文:Finding People in Images and Videos
计算流程:
RGB colour space with no gamma correction; [−1; 0; 1] gradient filter with no smoothing; linear gradient voting into 9 orientation bins in 0◦–180◦; 16×16 pixel blocks of four 8×8 pixel cells; Gaussian spatial window with σ = 8 pixel; L2-Hys (Lowe-style clipped L2 norm) block normalization; block spacing stride of 8 pixels (hence 4-fold coverage of each cell); 64×128 detection window; linear SVM classifier.
最佳梯度 模板[−1; 0; 1]。
Simple 1-D [−1; 0; 1] masks at σ=0 work best. Using larger masks always seems to decrease performance, and smoothing damages it significantly.
HOG特征的提取过程为:
Gamma归一化;
计算梯度;
划分cell
组合成block,统计block直方图;
梯度直方图归一化;
收集HOG特征。
Gamma归一化:
对图像颜色进行Gamma归一化处理,降低局部阴影及背景因素的影响.
计算梯度:
通过差分计算出图像在水平方向上及垂直方向上的梯度:
然后得到各个像素点的梯度的幅值及方向:
划分cell
将整个窗口划分成大小相同互不重叠的细胞单元cell(如8×8像素),计算出每个cell的梯度大小及方向.然后将每像素的梯度方向在0−180o0−180o 区间内(无向:0-180,有向:0-360)平均分为9个bins,每个cell内的像素用幅值来表示权值,为其所在的梯度直方图进行加权投票.
9bins:
组合成block,统计block直方图
将2×2个相邻的cell组成大小为16×16的像素块即block.依次将block大小的滑动窗口从左到右从上到下滑动,求其梯度方向直方图向量.
从论文中的不同大小的cell与不同大小的block作用下的效果对比图看,最佳的block size和cell size组合是3×3 block size 6×6 cell size。但是实际应用中使用的多是 2×2 block size 8×8 cell size,具体原因待补充。
原文解释:
Fig. 5 plots the miss rate at 10−4 FPPW w.r.t. cell size and block size in cells. For human detection, 3×3 cell blocks of 6×6 pixel cells perform best, with 10.4% miss-rate at 10−4 FPPW. In fact, 6–8 pixel wide cells
do best irrespective of the block size – an interesting coincidence as human limbs are about 6–8 pixels across in our images. 2×2 and 3×3 blocks work best. Beyond this, the results deteriorate: adaptivity to local
imaging conditions is weakened when the block becomes too big, and when it is too small (1×1 block / normalization over orientations alone) valuable spatial information is suppressed.
梯度直方图归一化
作者对比了L2-norm、L1-norm、L1-sqrt等归一化方法,发现都比非标准数据有显着的改善.其中L2-norm和L1-sqrt效果最好,而L1-norm检测效果要比L2-norm和L1-sqrt低5%.
这样通过归一化能够进一步地对光照、阴影和边缘进行压缩.
收集HOG特征
由于每个cell内的梯度方向分成了9个bins,这样每个细胞单元的HOG特征向量长度是9.
这样,对于大小为128×64大小的图像,采用8*8像素的sell,2×2个cell组成的16×16像素的block,采用8像素的block移动步长,这样检测窗口block的数量有((128-16)/8+1)×((64-16)/8+1)=15×7.则HOG特征描述符的维数为15×7×4×9.
上面的计算表达式((128-16)/8+1)×((64-16)/8+1)=15×7可以参考如下的卷积计算公式。
N=(W-F+2P)/S+1
其中N:输出大小
W:输入大小
F:卷积核大小
P:填充值的大小
S:步长大小
动画辅助理解:
计算梯度直方图
在这一步,我们先把整个图像划分为若干个8x8的小单元,称为cell,并计算每个cell的梯度直方图。这个cell的尺寸也可以是其他值,根据具体的特征而定。
为什么我们要把图像分成若干个8x8的小单元?
这是因为对于一整张梯度图,其中的有效特征是非常稀疏的,不但运算量大,而且效果可能还不好。于是我们就使用特征描述符来表示一个更紧凑的特征。一个8x8的小单元就包含了8x8x2 = 128个值,因为每个像素包括梯度的大小和方向。
现在我们要把这个8x8的小单元用长度为9的数组来表示,这个数组就是梯度直方图。这种表示方法不仅使得特征更加紧凑,而且对单个像素值的变化不敏感,也就是能够抗噪声干扰。
我们来看一下图片中的一个cell中的梯度:
中间那张图中的箭头表示梯度,箭头方向表示梯度方向,箭头长度表示梯度大小。
右图是 8×8 的cell中表示梯度的原始数字,注意角度的范围介于0到180度之间,而不是0到360度, 这被称为“无符号”梯度,因为两个完全相反的方向被认为是相同的。
现在我们来计算cell中像素的梯度直方图,先将角度范围分成9份,也就是9 bins,每20°为一个单元,也就是这些像素可以根据角度分为9组。将每一份中所有像素对应的梯度值进行累加,可以得到9个数值。直方图就是由这9个数值组成的数组,对应于角度0、20、40、60... 160。
比如上面方向图中蓝圈包围的像素,角度为80度,这个像素对应的幅值为2,所以在直方图80度对应的bin加上2。红圈包围的像素,角度为10度,介于0度和20度之间,其幅值为4,那么这个梯度值就被按比例分给0度和20度对应的bin,也就是各加上2。
还有一个细节需要注意,如果某个像素的梯度角度大于160度,也就是在160度到180度之间,那么把这个像素对应的梯度值按比例分给0度和160度对应的bin。
将这 8x8 的cell中所有像素的梯度值加到各自角度对应的bin中,就形成了长度为9的直方图:
可以看到直方图中,0度和160附近有很大的权重,说明了大多数像素的梯度向上或者向下,也就是这个cell是个横向边缘。
现在我们就可以用这9个数的梯度直方图来代替原来很大的三维矩阵,即代替了8x8x2个值。
Block 归一化
HOG将8×8的一个区域作为一个cell,再以2×2个cell作为一组,称为block。由于每个cell有9个值,2×2个cell则有36个值,HOG是通过滑动窗口的方式来得到block的,如下图所示:
![](https://pic4.zhimg.com/v2-2324177420c0a79d48d844b5e124f1f3_b.jpg)
在前面的步骤中,我们基于图像的梯度对每个cell创建了一个直方图。
但是图像的梯度对整体光照非常敏感,比如通过将所有像素值除以2来使图像变暗,那么梯度幅值将减小一半,因此直方图中的值也将减小一半。 理想情况下,我们希望我们的特征描述符不会受到光照变化的影响,那么我们就需要将直方图“归一化” 。
在说明如何归一化直方图之前,先看看长度为3的向量是如何归一化的。
假设我们有一个向量 [128,64,32]
,向量的长度为 ,这叫做向量的L2范数。将这个向量的每个元素除以146.64就得到了归一化向量
[0.87, 0.43, 0.22]
。
现在有一个新向量,是第一个向量的2倍 [128x2, 64x2, 32x2],也就是 [256, 128, 64]
,我们将这个向量进行归一化,你可以看到归一化后的结果与第一个向量归一化后的结果相同。所以,对向量进行归一化可以消除整体光照的影响。
知道了如何归一化,现在来对block的梯度直方图进行归一化(注意不是cell),一个block有4个直方图,将这4个直方图拼接成长度为36的向量,然后对这个向量进行归一化。
因为使用的是滑动窗口,滑动步长为8个像素,所以每滑动一次,就在这个窗口上进行归一化计算得到长度为36的向量,并重复这个过程。
计算HOG特征向量
终于可以计算整个图像的特征描述符了,每滑动一次,一个block就得到一个长度为36的特征向量,那会得到多少个特征向量呢?
比如上面这个图,将整幅图像划分成cell的个数为8x16,就是横向有8个cell,纵向有16个cell。每个block有2x2个cell的话,那么cell的个数为:(16-1)x(8-1)=105。即有7个水平block和15个竖直block。
再将这105个block合并,就得到了整个图像的特征描述符,长度为 105×36=3780。
只看理论应该就是这样了,但是在实现过程中有一些不得不需要考虑的问题:
问题一、图片尺寸问题
这个问题比较容易解决,可以将图片统一归一化到固定尺寸,比如128×64.
问题二、梯度计算问题
很多人第一反应,梯度计算会有问题么,不就是直接卷积梯度模板就可以了,其实模板[-1,0,1]不能计算边缘像素的梯度,不考虑边缘,卷积后的图像就会比原图宽高都小2个像素。然后图像就不是原本cell尺寸的整数倍,
后面的步骤都无法进行。我看了一下matlab中对边缘像素计算梯度时的处理,即对水平方向第一行梯度为第二行减去第一行,最后一行梯度为最后一行减去其前一行;竖直方向第一列梯度为第二列减去第一列,最后一列梯度为最后一列减去其前一列。这样计算后的梯度图像尺寸还是和原图是一样的,可以继续用于后续操作。
问题三、重复计算问题
为了提高计算效率就要避免重复计算问题,从前面的动态图可以看到,滑动的Block与前一个(如果有的话)Block有一半的重叠,与上一层的(如果有的话)Block有一半的重叠。消除重复计算就可以提高计算效率。
解决这个问题就需要一次计算并记录数据,在需要使用的时候调用就可以了。(当然opencv中除了避免重复计算加速还有指令集加速,关于指令集加速不在这里讨论。)
参考博客:https://blog.csdn.net/zhazhiqiang/article/details/21047207
参考博客:https://www.jb51.net/article/176145.htm
参考博客:https://blog.csdn.net/sinat_42239797/article/details/90646935
参考:https://zhuanlan.zhihu.com/p/85829145
参考:https://www.learnopencv.com/histogram-of-oriented-gradients/
下面例举一些以讹传讹的博客:网上资源有对有错,对错只能靠自己去分辨,以其昏昏,使人昭昭是不可能帮助别人的。
内容有错误的博客:https://blog.csdn.net/krais_wk/article/details/81119237 (这篇错误的博客还有还几篇类似错误的博客,希望大家避开)