先来说一下HOG吧,全称方向梯度直方图,是一种用来图像物体检测的描述子。
结合支持向量机,当前广泛应用于行人检测。
生成过程:
(1)图像归一化,为了减小光照等各种因素对特征目标提取的影响,对图片进行预处理。
(2)计算像素梯度,个人理解这里算是为什么这个算法对行人检测有着良好的效果,像素梯度我认为可以看作是
描述某个像素点与其周围像素点差异性的大小度量。
就像我们地理学里所知的登高设色地形图一样,我们的图像中的点的像素值就可以看作地形图的海拔高度值。
如图所示,
肉眼大致估计,向量2所指的方向就是梯度方向,这也是为什么梯度这个量对于图像边缘识别那么有用了。
像素梯度的计算公式就不多说了(天知地知,你我都知)。
(3)这一步算是开始落实我们的HOG算法的核心了,我们采取“投票制度”。
这里有一个三层级别
Pixel级(像素),Cell级(单元),Block级(块)。
Block是划分图像的第一次,通常使用的HOG结构有三种,矩形,圆形和环绕。
在进行下一步的细分,每一个块由若干个单元组成,每个单元又由若干个像素组成。
如下图所示,我们的Cell就相当于一个投票空间,每个像素都有投票的权利,每个像素都拿这个权利选择一个
方向,这个方向就是像素点自己的梯度方向。
在每个Cell中,统计票数,也就是梯度统计,以梯度方向为横坐标,梯度大小和为纵坐标绘制梯度方向直方图。
方向可以是180度(无符号),也可以是360度(有符号),然后将这个角度划分为若干个区间,
如图中所示,采用360度,每20度为一个区间,区间边界度数对应一个直方柱。
就如上图中,红色向量属于20-40度区间,那么假设它是35度,它的梯度大小为40,那么如果采取线性插值法
进行投票,若不对大小进行处理(有时候会进行权重处理,比如梯度幅值的平方等等),那么就应该向40度投票
30,向20度投票10。
在每个cell中进行上述统计绘制完整的直方图。
这里选取合适的空间大小和区间大小是最大化检测能力的关键,网上关于这方面的说法比较多,不多说了。
(4)梯度归一化
cell投票完成后,然后将cell整合成block,进行特征向量的归一化,这一步的目的是使向量空间对
光照,阴影,边缘变化具有鲁棒性。
归一化的方式有一下几种:
在人体检测当中,方法a的表现是最好的。
还有就是cell不是某个block私有的,他可能同时属于多个block,也就是block之间可能是重叠的。
(5)整合特征向量
最终得到的向量是一个Block_numCell_numOrientation_num维的向量。
以上就是对HOG特征提取的一般过程,更多理论知识网上都有,自行学习吧。
接下来,就来说一下利用Opencv自带的HOG和SVM进行行人检测的基本框架,由于本次项目有特定需求,
所以不使用它自带的已训练好的模型,决定自己进行训练。
训练基本模块组织:
(1)加载并读取正负样本
正样本:含有人体的图片若干;
负样本:不含人体的图片若干;
手动裁剪样本:hog检测窗口的大小为128*64,所以我们需要将样本进行手动裁剪,比如要进行行人检测,
就需要将样本中的行人裁剪出来,负样本不必做处理,但是要比上面这个尺寸大才行。
处理完成后分别存放在两个对应的文件夹当中。
(2)分别提取正样本和负样本的HOG特征,这里相当于原料精化的过程。
同时对正样本和负样本做标签,比如将正负样本分别标记为1和0。
提取的特征向量和标签就是分类器的输入了。
计算特征:hog.compute()
(3)分类器设置与训练
设置SVM的初始参数,包括各种核函数和损失函数等等。
一定要选择线性SVM,因为cv.HOGDescriptor()检测函数只支持线性检测。
保存参数:svm.save();
加载参数:cv.ml.SVM_load();
训练:svm.train();
(4)训练之后,保存训练结构为一个文本文件。
这个文本文件中存储着几个量:
support vector:支持向量;
alpha:约束条件参数(拉格朗日乘子,支持向量机的训练可以看作找最优alpha的过程);
rho:判决函数偏置量;
(5)自举法(bootstrap)处理难样本(hardexample)。
利用上面习得的分类器对我们的负样本进行检测,检测方法:多尺度检测
hog.detectMultiScale()
我们图片里的人有大有小,所以要给图像一个多层次的大小度量,也就是我们的图像金字塔,
在每一层中进行检测,然后做标注,将结果综合。
将负样本中错误识别出来的行人区域继续进行上述(2)过程,将得到的特征和我们第一次
得到的特征综合,再次重复(3)的训练过程。
(6)存储模型,大功告成。