`

闵大荒之旅(六) ----- 初探HOG源码

 
阅读更多

  目前的进度有些缓慢了。。。

要想用CUDA实现HOG特征的并行计算,那么首先就要熟悉HOG计算的相关内容、思想,以便实现并行计算方案。

关于HOG特征的介绍,在网上有非常非常多,其中英文原文:http://vision.stanford.edu/teaching/cs231b_spring1213/papers/CVPR05_DalalTriggs.pdf

故这里不作详细介绍,简单摘抄其他博客内容进行介绍:

 

HOG特征提取方法就是将一个image(你要检测的目标或者扫描窗口):

1)灰度化(将图像看做一个x,y,z(灰度)的三维图像);

2)采用Gamma校正法对输入图像进行颜色空间的标准化(归一化);目的是调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰;

3)计算图像每个像素的梯度(包括大小和方向);主要是为了捕获轮廓信息,同时进一步弱化光照的干扰。

4)将图像划分成小cells(例如6*6像素/cell);

5)统计每个cell的梯度直方图(不同梯度的个数),即可形成每个celldescriptor

6)将每几个cell组成一个block(例如3*3cell/block),一个block内所有cell的特征descriptor串联起来便得到该blockHOG特征descriptor

7)将图像image内的所有blockHOG特征descriptor串联起来就可以得到该image(你要检测的目标)的HOG特征descriptor了。这个就是最终的可供分类使用的特征向量了。

摘抄自:http://blog.csdn.net/liulina603/article/details/8291093

 

当然上述过程只是一个简单的介绍,其中还有很多重要的细节没有体现,比如说权重的分配等等。为了我们自己写的HOG特征和OpenCV中的HOG特征、SVM算法的接口匹配,这样的话,会使得我们的项目进展得更加顺利。显而易见,要想达到这种目的,最简单的方法就是研究OpenCV中的源码,接下来,我将尝试理解源码。 

首先,我们要找到这个源码。我们用CMake对OpenCV249进行编译,得到一个新的文件夹,在这里面我们可以找到

 OpenCV.sln的项目文件(我这里CMake选择的编译器是VS2012,各位视情况而定哦)。用VS2012打开该项目文件,找到

打开hog.cpp,其中就是hog的源码。

 

要得到HOG特征,并且结合我们要移植到CUDA一侧进行改写成并行HOG特征算法,于是,我们要对HOG特征源码中的核心函数进行分析,尤其是计算过程。http://www.cnblogs.com/tornadomeet/archive/2012/08/15/2640754.html博客中有比较详细的hog源码的介绍,拜读之后受益匪浅,既然前人已经有了成熟的经验,那在这里我也就借鉴一下了!

 

这里主要注意

void HOGDescriptor::compute

void HOGCache::init

void HOGDescriptor::computeGradient

三个函数,这些是和HOG特征向量的计算有着直接的关系。

 

这里我把一些值得注意的地方列举出来,希望对理解源码有所帮助!

 

1.         gradPtr[x*2] = mag*(1.f - angle);
            gradPtr[x*2+1] = mag*angle;

乍一看,gradPtr的长度是width,而for循环中x的最大值也是width,那岂不是越界了么?

我们看到gradPtr定义的地方:

 float* gradPtr = (float*)grad.ptr(y);

看gard定义的地方:

grad.create(gradsize, CV_32FC2);  // <magnitude*(1-alpha), magnitude*alpha>

这里是CV_32FC2,明显是两通道,所以实际上gradPtr的大小是2*width,偶数第一通道,奇数第二通道。

 

2.幅值统计的时候,并不是落在那个bin,就只有该bin+幅值,而是与其最近的一个bin也受到影响

 

3.一个block内的cell是相互影响的,具体可参见我上列的博客

 

 

CUDA移植方案:

我的目的是将hog.cpp中的特征计算函数移植到CUDA处进行并行计算加速,那么简单的计算当然是没问题,但是涉及到opencv的内容,CUDA是hold不住的,因为CUDA是类似C语言的编程语言,没有提供opencv的相关API。于是有关内容都要自己改写。

比如说:

struct HOGCache
{
    struct BlockData
    {
        BlockData() : histOfs(0), imgOffset() {}
        int histOfs;
        Point imgOffset;
    };

    struct PixData
    {
        size_t gradOfs, qangleOfs;
        int histOfs[4];
        float histWeights[4];
        float gradWeight;
    };

    HOGCache();
    HOGCache(const HOGDescriptor* descriptor,
        const Mat& img, Size paddingTL, Size paddingBR,
        bool useCache, Size cacheStride);
    virtual ~HOGCache() {};
    virtual void init(const HOGDescriptor* descriptor,
        const Mat& img, Size paddingTL, Size paddingBR,
        bool useCache, Size cacheStride);

    Size windowsInImage(Size imageSize, Size winStride) const;
    Rect getWindow(Size imageSize, Size winStride, int idx) const;

    const float* getBlock(Point pt, float* buf);
    virtual void normalizeBlockHistogram(float* histogram) const;

    vector<PixData> pixData;
    vector<BlockData> blockData;

    bool useCache;
    vector<int> ymaxCached;
    Size winSize, cacheStride;
    Size nblocks, ncells;
    int blockHistogramSize;
    int count1, count2, count4;
    Point imgoffset;
    Mat_<float> blockCache;
    Mat_<uchar> blockCacheFlags;

    Mat grad, qangle;
    const HOGDescriptor* descriptor;
};

  HOGCache这个类型我们需要重写。具体重写办法下回我将介绍!

最后能得到HOG特征,再在opencv cpp处进行SVM训练。

  • 大小: 17.6 KB
  • 大小: 6.7 KB
  • 大小: 10 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics