原地址:http://blog.csdn.net/chlele0105/article/details/11991533

梯度直方图特征(HOG) 是一种对图像局部重叠区域的密集型描述符,它通过计算局部区域的梯度方向直方图来构成特征。Hog特征结合SVM分类器已经被广泛应用于图像识别中,尤其在行人检测中获得了极大的成功。需要提醒的是,HOG+SVM进行行人检测的方法是法国研究人员Dalal在2005的CVPR上提出的,而如今虽然有很多行人检测算法不断提出,但基本都是以HOG+SVM的思路为主。

HOG特征是一种局部区域描述符,它通过计算局部区域上的梯度方向直方图来构成人体特征,能够很好地描述人体的边缘。它对光照变化和小量的偏移不敏感。

图像中像素点(x,y)的梯度为

Dalal提出的Hog特征提取的过程:把样本图像分割为若干个像素的单元(cell),把梯度方向平均划分为9个区间(bin),在每个单元里面对所有像素的梯度方向在各个方向区间进行直方图统计,得到一个9维的特征向量,每相邻的4个单元构成一个块(block),把一个块内的特征向量联起来得到36维的特征向量,用块对样本图像进行扫描,扫描步长为一个单元。最后将所有块的特征串联起来,就得到了人体的特征。例如,对于64*128的图像而言,每2*2的单元(16*16的像素)构成一个块,每个块内有4*9=36个特征,以8个像素为步长,那么,水平方向将有7个扫描窗口,垂直方向将有15个扫描窗口。也就是说,64*128的图片,总共有36*7*15=3780个特征。

在行人检测过程中,除了上面提到的HOG特征提取过程,还包括彩图转灰度,亮度校正等步骤。总结一下,在行人检测中,HOG特征计算的步骤:

(1)将输入的彩图转换为灰度图;

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

(3)计算梯度;主要是为了捕获轮廓信息,同时进一步弱化光照的干扰。

(4)将梯度投影到单元的梯度方向;目的是为局部图像区域提供一个编码,

(5)将所有单元格在块上进行归一化;归一化能够更进一步对光照、阴影和边缘进行压缩,通常,每个单元格由多个不同的块共享,但它的归一化是基于不同块的,所以计算结果也不一样。因此,一个单元格的特征会以不同的结果多次出现在最后的向量中。我们将归一化之后的块描述符就称之为HOG描述符。

(6)收集得到检测空间所有块的HOG特征;该步骤就是将检测窗口中所有重叠的块进行HOG特征的收集,并将它们结合成最终的特征向量供分类使用。

HOG特征描述

首先我们来了解一下HOG特征描述子。

HOG特征描述子(HOG descriptors)是由Navneet Dalal和 Bill Triggs在2005年的一篇介绍行人检测方法的论文提到的特征描述子(论文以及演讲可参见参考资料1、2)。

其主要思想是计算局部图像梯度的方向信息的统计值,来作为该图像的局部特征值。

  • 如上图,归一化图像后,由于颜色数据对我们没有帮助,所以将图片转为灰度图。
  • 然后将图片分割成一定“块”数,称作细胞单元。
  • 计算每个细胞单元的梯度大小方向。
  • 得到每个单元的梯度方向组成一个图片的特征向量。
  • 将这个特征向量交给SVM来学习或辨认。

SVM的简单介绍可以参考:OpenCV 2.4+ C++ SVM文字识别

算法分析

  • 梯度计算

OpenCV 2.4+ C++ 边缘梯度计算中,介绍了Sobel算子和Scharr滤波器的梯度计算方法,但是论文作者使用这些复杂方法的效果并不好,最好的是使用简单的一维梯度算子:[-1, 0, 1],进行卷积计算,分别算出x方向梯度Gx与y方向梯度Gy。然后利用下面两个公式计算梯度大小和方向:

    

    

  • 平滑处理

论文作者使用了高斯模糊进行平滑处理,结果效果变差了。其可能原因是:许多有用的图像信息是来自变化剧烈的边缘,而在计算梯度之前加入高斯滤波会把这些边缘滤除掉。

  • 细胞方向选择
  1. 细胞的统计方向,由细胞中的每一个像素点投票取得。
  2. 票箱是0 - PI(无向)角度范围平分为9个角度,即PI/9为每个票箱的角度范围。
  3. 每个投票像素点的投票权重,由其梯度幅值计算出来,可采用幅值本身(实验效果最佳),或者他的函数来表示这个权重。

