Histogram of Oriented Gradients(HOG)特征描述子原理解释以及在OpenCV中的使用

Histogram of Oriented Gradients(HOG)特征描述子原理解释以及在OpenCV中的使用
一、什么是特征描述子?

特征描述子是对一张图片或者一个图片块的一种表示,通过提取有用信息并扔掉多余的信息来简化图像。通常,特征描述子将一张大小为width×height×3 (通道数)的图片化成一个长度为n的特征向量/数组。以HOG特征为例,输入图像的大小是64×128×3,输出是一个长度为3780(假设)的特征向量。

上面这些听起来不错,但是对于一张图片的信息,哪些是有用的哪些是冗余的呢?为了定义这个有用信息,我们需要知道它对什么有用。显然,特征向量对于我们看一张图像没什么用。但是,它对图像识别和目标检测这样的任务很有用。将由这些算法生成的特征向量作为支持向量机等分类算法的输入往往可以得到不错的结果。

但是,对于分类任务来说,哪类特征是有用的呢?让我们先用一个例子讨论一下。假设我们想设计一个目标检测器来检测衬衫或者外套上的纽扣。通常纽扣是圆的(可能在图片上会是椭圆)而且一般会有一些孔用于缝纫。你可以在一张纽扣的图片上执行边缘检测,仅仅通过观察边缘图像就可以判断它是不是一个纽扣。在这个例子中,边缘信息是有用的而颜色信息是无用的。此外,特征也需要有区分能力。例如,从某一张图片中提取的一个好的特征应具备区分纽扣和其他圆心物体(如硬币和车轮)的能力。

对于HOG特征描述子,选用梯度方向的分布作为特征。一张图像的梯度(x和y方向的导数)很有用,因为在边缘和拐角(强度变化剧烈的区域)处的梯度幅值很大。而且我们知道边缘和拐角比其他平坦的区域包含更多关于物体形状的信息。

例如将上图转化为一种特征描述取出颜色等冗余信息后,我们仍能够判断图片中的物体,也就是说特征描述子具有识别对象所需的必要信息。

二、如何计算HOG特征向量

Step1:图片预处理

我们需要对图像进行预处理,并将宽高比降低到1:2,图像大小最好是64 x 128。这是因为我们将图像分成8 x 8和16 x 16小块来提取特征。具有指定的大小(64 x 128)将使我们的所有计算相当简单。事实上,这正是原始论文中使用的值。当然完整的图片可以是任意的尺寸。通常我们会在图片的不同位置分析多尺度图片块。唯一的要求就是图片块需要有固定的长宽比。比如:100×200, 128×256或者1000×2000都可以,但101×205就不满足要求

回到我们的例子,让我们将大小为64x128作为目前的标准图像大小。以下是调整后的图像:

Step2:计算每个像素点的梯度幅值和方向

在预处理完图像之后,我们就需要计算图中每一像素点的梯度幅值以及方向。这里有一点需要注意,对于图像边缘我们需要做一些padding或者放弃边缘的梯度计算。

梯度计算分别要计算X轴以及Y轴的梯度,我们可以使用以下的向量对像素点进行梯度计算,或者我们也可以使用OpenCV中的Sobel算子(kernel size设为1)得到相同的结果。

X轴和Y轴梯度计算公式分别为:
G x ( x , y ) = H ( x + 1 , y ) − H ( x − 1 , y ) G y ( x , y ) = H ( x , y + 1 ) − H ( x , y − 1 ) (2-1) G_x(x,y) = H( x+1,y) - H(x-1, y) \\ G_y(x,y) = H( x,y+1) - H(x, y-1) \tag{2-1} Gx(x,y)=H(x+1,y)H(x1,y)Gy(x,y)=H(x,y+1)H(x,y1)(2-1)
其中 G x ( x , y ) , G y ( x , y ) , H ( x , y ) G_x(x,y), G_y(x,y), H(x,y) Gx(x,y),Gy(x,y),H(x,y)分别表示该像素点在X轴方向,Y轴方向的梯度, H ( x , y ) H(x,y) H(x,y)为该像素点。

