特征描述符是图像或图像块的表示,其通过提取有用信息和丢弃无关信息来简化图像。
通常,特征描述符将一个width*height* 3(通道)的图像转换为长度为n的特征向量或数组。在HOG特征描述符的情况下,输入图像的大小为64×128×3,输出特征向量的长度为3780。
在HOG特征描述符中,梯度方向(定向梯度)的分布(直方图)被用作特征。图像的梯度(x和y导数)是有用的,因为在边缘和角落(突然强度变化的区域)周围的梯度幅度很大,并且我们知道边缘和角落包含关于物体形状的更多信息而不是平坦区域。
如何计算方向梯度的直方图?
在本节中,我们将详细介绍计算HOG特征描述符。为了说明每个步骤,我们将使用图像的块。
第1步:预处理
如前所述,用于行人检测的HOG特征描述符是在图像的64×128块上计算的。当然,图像可以是任何尺寸。通常,在多个图像位置处分析多个尺度的贴片。唯一的限制是被分析的块具有固定的宽高比。在我们的例子中,块需要具有1:2的宽高比。例如,它们可以是100×200,128×256或1000×2000但不是101×205。
为了说明这一点,我展示了一个大小为720×475的图像。我们选择了一个大小为100×200的块来计算我们的HOG特征描述符。将这个块从图像中裁剪并调整为64×128。现在我们准备为这个图像块计算HOG描述符。
Dalal和Triggs的论文也提到了伽马校正作为预处理步骤,但性能提升很小,因此我们正在跳过这一步。
第2步:计算渐变图像
要计算HOG描述符,我们需要首先计算水平和垂直梯度; 毕竟,我们想要计算梯度的直方图。通过使用以下核来对图像进行滤波可以轻松实现这一点。
图2:滤波核
在OpenCV中使用核大小为1的Sobel运算符,我们也可以获得相同的结果。
- # Python 梯度计算
- # 读图像
- im = cv2.imread('bolt.png')
- im = np.float32(im) / 255.0
- # 计算梯度
- gx = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=1)
- gy = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=1)
复制代码
接下来,我们可以使用以下公式找到梯度的大小和方向:
在opencv中可以使用cartToPolar函数来实现
- # Python 计算梯度大小和方向 (度为单位)
- mag, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True)
复制代码下图显示了梯度:
图3:左:x-梯度的绝对值 中:y-梯度的绝对值 右梯度的大小
请注意,x-gradient在垂直线上触发,y-gradient在水平线上触发。梯度的大小会随着强度的急剧变化而发生。当该区域光滑时,它们都不会产生。我故意省略了显示渐变方向的图像,因为以图像的方向传达的信息不会太多。
梯度图像删除了许多非必要信息(例如恒定的彩色背景),但突出显示了轮廓。换句话说,你可以查看梯度图像,并且仍然可以轻松地说出图片中有人。
在每个像素处,梯度具有幅度和方向。对于彩色图像,评估三个通道的梯度(如图3所示)。一个像素处的梯度的大小是三个通道的梯度的最大值,并且角度是对应于最大梯度的角度。
步骤3:计算8×8单元中梯度的直方图
在该步骤中,将图像分成8×8个单元,并计算每个8×8单元的梯度直方图。
图4:HOG的8*8cell
我们将在一瞬间了解直方图,但在我们做之前让我们先了解为什么我们将图像分成8×8个单元格。使用特征描述符描述图像块的一个重要原因是它提供了紧凑的表现。8×8图像块包含8×8×3 = 192个像素值。此块的每个像素的梯度包含2个值(幅度和方向),最多可添加8x8x2 = 128个数字。到本节结束时,我们将看到如何使用9-bin直方图表示这128个数字,这些直方图可以存储为9个数字的数组。不仅表示更紧凑,计算块上的直方图使得这种表示对噪声更加鲁棒。个别的梯度可能有噪声,但超过8×8块的直方图使得表示对噪音的敏感性降低。
但为什么8×8块呢?为什么不是32×32?它是我们正在寻找的特征尺度的设计选择。HOG最初用于行人检测。行人照片中的8×8个cell缩放到64×128,足以捕捉有趣的特征(例如,脸部,头顶等)。
直方图的本质是一个由9个bin组成的数组或向量,每个bin对应于角度0,20,40,60 ... 160。
让我们看看图像中的一个8×8块,看看梯度的外观。
图5:中:箭头表示RGB块和梯度 右:同一块中的数字表示梯度
如果你是计算机视觉的初学者,那么图像中心的信息非常丰富。它显示图像的块用箭头表示梯度-箭头显示梯度的方向,其长度显示幅度。注意箭头的方向如何指向强度变化的方向,幅度表示差异有多大。
在右侧,我们看到原始数字代表8×8单元格中的梯度,只有一个小差异-角度介于0和180度之间,而不是0到360度。这些被称为“无符号”梯度,因为梯度的负方向也由相同的数字表示。换句话说,一个梯度箭头和与其相对的180度的箭头被认为是相同的。但是,为什么不使用0 - 360度?根据经验,已经表明无符号梯度比行人检测的有符号梯度更有效。HOG的某些实例将允许你指定是否要使用带符号的渐变。
下一步是在这些8×8单元格中创建梯度直方图。直方图包含9个bin对应于角度0,20,40 ...... 160。
下图说明了该过程。我们正在寻找与上图相同的8×8块的梯度的大小和方向。基于方向选择bin,并且基于幅度选择投票(进入bin中的值)。让我们首先关注蓝色环绕的像素。它的角度(方向)为80度,幅度为2.所以它在第5个箱子中加2。使用红色环绕的像素处的梯度具有10度的角度和4的大小。由于10度是0到20之间的一半,因此像素的投票均匀地分成两个bin。
图6:梯度直方图
还有一个细节需要注意。如果角度大于160度,则介于160和180之间,我们知道角度包围0和180等效。因此,在下面的示例中,角度为165度的像素与0度箱和160度bin成比例。
图7:梯度直方图示例
将8×8cell中的所有像素的贡献相加以创建9-bin直方图。对于上面的块,它看起来像这样
图8:梯度直方图化
在我们的表示中,y轴是0度。你可以看到直方图在0度和180度附近有很多权重,这只是另一种说法,即块的梯度要么方向向上要么方向向下。
步骤4:16×16块标准化
在上一步中,我们基于图像的梯度创建了直方图。图像的梯度对整体光照很敏感。如果将所有像素值除以2则使图像变暗,则梯度幅度将改变一半,因此直方图值将改变一半。理想情况下,我们希望描述符与光照变化无关。换句话说,我们希望“标准化”直方图,以便它们不受照明变化的影响。
在我解释直方图是如何规范化之前,让我们看看长度为3的向量是如何规范化的。
假设我们有一个RGB
颜色矢量[128,64,32]。这个向量的长度是
。这也称为向量的L2
范数。将该向量的每个元素除以146.64得到归一化向量[0.87,0.43,0.22]。现在考虑另一个向量,其中元素是第一个向量2 x [128,64,32] = [256,128,64]的值的两倍。你可以自己解决这个问题,看看规范化[256,128,64]会产生[0.87,0.43,0.22],这与原始RGB矢量的标准化版本相同. 现在我们知道如何规范化矢量,你可能会想到在计算HOG时可以简单地将9×1直方图归一化,就像我们对上面的3×1矢量进行归一化一样。这不是一个坏主意,但更好的想法是在更大尺寸的16×16块上进行标准化。16×16块具有4个直方图,它们可以连接形成36×1元素向量,并且可以按照3×1向量归一化的方式进行归一化。然后将窗口以8个元素进行移动,并在该窗口上计算归一化的36×1矢量,并重复该过程。
步骤5:计算HOG特征向量
为了计算整个图像块的最终特征向量,将36×1向量连接成一个大矢量。这个载体的大小是多少?让我们计算一下
1.我们有多少个16×16块的位置?
有7个水平位置和15个垂直位置,总共7 x 15 = 105个位置。
2.每个16×16块由36×1向量表示。所以当我们将它们全部连接成一个大向量时,我们得到一个36×105 = 3780维向量。
可视化方向梯度直方图
通常通过在8×8的cell中绘制9×1标准化直方图来可视化图像块的HOG描述符。如图8所示,你会注意到直方图的主导方向捕捉了人的形状,特别是在躯干和腿部周围。
不幸的是,没有简单的方法可视化OpenCV中的HOG描述符。
图9:可视化方向梯度直方图