Opencv中Hog算法流程

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u010484388/article/details/53860097

参考记录

(1)opencv之HOG源代码注释
链接http://blog.csdn.net/antter0510/article/details/20564627
主要参考该博文进行解析,该博文注释比较详细,
(2)opencv之HOG源代码分析
http://blog.csdn.net/antter0510/article/details/20565045
该博文是(1)的姊妹篇,主要对hog算子用到的各个重要函数做了解析。
(3)opencv源码解析之(6):hog源码分析
http://www.cnblogs.com/tornadomeet/archive/2012/08/15/2640754.html
该篇博文的1到8节值得进行学习。
(4)HOG:从理论到OpenCV实践
http://blog.csdn.net/zhazhiqiang/article/details/21047207
从该篇博文可以学习hog算子的理论知识。

一个简单例子

对于如下例子:来自参考(4)

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/gpu/gpu.hpp>
#include <stdio.h>

using namespace cv;

int main(int argc, char** argv)
{
    Mat img;
    vector<Rect> found;
     img = imread(argv[1]);
    if(argc != 2 || !img.data)
    {
        printf("没有图片\n");
        return -1;
    }
    HOGDescriptor defaultHog;
    defaultHog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
    //进行检测
    defaultHog.detectMultiScale(img, found);
    //画长方形,框出行人
    for(int i = 0; i < found.size(); i++)
            {
        Rect r = found[i];
        rectangle(img, r.tl(), r.br(), Scalar(0, 0, 255), 3);
    }
    namedWindow("检测行人", CV_WINDOW_AUTOSIZE);
    imshow("检测行人", img);
    waitKey(0);

    return 0;
}

算法流程

算法流程中1是opencv的主要算法流程,2是detect算法的流程。

1、detectMultiScale算法执行流程。

    1.1在该函数中,首先求得可以变化的层数,根据窗口大小增长到刚超过img大小为准。
    1.2使用HOGInvoker初始化函数对各个尺度下的图片进行检测。
        1.2.1对图片尺度数量进行循环,求出各个尺度下图片的检测结果
            1.2.1.1求出当前尺度下图片的信息,将原图片进行压缩。
            1.2.1.2对每个尺度下的图片,使用detect进行单幅图片的行人检测
            1.2.1.3将使用detect检测到的行人的窗口位置信息重新变换到正常尺寸图片上。并且将检测到的行人矩形框位置、比例信息、weitht信息添加到1.2的函数中。
    1.3将tempScales中的内容复制到foundScales中;
    1.4 清除所有位置信息  foundLocations.clear();并将找到的行人位置信息容器复制到foundLocations中 。
    1.5 清空foundWeights将将候选目标可信度保存在foundWeights中。
    1.6 使用meanshift对矩形框进行聚类或者简单的对矩形框进行聚类。

2、detect函数算法执行流程

    2.1一些初始化工作,如将locations清空等。
    2.2使用HOGCache cache(this, img, padding, padding, nwindows == 0, cacheStride); 完成img的梯度图和方向图的计算及blockData,pixData的初始化工作。
         2.2.1使用computeGradient计算出当前图像img的梯度、方向矩阵。
             2.2.1.1为grad和qangle开辟内存
                 2.2.1.1.1按照paddingTL和paddingBR建立一个扩展grandsize。
                 2.2.1.1.2按照grandsize给grad和qangle开辟内存,并且每个mat都初始化为双通道
            2.2.1.2如果需要,进行gamma校正。
            2.2.1.3 建立扩展后位置与原图像位置的对应关系
                2.2.1.3.1开辟内存mapbuf,长度为gradsize.width + gradsize.height +4; 
                2.2.1.3.2使用指针xmap建立扩展后x方向位置与原图像x位置的对应关系,同理使用ymap,需要注意的是,xmap和ymap指向的内存空间是mapbuf。
                2.2.1.3.3建立对应关系,建立对应关系后, 例子xmap[10]=5,意思是在扩展后图像x方向10的位置对应与原图像x方向5的位置。
            2.2.1.4 开始求梯度幅值和角度
                2.2.1.4.1 准备工作
                    2.2.1.4.1.1开辟内存_dbuf,其大小为width*4,其中width为扩展后的宽度。
                    2.2.1.4.1.2创建4个Mat,Dx,Dy, Mag, Angle,这些Mat使用_dbuf内存,这些mat变量都是临时变量,用来存入每行计算出来的数据。
                    其中,Dx中存放每个像素计算出来x方向的梯度,Dy中存放y方向的梯度,Mag中存放梯度幅值,Angle中存放角度值,
                2.2.1.4.2 对img每行进行遍历
                    2.2.1.4.2.1如果是单通道,计算出每个像素点的x和y方向的梯度值,然后放到Dx和Dy中
                    2.2.1.4.2.2 如果是多通道(也就是三通道),计算出每个像素点每个通道的x和y方向的梯度值和梯度幅值。
                    2.2.1.4.2.3 使用cartToPolar( Dx, Dy, Mag, Angle, false)计算出来Mag和Angle。
                    2.2.1.4.2.4 对每行计算出来的Mag数据和Angle数据进行遍历,然后将得到的数据存入
                    grad和qangle(其中grad的计算方式为gradPtr[x*2] = mag*(1.f - angle);
                    gradPtr[x*2+1] = mag*angle;  qangle的计算方式为将0-8个整数值赋值给qangle[x*2]和gradPtr[x*2+1] )
        2.2.2 接下来函数的主要工作是给 vector<PixData> pixData;和vector<BlockData> blockData;
各个像素点对不同cell的作用数据,如histOfs[4]用来存放对哪个cell起作用,其取值是0,1,2,3;)
            2.2.2.1 初始化工作,计算各个变量。
               2.2.2.1.1对 blockSize.width和blockSize.height进行循环,然后计算一个block中各个
               像素点的数据,即给pixData容器赋值。blocksize大小,当前计算的所有数据都存在第三段中。
               2.2.2.1.3对blockData进行赋值,其内部的所有赋值都是相对于一个移动窗口计算的   
    2.3 进行行人检测工作         
        2.3.1 一些初始化工作
        2.3.2 循环每个扫描窗口,然后对每个扫描窗口内的block数量进行遍历
            2.3.2.1 求出每个Block的直方图 const float* vec = cache.getBlock(pt, &blockHist[0]);
            2.3.2.2 将直方图的每个值与svmVec相乘,然后将所有值进行相加,每个窗口计算出一个s值与阈值进行比较
                       if( s >= hitThreshold )//超过既定阈值,说明包含行人  
                       {  
                           hits.push_back(pt0);  
                           weights.push_back(s);  
                      }  
        (这里的疑问是,使用的svmVec向量好像是一个Blocksize大小的向量,有些太小了,回头再仔细看)  
    2.3全部工作结束。
展开阅读全文

没有更多推荐了,返回首页