opencv实现行人检测(C++)

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时表示不起调节作用。

  1. 最后对检测出来的目标矩形框,要采用一些方法处理,比如说2个目标框嵌套着,则选择最外面的那个框。
  2. 因为hog检测出的矩形框比实际人体框要稍微大些,所以需要对这些矩形框大小尺寸做一些调整。
    opencv实现行人检测(C++)_第1张图片

一、基本思想
opencv实现行人检测(C++)_第2张图片

上图是目标检测的基本流程。

 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)

三、HOG算法流程
opencv实现行人检测(C++)_第3张图片

算法流程比较简单:

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)
opencv实现行人检测(C++)_第4张图片
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实现流程

opencv实现行人检测(C++)_第5张图片


#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;  
}  

你可能感兴趣的:(c++与opencv做图像处理)