图像特征:方向梯度直方图 HOG

文章目录

  • 参考资料
  • 简介
  • 算法流程
    • 灰度化和gamma校正
    • 计算梯度
    • 统计cell的梯度方向直方图
    • Block 块内归一化(重点)
    • 组合为HOG特征
    • HOG特征与可视化
  • OpenCV 算法实现


参考资料

  • 2012-08-31 图像特征提取之HOG特征
  • 2015-05-12 特征提取-----HOG
  • 2017-03-17 HOG特征及其提取方法图示
  • 2017-10-19 HOG特征-方向梯度直方图特征

简介

方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子,是通过计算和统计图像 局部区域 的梯度方向直方图来构成特征。最早由法国研究员Dalal等在CVPR-2005上提出,用于解决人体目标检测问题。

主要思想:
一幅图像中局部目标的表象和形状(appearance and shape)能够很好地被边缘或轮廓的 方向密度分布 来描述,而梯度信息正处于边缘或轮廓附近。因此考虑将图像分成多块局部区域(cell),采集其中各像素点的梯度方向直方图或边缘的方向直方图,组合得到的直方图来构建特征描述器。

优点:

  1. HOG表示的是边缘(梯度)的结构特征,因此可以描述局部的形状信息
  2. 位置和方向空间的量化一定程度上可以抑制平移和旋转带来的影响;
  3. 采取在局部区域归一化直方图,可以部分抵消光照变化带来的影响。
  4. 由于一定程度忽略了光照颜色对图像造成的影响,使得图像所需要的表征数据的维度降低了。
  5. 而且由于它这种分块分单元的处理方法,也使得图像局部像素点之间的关系可以很好得到的表征。

缺点:

  1. 描述子生成过程冗长,导致速度慢,实时性差;
  2. 很难处理遮挡问题;
  3. 由于梯度的性质,该描述子对噪点相当敏感;
  4. 只使用灰度图像,未考虑颜色信息。

算法流程

主要步骤:灰度化和gamma校正 -> 计算梯度 -> 统计cell的梯度方向直方图 -> Block 块内归一化 -> 生成HOG特征
图像特征:方向梯度直方图 HOG_第1张图片

灰度化和gamma校正

为了减少光照影响,处理光线太暗或太强的情况,需要将整个图像进行归一化处理:灰度化和Gamma校正。在图像的纹理强度中,局部的表层曝光贡献的比重较大,这种处理能够有效地降低图像局部的阴影和光照变化。

灰度化:
HOG特征考虑的是代表边缘和形状特性的梯度信息,色彩几乎没有贡献,作用不大,可直接转化为灰度图。
G r a y = 0.3 × R + 0.59 × G + 0.11 × B Gray = 0.3 \times R + 0.59 \times G + 0.11 \times B Gray=0.3×R+0.59×G+0.11×B

Gamma校正:
为了降低图像局部的阴影和光照变化,首先需要对整个图像进行Gamma校正,将图像整体亮度提高或降低。在实际中可以采用两种不同的方式进行Gamma标准化:平方根或对数法。平方根法的公式如下(其中 γ = 0.5 γ=0.5 γ=0.5 ):
I ( x , y ) = I ( x , y ) γ I(x,y) = I(x,y)^{\gamma} I(x,y)=I(x,y)γ
图像特征:方向梯度直方图 HOG_第2张图片

计算梯度

计算图像横坐标和纵坐标方向的梯度,并据此计算每个像素位置的梯度方向值;微分操作不仅能够捕获轮廓、人影和一些纹理信息,还能进一步弱化光照的影响。

梯度算子:水平边缘算子 [ − 1 , 0 , 1 ] [-1, 0, 1] [1,0,1],垂直边缘算子 [ − 1 , 0 , 1 ] T [-1, 0, 1]^T [1,0,1]T
值得说明的是:

HOG的提出者尝试了其他一些更复杂的模板,如3×3 Sobel 模板,或对角线模板(diagonal masks),但是在行人检测实验中,复杂模板的表现都较差,作者总结到:模板越简单,效果反而越好
.
同时尝试了在使用微分算子前加入高斯平滑滤波,但加入后的检测效果变得更差,原因是:许多有用的图像信息是来自变化剧烈的边缘,而高斯滤波会模糊边缘。如果需要滤波,则应考虑 保边去噪 算法。

计算梯度幅值与方向:
图像特征:方向梯度直方图 HOG_第3张图片

统计cell的梯度方向直方图

将图像划分成若干个 cell 单元格,相邻的cell互不重叠。在每个cell内,将所有梯度方向划分为n个bin(一般取 n = 9 n=9 n=9),作为直方图的横轴,角度范围所对应的梯度值累加值作为直方图纵轴,进行统计即得到梯度方向直方图。

假设每个cell为 6 × 6 6\times 6 6×6 个像素,采用9个bin的直方图来统计,也就是将cell的梯度方向由360度分成9个方向块,如图所示:
图像特征:方向梯度直方图 HOG_第4张图片
如果某像素的梯度方向是20-40度,则直方图第2个bin的计数就加一。这样,对cell内每个像素用梯度方向在直方图中进行加权投影(映射到固定的角度范围),就可以得到这个cell的梯度方向直方图了,即一个9维的特征向量。

值得说明的是:
上述的梯度角度是0-180度,不是0-360度,这称为"unsigned"梯度,即认为正负梯度角是一样的,梯度的箭头旋转180度之后保持不变。那为什么不用0-360度的表示呢?因为HOG的提出者表示在行人检测任务中发现unsigned gradients 比 signed gradients 效果更好。对于其他任务,则可以自行指定是否使用"unsigned"梯度

单元格Cell中的每一个像素点都为某个基于方向的直方图通道(orientation-based histogram channel)投票,投票是采取加权投票(weighted voting)权值由梯度幅值计算得到,可以是幅值本身或者其函数值,投票结果就是该cell的特征向量。
C = [ x 1 , x 2 , ⋯   , x 9 ] C=[x_1,x_2,\cdots,x_9] C=[x1,x2,,x9]

实际测试表明: 使用幅值来表示权值能获得最佳的人体检测效果。

Block 块内归一化(重点)

由于局部光照的变化以及前景-背景对比度的变化,使得梯度强度的变化范围非常大,这就需要对梯度强度做归一化。归一化能够进一步地对光照、阴影和边缘进行压缩。

但不能进行全局归一化,否则容易模糊细节或边缘,考虑把 m m m 个cell组合成一个大的、空间上连通的 block 区块(一般取 m = 4 m=4 m=4)。这样,一个block内就含有多个cell的特征向量,归一化后,将其串联起来得到的高维特征向量即是该block的HOG特征:
B = [ C 1 , C 2 , C 3 , C 4 ] B=[C_1, C_2,C_3,C_4] B=[C1,C2,C3,C4]

图像特征:方向梯度直方图 HOG_第5张图片
所有block的大小都必须相同,相邻block之间的距离(称为跨距)是一个自由参数,但通常设置为块大小的一半,在这种情况下,将得到重叠块,即其他文章所说的 “overlap”分割问题,对应地有“non-overlap”:区块不交叠,cell不重复计算。实践表明:一般选用“overlap”分割,其拥有更好的表征能力,即使计算量较大
图像特征:方向梯度直方图 HOG_第6张图片

有关归一化方法,值得说明的是:
不同于常见的Min-Max 归一化,有 参考文章 中提出了下述方法:
图像特征:方向梯度直方图 HOG_第7张图片

组合为HOG特征

l l l个Block的特征向量组合起来, h h h取决于图像的宽高尺寸,这样就得到了最终的HOG特征:
H O G = [ B 1 , B 2 , ⋯   , B l ] HOG=[B_1, B_2,\cdots,B_l] HOG=[B1,B2,,Bl]

维数计算:
d i m s = l × m × n = l × 36 dims = l \times m \times n = l\times36 dims=l×m×n=l×36

