织梦CMS - 轻松建站从此开始!

罗索

opencv源码解析之(6):hog源码分析

落鹤生 发布于 2014-08-16 22:53 点击:次 
在博客目标检测学习_1(用opencv自带hog实现行人检测) 中已经使用了opencv自带的函数detectMultiScale()实现了对行人的检测,当然了,该算法采用的是hog算法,那么hog算法是怎样实现的呢?这一节就来简单分析一下opencv中自带 hog源码。
TAG: 目标检测  行人检测  

一、网上一些参考资料

       在博客目标检测学习_1(用opencv自带hog实现行人检测) 中已经使用了opencv自带的函数detectMultiScale()实现了对行人的检测,当然了,该算法采用的是hog算法,那么hog算法是怎样实现的呢?这一节就来简单分析一下opencv中自带 hog源码。

       网上也有不少网友对opencv中的hog源码进行了分析,很不错,看了很有收获。比如:

    http://blog.csdn.net/raocong2010/article/details/6239431

    该博客对该hog算法中用到的block,cell等概念有一定的图标解释;

    http://blog.csdn.net/pp5576155/article/details/7029699

    该博客是转载的,里面有opencv源码的一些注释,很有帮助。

    http://gz-ricky.blogbus.com/logs/85326280.html

    本博客对hog描述算子长度的计算做了一定介绍。

    http://hi.baidu.com/susongzhi/item/3a3c758d7ff5cbdc5e0ec172

    该博客对hog中快速算法的三线插值将得很详细。

    http://blog.youtueye.com/work/opencv-hog-peopledetector-trainning.html

    这篇博客对hog怎样训练和检测做了一定的讲解。

 

         二、关于源码的一些简单说明

         本文不是讲解hog理论的,所以需要对hog算法有一定了解,这些可以去参考hog提出者的博士论文,写得很详细。

         按照正常流程,hog行人检测分为训练过程和检测过程,训练过程主要是训练得到svm的系数。在opencv源码中直接采用训练好了的svm系数,所以训练过程源码中没有涉及到多少。

   首先还是对hog源码中一些固定参数来个简单说明:

   检测窗口大小为128*64;

   Block大小为16*16;

   Cell大小为8*8;

   Block在检测窗口中上下移动尺寸为8*8;

   1个cell的梯度直方图化成9个bin;

   滑动窗口在检测图片中滑动的尺寸为8*8;

   代码中的一个hog描述子是针对一个检测窗口而言的,所以一个检测窗口共有105= ((128-16)/8+1)*((64-16)/8+1)个block;一个block中有4个cell,而一个cell的hog描述子向量的长度为 9;所以检测窗口的hog向量长度=3780=105*4*9维。

 

         三、hog训练部分流程的简单理解

         虽然hog源码中很少涉及到训练部分的代码,不过了解下训练过程的流程会对整个检测过程有个整体认识。

         训练过程中正样本大小统一为128*64,即检测窗口的大小;该样本图片可以包含1个或多个行人。对该图片提前的hog特征长度刚好为3780维,每一个 特征对应一个正样本标签进行训练。在实际的训练过程中,我们并不是去google上收集或者拍摄刚好128*64大小且有行人的图片,而是收集包含行人的 任意图片(当然了,尺寸最好比128*64大),然后手工对这些正样本进行标注,即对有行人的地方画个矩形,其实也就是存了2个顶点的坐标而已,并把这个 矩形的信息存储起来;最好自己写一个程序,每读入一张图片,就把矩形区域的内容截取出来并缩放到统一尺寸128*64,这样,对处理过后的该图片进行 hog特征提取就可以当做正样本了。

         负样本不需要统一尺寸,只需比128*64大,且图片中不能包含任何行人。实际过程中,由于是负样本,里面没有目标信息,所以不需要人工进行标注。程序中可以对该图片随机进行截取128*64大小的图片,并提取出其hog特征作为负样本。

 

         四、hog行人检测过程

         检测过程中采用的是滑动窗口法,对应本代码中,滑动窗口法的流程如下:

 

         由上图可以看出,检测时,会对输入图片进行尺度缩放(一般是缩小),在每一层的图像上采用固定大小的滑动窗口(128*64)滑动,没个滑动窗口都提取出hog特征,送入到svm分类器中,看该窗口中是否有目标。有则存下目标区域来,无则继续滑动。

         检测过程中用到的函数为detectMultiScale(),其参数分配图如下。 

         五、计算检测窗口中图像的梯度

         计算梯度前如果需要gamma校正的话就先进行gamma校正,所谓的gamma校正就是把原来的每个通道像素值范围从0~255变换到 0~15.97(255开根号)。据作者说这样校正过后的图像计算的效果会更好,在计算梯度前不需要进行高斯滤波操作。

         梯度的计算是分别计算水平梯度图和垂直梯度图,然后求幅值和相位。水平梯度卷积算子为:

      

    垂直梯度卷积算子为:

     

         在阅读该源码的时候,要特别注意梯度幅值和角度的存储方式。因为是对一个滑动窗口里的图像进行的,所以梯度幅值和角度按照道理来说应该都是128*64=8192维的向量。但实际过程中这2者都是用的128*64*2=16384维的向量。为什么呢?

         因为这里的梯度和角度都是用到了二线插值的。每一个点的梯度角度可能是0~180度之间的任意值,而程序中将其离散化为9个bin,即每个bin占20 度。所以滑动窗口中每个像素点的梯度角度如果要离散化到这9个bin中,则一般它都会有2个相邻的bin(如果恰好位于某个bin的中心,则可认为对该 bin的权重为1即可)。从源码中可以看到梯度的幅值是用来计算梯度直方图时权重投票的,所以每个像素点的梯度幅值就分解到了其角度相邻的2个bin了, 越近的那个bin得到的权重越大。因此幅度图像用了2个通道,每个通道都是原像素点幅度的一个分量。同理,不难理解,像素点的梯度角度也用了2个通道,每 个通道中存储的是它相邻2个bin的bin序号。序号小的放在第一通道。

         二线插值的示意图如下:

 

 

         其中,假设那3条半径为离散化后bin的中心,红色虚线为像素点O(像素点在圆心处)的梯度方向,梯度幅值为A,该梯度方向与最近的相邻bin为 bin0,这两者之间的夹角为a.这该像素点O处存储的梯度幅值第1通道为A*(1-a),第2通道为A*a;该像素点O处存储的角度第1通道为 0(bin的序号为0),第2通道为1(bin的序号为1)。

         另外在计算图像的梯度图和相位图时,如果该图像时3通道的,则3通道分别取梯度值,并且取梯度最大的那个通道的值为该点的梯度幅值。

         六、HOG缓存结构体

         HOG缓存思想是该程序作者加快hog算法速度采用的一种内存优化技术。由于我们对每幅输入图片要进行4层扫描,分别为图像金字塔层,每层中滑动窗口,每 个滑动窗口中滑动的block,每个block中的cell,其实还有每个cell中的像素点;有这么多层,每一层又是一个二维的,所以速度非常慢。作者 的采用的思想是HOG缓存,即把计算得到的每个滑动窗口的数据(其实最终是每个block的hog描述子向量)都存在内存查找表中,由于滑动窗口在滑动 时,很多个block都会重叠,因此重叠处计算过的block信息就可以直接从查找表中读取,这样就节省了很多时间。

         在这个HOG存储结构体中,会计算滑动窗口内的hog描述子,而这又涉及到滑动窗口,block,cell直接的关系,其之间的关系可以参考下面示意图:

 

         外面最大的为待检测的图片,对待检测的图片需要用滑动窗口进行滑动来判断窗口中是否有目标,每个滑动窗口中又有很多个重叠移动的block,每个 block中还有不重叠的cell。其实该程序的作者又将每个block中的像素点对cell的贡献不同,有将每个cell分成了4个区域,即图中蓝色虚 线最小的框。

         那么block中不同的像素点对它的cell(默认参数为1个block有4个cell)的影响是怎样的呢?请看下面示意图。

         

         如果所示,黑色框代表1个block,红实线隔开的为4个cell,每个cell用绿色虚线隔开的我们称之为4个区域,所以该block中共有16个区域,分别为A、B、C、…、O、P。

         程序中将这16个区域分为4组:

         第1组:A、D、M、P;该组内的像素点计算梯度方向直方图时只对其所在的cell有贡献。

         第2组:B、C、N、O;该组内的像素点计算梯度直方图时对其所在的左右cell有贡献。

         第3组:E、I、H、L;该组内的像素点计算梯度直方图时对其所在的上下cell有贡献。

         第4组:F、G、J、K;该组内的像素点对其上下左右的cell计算梯度直方图时都有贡献。

         那到底是怎么对cell贡献的呢?举个例子来说,E区域内的像素点对cell0和cell2有贡献。本来1个block对滑动窗口贡献的向量维数为36 维,即每个cell贡献9维,其顺序分别为cell0,cell1,cell2,cell3.而E区域内的像素由于同时对cell0和cell2有贡献, 所以在计算E区域内的像素梯度投票时,不仅要投向它本来的cell0,还要投向下面的cell2,即投向cell0和cell2有一个权重,该权重与该像 素点所在位置与cell0,cell2中心位置的距离有关。具体的关系可以去查看源码。

         该结构体变量内存分配图如下,可以增强读代码的直观性:

 

           在读该部分源码时,需要特别注意以下几个地方:

    1)         结构体BlockData中有2个变量。1个BlockData结构体是对应的一个block数据。histOfs和imgOffset.其中 histOfs表示为该block对整个滑动窗口内hog描述算子的贡献那部分向量的起始位置;imgOffset为该block在滑动窗口图片中的坐标 (当然是指左上角坐标)。

    2)         结构体PixData中有5个变量,1个PixData结构体是对应的block中1个像素点的数据。其中gradOfs表示该点的梯度幅度在滑动窗口图 片梯度幅度图中的位置坐标;qangleOfs表示该点的梯度角度在滑动窗口图片梯度角度图中的位置坐标;histOfs[]表示该像素点对1个或2个或 4个cell贡献的hog描述子向量的起始位置坐标(比较抽象,需要看源码才懂)。histWeight[]表示该像素点对1个或2个或4个cell贡献 的权重。gradWeight表示该点本身由于处在block中位置的不同因而对梯度直方图贡献也不同,其权值按照二维高斯分布(以block中心为二维 高斯的中心)来决定。

    3)         程序中的count1,cout2,cout4分别表示该block中对1个cell、2个cell、4个cell有贡献的像素点的个数。

 

    七、其他一些函数

    该程序中还有一些其它的函数。

    getblock()表示的是给定block在滑动窗口的位置以及图片的hog缓存指针,来获得本次block中计算hog特征所需要的信息。

    normalizeBlockHistogram()指对block获取到的hog部分描述子进行归一化,其实该归一化有2层,具体看代码。

    windowsInImage()实现的功能是给定测试图片和滑动窗口移动的大小,来获得该层中水平和垂直方向上需要滑动多少个滑动窗口。

    getWindow()值获得一个滑动窗口矩形。

    compute()是实际上计算hog描述子的函数,在测试和训练阶段都能用到。

    detect()是检测目标是用到的函数,在detectMultiScale()函数内部被调用。

 

         八、关于HOG的初始化

         Hog初始化可以采用直接赋初值;也直接从文件节点中读取(有相应的格式,好像采用的是xml文件格式);当然我们可以读取初始值,也可以在程序中设置 hog算子的初始值并写入文件,这些工作可以采用源码中的read,write,load,save等函数来完成。

 

         九、hog源码的注释

         在读源码时,由于里面用到了intel的ipp库,优化了算法的速度,所以在程序中遇到#ifdef HAVE_IPP后面的代码时,可以直接跳过不读,直接读#else后面的代码,这并不影响对原hog算法的理解。

         首先来看看hog源码中用到的头文件目录图,如下:

 

 

    下面是我对hog源码的一些注释,由于本人接触c++比较少,可能有些c++的语法常识也给注释起来了,还望大家能理解。另外程序中还有一些细节没有读懂,或者说是注释错了的,大家可以一起来讨论下,很多细节要在源码中才能看懂。

(tornadomeet)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201408/17024.html]
本文出处:博客园 作者:tornadomeet 原文
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容