在计算完像素点的梯度之后,我们需要计算该像素点幅值以及梯度方向,公式如下:
G ( x , y ) = G x 2 ( x , y ) + G y 2 ( x , y ) G(x,y) = \sqrt {G_x^2(x,y) + G_y^2(x,y)} G(x,y)=Gx2(x,y)+Gy2(x,y)
θ = a r c t a n G y ( x , y ) G x ( x , y ) (2-2) \theta=arctan\frac{G_y(x,y)}{G_x(x,y)} \tag{2-2} θ=arctanGx(x,y)Gy(x,y)(2-2)
其中角度的计算正如你高中所学习的那样:

t a n θ = G y G x (2-3) tan\theta= \frac{G_y} {G_x}\tag{2-3} tanθ=GxGy(2-3)我们对其求反函数就可以得到该像素点的梯度方向角度。

Step3:将图像划分为一个一个cell,并绘制cell的梯度直方图

HOG特征描述子中创建的直方图不是为整个图像生成,而是将图像分割为8 × 8个单元格(cell),计算每个单元格的方向梯度直方图。通过这样做,我们得到了代表整个图像的小块的特征(或直方图)。我们当然可以把这个值从8 x 8换成16 x 16或者32 x 32。

如果我们将图像划分为8 × 8个单元格并生成直方图,假设我们将直方图的角度分为9份,也就是说有9个bin,则每个单元格获得9 x 1矩阵。下面介绍如何划分bin的角度以及如何将计算好的梯度幅值加到每一个bin中。

我们采用9个bin的直方图来统计这8 x 8个像素的梯度信息。也就是将cell的梯度方向360度分成9个方向块,如下图所示,对cell内每个像素用梯度方向在直方图中进行加权投影(映射到固定的角度范围),就可以得到这个cell的梯度方向直方图了,就是该cell对应的9维特征向量(因为有9个bin)。

但是如左下图(梯度方向)所示,我们发现8 × 8的cell中表示梯度的数字有一点细微的差别-——角度实际在0°到180°之间的而不是0°到360°之间。这些叫做“无符号梯度”,因为一个正负方向的两个梯度由同一个数字表示。换句话说,某一个梯度箭头和它对应的另一个值(加上180°对应的那个值)被当作是同一个梯度。根据经验,无符号梯度被证明比有符号梯度效果更好,一些HOG特征的实现代码会允许你选择是否使用有符号梯度。

下一步就是在这些8×8的cells上创建梯度直方图。直方图包含9个bins分别对应着0°、20°、40°、… 160°。

我们在上图的8×8的cells上查看梯度的大小和方向。每个bin是基于梯度方向选出来的,对应的票数(加在当前bin上的值)对应着梯度的大小。我们先来看看用蓝色圆圈出来的像素,它的梯度的角度是80°,大小为2。因此它在第5个bin上加2。图中用红色圈出来的梯度的角度是10°,大小是4。由于10°是在0°和20°的中间位置,因此根据10°到0°和20°的距离比例,将10°对于的幅值按比例加到0°和20°的bin中去,计算如下:
( 20 − 10 ) / ( 20 − 0 ) ∗ 4 ⏟ 10°对应的幅值 = 2 ⏞ 加到0°bin上的权重 \overbrace{(20-10)/ (20 - 0) *\underbrace4_\text{10°对应的幅值} = 2 }^\text{加到0°bin上的权重} 2010/(200)10°对应的幅值 4=2 加到0°bin上的权重
( 10 − 0 ) / ( 20 − 0 ) ∗ 4 ⏟ 10°对应的幅值 = 2 ⏞ 加到20°bin上的权重 \overbrace{(10-0)/ (20 - 0) *\underbrace4_\text{10°对应的幅值} = 2 }^\text{加到20°bin上的权重} 100/(200)10°对应的幅值 4=2 加到20°bin上的权重
即角度距离那个bin值最近,则权重比例越高。还有一个细节需要注意,如果梯度方向大于160°。此时梯度的角度位于160°和180°之间。我们知道0°和180°是一样的(无符号梯度),因此对应的幅值比例加到0°的bin上去。

