hog行人检测
本文主要介绍下opencv中怎样使用hog算法,因为在opencv中已经集成了hog这个类。其实使用起来是很简单的,从后面的代码就可以看出来。本文参考的资料为opencv自带的sample。
关于opencv中hog的源码分析在文末:
开发环境:opencv3.10+ubuntu14.04
说明:
1. hog描述子在opencv中为HOGDescriptor。
2. 可以调用该描述子setSVMDetector方法给用于对hog特征进行分类的svm模型的系数赋值,这里的参数为HOGDescriptor::getDefaultPeopleDetector()时表示采用系统默认的参数,因为这些参数是用很多图片训练而来的。
3. 对输入图片进行行人检测时由于图片的大小不一样,所以要用到多尺度检测。这里是用hog类的方法detectMultiScale。参数解释如下:
HOGDescriptor::detectMultiScale(const GpuMat& img, vector& found_locations, doublehit_threshold=0, Size win_stride=Size(), Size padding=Size(), double scale0=1.05, int group_threshold=2)
该函数表示对输入的图片img进行多尺度行人检测 img为输入待检测的图片;found_locations为检测到目标区域列表;参数3为程序内部计算为行人目标的阈值,也就是检测到的特征到SVM分类超平面的距离;参数4为滑动窗口每次移动的距离。它必须是块移动的整数倍;参数5为图像扩充的大小;参数6为比例系数,即滑动窗口每次增加的比例;参数7为组阈值,即校正系数,当一个目标被多个窗口检测出来时,该参数此时就起了调节作用,为0时表示不起调节作用。
上图是目标检测的基本流程。
HOG属于特征提取,它统计梯度直方图特征。具体来说就是将梯度方向(0->360°)划分为9个区间,将图像化为16x16的若干个block,每个block在化为4个cell(8x8)。对每一个cell,算出每一点的梯度方向和模,按梯度方向增加对应bin的值,最终综合N个cell的梯度直方图形成一个高维描述子向量。实际实现的时候会有各种插值。
选用的分类器是经典的SVM。
检测框架为经典的滑动窗口法,即在位置空间和尺度空间遍历搜索检测。
二、基本概念
原始图像打完补丁后就直接用固定的窗口在图像中移动,计算检测窗口下的梯度,形成描述子向量,然后就直接SVM了
![这里写图片描述](https://img-blog.csdn.net/20170816213751887?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhb19fcnVu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
算法流程比较简单:
1、gamma校正
r=0.5,暗区对比度提高,亮区对比度下降
2、计算梯度
微分算子[-1 0 1],取RGB通道中模值最大的为该像素点的梯度。
插值策略:对与该点梯度方向相邻的两个bin按距离进行线性插值。
3 、权值
高斯权值:与到block中心负相关,对于图中的大圆圈
cell中心权值:到对称cell中心的“距离”正相关,对应下图中小方块到十字的距离。
这一部分比较复杂, 每一个像素点还要对cell插值。
1)F,J,G,K区域内的像素点对四个cell都有贡献,比如P4对cell 0 的权重是倒对称cell中心即cell 3的“距离” P4-cell 3 即图中绿色虚线的“长度”,对其它cell 的权值依次类推
2)B,C,E,I,N,O,H,L区域的像素点要对两个cell中心插值。比如P2虽然处在cell 1中,但是对cell 0 也有贡献,对虚线中的红,绿两个十字所在的cell 也有贡献。那对cell 0的权重计算方法同P4。
取到对称cell 中心的 “距离”,即到绿色中心的“距离”。
3)A,D,M,P,区域的点对周围的四个cell也有贡献,但是block覆盖的只有一个cell,自然只要对其本身所在的cell插值即可。比如P1,到对称cell 中心的“距离”,即图中的cell中心。
但是要注意:cell的编号顺序是从上到下,从左到右,即(cell 0 cell 1 cell 2 cell 3)但是四个cell的偏移量存储顺序却是(cell 0 ->cell 2 ->cell 1->cell 3)
4、归一化
L2 Hys归一化,比较简单
5、获取整个检测窗口内的所有block的梯度直方图组成一个很高很高维的描述子向量
用查表替代了八重循环,大大减少了时间开销。
最笨的方法是依次循环:
1.检测窗口在输入图像中滑动
2.block在检测窗口win中滑动
3.cell在block中滑动
4.在cell中循环获取像素的梯度值
每一层循环都是2维的这样下来就是八重循环…………子子孙孙无穷尽也
作者通过预先计算好的pixData,blockData基本上化为了3重循环。
1.循环图像中的每一个检测窗口win
2.循环检测窗口内的每一个block
3.循环每一个block中的像素点,getblock()
每一层都是一维。
6、SVM分类
计算到分类超平面的距离
四、HOG算法OpenCV实现流程
#include
#include
int main(int argc, char** argv)
{
cv::Mat image = cv::imread("test.bmp");
if (image.empty())
{
std::cout<<"read image failed"<<std::endl;
}
// 1. 定义HOG对象
cv::HOGDescriptor hog; // 采用默认参数
// 2. 设置SVM分类器
hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector()); // 采用已经训练好的行人检测分类器
// 3. 在测试图像上检测行人区域
std::vector regions;
hog.detectMultiScale(image, regions, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 1);
// 显示
for (size_t i = 0; i < regions.size(); i++)
{
cv::rectangle(image, regions[i], cv::Scalar(0,0,255), 2);
}
cv::imshow("hog", image);
cv::waitKey(0);
return 0;
}