分块计算:
l = ( W / S − 1 ) × ( H / S − 1 ) l = (W/S-1) \times (H/S-1) l=(W/S1)×(H/S1)

其中,步长 S S S一般取 Block像素数的一半

HOG特征与可视化

可视化结果表示HOG特征的主要方向捕捉了人体的外形,特别是躯干和腿。
图像特征:方向梯度直方图 HOG_第8张图片

OpenCV 算法实现

接口代码

图像特征:方向梯度直方图 HOG_第9张图片

Default Value Comment
_winSize Size(64,128) Size of detection window in pixels (width, height). Defines the region of interest. Must be an integer multiple of cell size.
_blockSize Size(16,16) Block size in pixels (width, height). Defines how many cells are in each block. Must be an integer multiple of cell size and it must be smaller than the detection window. The smaller the block the finer detail you will get.
_blockStride Size(8,8) Block stride in pixels (horizontal, vertical). It must be an integer multiple of cell size. The block_stride defines the distance between adjecent blocks, for example, 8 pixels horizontally and 8 pixels vertically. Longer block_strides makes the algorithm run faster (because less blocks are evaluated) but the algorithm may not perform as well.
_cellSize Size(8,8) Cell size in pixels (width, height). Determines the size fo your cell. The smaller the cell the finer detail you will get.
_nbins 9 Number of bins for the histograms. Determines the number of angular bins used to make the histograms. With more bins you capture more gradient directions. HOG uses unsigned gradients, so the angular bins will have values between 0 and 180 degrees.
_derivAperture 1 /
_winSigma -1 Gaussian smoothing window parameter. The performance of the HOG algorithm can be improved by smoothing the pixels near the edges of the blocks by applying a Gaussian spatial window to each pixel before computing the histograms.
_histogramNormType L2Hys histogram normalization type
_L2HysThreshold FALSE L2-Hys (Lowe-style clipped L2 norm) normalization method shrinkage. The L2-Hys method is used to normalize the blocks and it consists of an L2-norm followed by clipping and a renormalization. The clipping limits the maximum value of the descriptor vector for each block to have the value of the given threshold (0.2 by default).
_gammaCorrection TRUE Flag to specify whether the gamma correction preprocessing is required or not. Performing gamma correction slightly increases the performance of the HOG algorithm.
_nlevels 64 Maximum number of detection window increases.
_signedGradient FALSE sets signedGradient with given value
#include 
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/objdetect/objdetect.hpp"

using namespace std;

int main(int argc, char* argv[])
{
    cv::Mat src = cv::imread("../src.png");

    cv::Size winSize(64, 128);      // ROI
    cv::Size cellSize(8, 8);        // cell
    cv::Size blockSize(16, 16);     // block
    cv::Size blockStride(8, 8);     // 步长
    int nbins(9);                   // bins number
    cv::HOGDescriptor hog(winSize, blockSize, blockStride, cellSize, nbins);

    std::vector< float > feature;
    hog.compute(src(cv::Rect(0, 0, 64, 128)), feature);  // 只取第一个窗口的HOG特征
    cout << "feature dims: " << feature.size() << endl;  // 3780

    return 0;
}

每个Block中4个Cell,每个Cell统计9个bins,则HOG维数计算如下:

m × n = 4 × 9 = 36 m \times n = 4 \times 9 = 36 m×n=4×9=36

一般步长取Block区块的一半,则

d i m s = ( W / S − 1 ) × ( H / S − 1 ) × 36 = 3780 dims = (W/S-1) \times (H/S-1) \times 36 = 3780 dims=(W/S1)×(H/S1)×36=3780

关于特征维数值得说明的是:
特征维数越多,表征能力越强,但肯定存在冗余,增大计算量。这就需要考虑“特征降维”,如PCA,这也是 OpenCV-KCF 中存在PCA参数的原因。

你可能感兴趣的:(数字图像处理,HOG,方向梯度直方图)