局部关照变化或者前景和背景的对比变化,可能使梯度强度产生剧烈变化,但我们关注的不是这些信息,所以需要对这些信息弱化处理。利用数个细胞单元组成空间上连通的块。这样,HOG描述就成了由各个块所有细胞单元的直方图组成的一个向量,这些区域是互相重叠的。这样就减小了这些剧烈变化的影响。

每个细胞是8*8个像素点,以四个细胞组成一个块。

再由块组成检测窗。

  • 块向量归一化

最后是利用L2-norm或者L1-norm进行归一化。

v是未被归一化的向量,| vk |是k阶范数,ε为任意小常数,当k=2时,L2-norm为:

    

当k=1时,L1-norm为:

    

还有一种归一化方式L2-Hys:

    首先进行L2-norm,然后进行截短(即值被限制为v - 0.2v之间),然后再归一化。

HOGDescriptor API

gpu::HOGDescriptor::HOGDescriptor

创建HOG描述符和检测器。

C++: gpu::HOGDescriptor::HOGDescriptor(Size win_size=Size(64, 128), Size block_size=Size(16, 16), Sizeblock_stride=Size(8, 8), Size cell_size=Size(8, 8), int nbins=9, double win_sigma=DEFAULT_WIN_SIGMA, doublethreshold_L2hys=0.2, bool gamma_correction=true, int nlevels=DEFAULT_NLEVELS)
参数
  • win_size – 检测窗大小。需要和块的大小、步长匹配。
  • block_size – 块的大小。需要和细胞大小匹配。目前只支持(16,16)的大小。
  • block_stride – 块的步长,必须是细胞大小的整数倍。
  • cell_size – 细胞大小。目前只支持(8, 8)的大小。
  • nbins – 投票箱的个数。目前只支持每个细胞9个投票箱。
  • win_sigma – 高斯平滑窗口参数。
  • threshold_L2hys – L2-Hys归一化收缩率。
  • gamma_correction – 伽马校正预处理标志,需要或不需要。
  • nlevels – 检测窗口的最大数目。

gpu::HOGDescriptor::getDescriptorSize

返回分类所需的系数的数目。

C++: size_t gpu::HOGDescriptor::getDescriptorSize() const

gpu::HOGDescriptor::getBlockHistogramSize

返回块直方图的大小。

C++: size_t gpu::HOGDescriptor::getBlockHistogramSize() const

gpu::HOGDescriptor::setSVMDetector

设置线性SVM分类器的系数。

C++: void gpu::HOGDescriptor::setSVMDetector(const vector<float>& detector)

gpu::HOGDescriptor::getDefaultPeopleDetector

返回人的分类训练检测(默认的窗口大小)的默认系数。

C++: static vector<float> gpu::HOGDescriptor::getDefaultPeopleDetector()

gpu::HOGDescriptor::getPeopleDetector48x96

返回人的分类训练检测(48*96窗口大小)的系数。

C++: static vector<float> gpu::HOGDescriptor::getPeopleDetector48x96()

gpu::HOGDescriptor::getPeopleDetector64x128

返回人的分类训练检测(64*128窗口大小)的系数。

C++: static vector<float> gpu::HOGDescriptor::getPeopleDetector64x128()

gpu::HOGDescriptor::detect

在没有多尺度的窗口执行对象检测

C++: void gpu::HOGDescriptor::detect(const GpuMat& img, vector<Point>& found_locations, double hit_threshold=0, Sizewin_stride=Size(), Size padding=Size())
Parameters:
  • img – 源图像。只支持CV_8UC1CV_8UC4数据类型
  • found_locations – 检测出的物体的边缘。
  • hit_threshold – 特征向量和SVM划分超平面的阀值距离。通常它为0,并应由检测器系数决定。但是,当系数被省略时,可以手动指定它。
  • win_stride – 窗口步长,必须是块步长的整数倍。
  • padding – 模拟参数,使得CUP能兼容。目前必须是(0,0)。