8×8的cell中所有像素处的梯度按照方向将梯度大小累加到9个bin以创建最后的梯度直方图。上图中的cell对应的梯度直方图如下:

在我们的表示结果中,y轴对应0°。你可以发现上面的直方图中有大量的权重(梯度大小的投票结果)在0°和180°附近,这从另外一个角度说明了在这个cell中大部分梯度方向要么朝上要么朝下。

Step4:用cell组成一个block块,并对其进行归一化操作

由于局部光照的变化以及前景-背景对比度的变化,使得梯度强度的变化范围非常大。这就需要对梯度强度做归一化,归一化能够进一步地对光照、阴影和边缘进行压缩。理想情况下,我们想让特征描述子独立于光线变化,换句话说,我们想要“标准化”这个直方图使它不受光线变化的影响。

作者采取的办法是:把各个cell单元组合成大的、空间上连通的区间块(blocks)。这样,一个block内所有cell的特征向量串联起来便得到该block的HOG特征。就如下图中的一个block(蓝色框)这些区间是互有重叠的,这就意味着:每一个单元格的特征会以不同的结果多次出现在最后的特征向量中。我们将归一化之后的块描述符(向量)就称之为HOG描述符。

在我讲梯度直方图如何标准化之前,我们先来看看一个长度为3的向量如何标准化。

假设我们有一个RGB颜色向量[128, 64, 32]。这个向量的长度是 12 8 2 + 6 4 2 + 3 2 2 \sqrt{128^2 + 64^2 + 32^2} 1282+642+322 =146.64。这也叫做向量的L2范数。将这个向量的所有元素除以向量长度146.64就可以得到一个标准化的向量[0.87, 0.43, 0.22]。

现在我们知道如何标准化一个向量,你可能想到当计算HOG特征的时候你可以像之前标准化一个3×1向量一样去标准化9×1的直方图。这的确是个不错的想法,但是更好的做法是标准化一个更大的16×16的block。一个16×16的block包含4个直方图(每一个bin的大小为8 x 8),这4个直方图可以连接成一个36×1的向量,而且这个向量仍然可以像那个3×1的向量一样进行标准化。每次标准化后,整个窗口移动8(假设)个像素并再次计算得到一个36×1的标准化向量,就这样一直重复这个过程。

Step5:将所有block块的特征组合起来,形成HOG完整的特征描述向量

最后一步就是将检测窗口中所有的block块进行HOG特征的收集,并将它们结合成最终的特征向量供分类使用。

那么这个大向量的维度是多少?我们来计算:

对于64 x 128的图像而言,每8 x 8的像素组成一个cell,每2 x 2个cell组成一个块,因为每个cell有9个特征,所以每个块内有4*9=36个特征,以8个像素为步长。

  • 我们有多少个不同位置的16×16的block?一共有 (64-8)/8=7 个水平的位置和 (128-8)/8=15 个竖直的位置,所以总计7×15=105个。
  • 每一个16×16的block被表示成一个36×1的向量。因此,当我们把他们连接成一个大向量的时候会得到一个36×105=3780维度的向量。

梯度直方图可视化

一个图像块梯度特征的可视化通常通过在所有8×8的cell里画出对应的标准化的9×1向量(直方图)。不幸的是,目前在OpenCV中并没有一个简单的API方法来可视化HOG特征。

三、使用OpenCV给出的API实现HOG

这里我将在OpenCV栏目下介绍OpenCV中HOGDescriptor Struct Reference中的一些方法,如果需要请移步链接:https://blog.csdn.net/qq_40913465/article/details/106070151

最后感谢以下两片博客给出的参考:
https://baijiahao.baidu.com/s?id=1646997581304332534&wfr=spider&for=pc
https://blog.csdn.net/sinat_34474705/article/details/80219617

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值