gpu::HOGDescriptor::detectMultiScale

在多尺度窗口中执行对象检测。

C++: void gpu::HOGDescriptor::detectMultiScale(const GpuMat& img, vector<Rect>& found_locations, double hit_threshold=0, Size win_stride=Size(), Size padding=Size(), double scale0=1.05, int group_threshold=2)
参数
  • img – 源图像。只支持CV_8UC1CV_8UC4数据类型
  • found_locations – 检测出的物体的边缘。
  • hit_threshold – 特征向量和SVM划分超平面的阀值距离。通常它为0,并应由检测器系数决定。但是,当系数被省略时,可以手动指定它。
  • win_stride – 窗口步长,默认为8*8。
  • padding – 模拟参数,使得CUP能兼容。目前必须是(0,0)。
  • scale0 – 检测窗口增长参数。
  • group_threshold – 调节相似性系数的阈值。检测到时,某些对象可以由许多矩形覆盖。 0表示不进行分组。

gpu::HOGDescriptor::getDescriptors

返回整个图片的块描述符。

C++: void gpu::HOGDescriptor::getDescriptors(const GpuMat& img, Size win_stride, GpuMat& descriptors, intdescr_format=DESCR_FORMAT_COL_BY_COL)
参数
  • img – 源图像。只支持CV_8UC1CV_8UC4数据类型
  • win_stride – 窗口步长,必须是块步长的整数倍。
  • descriptors – 描述符的2D数组。
  • descr_format –

    描述符存储格式:

    • DESCR_FORMAT_ROW_BY_ROW - 行存储。
    • DESCR_FORMAT_COL_BY_COL - 列存储。

这个函数主要用于分类学习。

检测代码


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

这段代码虽然可以检测出行人,但是可能会出现,一个人身上有几个框框。例如下图左边的行人:

所以我们需要对found进行筛选,把那些被嵌套的长方形去除。


#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, foundRect;  
  
     img = imread(argv[1]);  
  
    if(argc != 2 || !img.data){  
        printf("没有图片\n");  
        return -1;  
    }  
  
    HOGDescriptor defaultHog;  
    defaultHog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());  
  
    //进行检测  
    defaultHog.detectMultiScale(img, found);  
  
    //遍历found寻找没有被嵌套的长方形  
    for(int i = 0; i < found.size(); i++){  
        Rect r = found[i];  
  
        int j = 0;  
        for(; j < found.size(); j++){  
            //如果时嵌套的就推出循环  
            if( j != i && (r & found[j]) == r)  
                break;  
        }  
        if(j == found.size()){  
            foundRect.push_back(r);  
        }  
    }  
  
    //画长方形,圈出行人  
    for(int i = 0; i < foundRect.size(); i++){  
        Rect r = foundRect[i];  
        rectangle(img, r.tl(), r.br(), Scalar(0, 0, 255), 3);  
    }  
  
      
    namedWindow("检测行人", CV_WINDOW_AUTOSIZE);  
    imshow("检测行人", img);  
  
    waitKey(0);  
  
    return 0;  
}  

PS:输入图片不能比检测窗还小,这样会抛出错误的。

相关链接:

HOG+SVM(自己训练SVM):http://blog.csdn.net/liulina603/article/details/8289625

HOG算子的更多相关文章

  1. opencv hog算子

    梯度直方图特征(HOG) 是一种对图像局部重叠区域的密集型描述符, 它通过计算局部区域的梯度方向直方图来构成特征.Hog特征结合SVM分类器已经被广泛应用于图像识别中,尤其在行人检测中获得了极大的成功 ...

  2. libsvm Minist Hog 手写体识别

    统计手写数字集的HOG特征 转载请注明出处,楼燚(yì)航的blog,http://www.cnblogs.com/louyihang-loves-baiyan/ 这篇文章是模式识别的小作业,利用sv ...

  3. HOG 梯度方向直方图简介(转载)

    一.基本HOG算法 HOG特征最早出现在SIFT算法中,由于其极强的图像特征描述能力,逐渐被人们熟知和广泛运用,其在目标检测方面表现尤为突出. HOG特征提取过程 步骤一:遍历图像每个像素点,以其为中 ...

  4. 人脸检测(1)——HOG特征

    一.概述 前面一个系列,我们对车牌识别的相关技术进行了研究,但是车牌识别相对来说还是比较简单的,后续本人会对人脸检测.人脸识别,人脸姿态估计和人眼识别做一定的学习和研究.其中人脸检测相对来说比较简单, ...

  5. python+图像分割seg

    好痛苦 1.目前思路为HOG+SVM 提取HOG时候发现,包装的lib cv2 里有hog算子,但是函数是指针形式.不会用了.. 现在改用推荐的scikits.image , from skimage ...

  6. Face recognition using Histograms of Oriented Gradients

    Face recognition using Histograms of Oriented Gradients 这篇论文的主要内容是将Hog算子应用到人脸识别上. 转载请注明:http://blog. ...

  7. 图像处理(二十一)基于数据驱动的人脸卡通动画生成-Siggraph Asia 2014

    http://blog.csdn.net/garfielder007/article/details/50582018 在现实生活中,我们经常会去评价一个人,长得是否漂亮.是不是帅哥美女,然而如何用五 ...

  8. ​综述 | SLAM回环检测方法

    本文作者任旭倩,公众号:计算机视觉life成员,由于格式原因,公式显示可能出问题,建议阅读原文链接:综述 | SLAM回环检测方法 在视觉SLAM问题中,位姿的估计往往是一个递推的过程,即由上一帧位姿 ...

  9. 目标检测——HOG特征

    1.HOG特征: 方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子.它通过计算和统计图像局部区域的 ...

随机推荐

  1. CodeForces Round #173 (282E) - Sausage Maximization 字典树

    练习赛的时候这道题死活超时....想到了高位确定后..低位不能对高位产生影响..并且高位要尽可能的为1..就是想不出比较好的方法了实现... 围观大神博客..http://www.cnblogs.co ...

  2. C# - 接口的继承

    代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...

  3. 20款Notepad++插件下载和介绍

    转自:http://www.kuqin.com/developtool/20090628/59334.html Notepad++从3.4版本开始支持插件机制,让用户可选择的为本身已经优秀的Notep ...

  4. 挺苹果的声音,iPhone 5s的两处进步

    苹果iPhone 5s发布后的两处重大进步让我很关注,但看了网上众多网友的点评,又深深的被中国当前手机发烧友圈的这种屌丝文化所震撼,这不是一条正确的道路,这将把中国的手机产业引向歧途,所以我不得不说几 ...

  5. Jetty总览

    Jetty入门 基本功能介绍 配置概览-怎么配置Jetty 配置概览-须要配置什么 Jetty配置 部署到Jetty 配置上下文 配置连接器 配置安全 配置JSP支持 Jetty管理指导 启动Jett ...

  6. Python标准库:内置函数dict(**kwarg)

    本函数是从一个字典參数构造一个新字典.參数kwarg是键值对的字典參数.以两个*开头的參数.就会收集成字典形式. 样例: #dict() #以键对方式构造字典 d1 = dict(one = 1, t ...

  7. 《UNIX环境高级编程》笔记--sigaction函数

    sigaction函数的功能是检查或修改指定信号相关联的处理动作,此函数取代UNIX早期版本使用的signal函数. #include<signal.h> int sigaction(in ...

  8. axure网格设置

    Axure默认的界面是没有吧网格显示出来,没有网格在制作原型的时候,对齐方面不是很好,个人习惯还是把网格显示出来,便于组件对齐和布局. 其实本来这篇文章应该叫做网格与参考线,只是本人对参考线的应用还很 ...

  9. Android触控屏幕Gesture(GestureDetector和SimpleOnGestureListener的使用教程)

    1.当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing等等,我们知道View类有个View.OnTouchListener内部接口,通过重写他的onTouch(Vie ...

  10. MSSQL - SQL Server2008附加数据库失败 错误号:5120

    附加数据库时,显示错误,错误信息为 一种解决方法为,设置mdf文件所在文件夹的权限(有些资料说只设置mdf文件的权限就好,但我试了不管用),在文件夹上右击——属性——安全,如图所示: 选择组或用户名中 ...