【中级】图像特征工程:HOG 特征描述符

英文原文:
https://www.analyticsvidhya.com/blog/2019/09/feature-engineering-images-introduction-hog-feature-descriptor/
边翻译边学习

前言

特征工程是机器学习算法领域重要的角色。这是进行最多次试验的地方:从现有特征中设计新特征并提高我们模型的性能。世界上一些顶级数据科学家们依靠特征工程来提高他们在黑客马拉松中的排行榜分数。我相信你甚至会在结构化数据上使用各种特征工程技术。

我们能否将此技术扩展到非结构化数据,比如图像?对于计算机视觉爱好者来说,这是一个有趣的问题,我们将在本文中解释它。准备好以特征提取的形式对图像数据进行特征工程吧!

我假设你已经阅读了:【初级】使用 Python 从图像数据中提取特征

在本文中,我将向您介绍一种流行的图像特征提取技术——定向梯度直方图( Histogram of Oriented Gradients 或 HOG)。我们将了解什么是 HOG 特征描述符,它的工作原理(算法背后的完整数学),最后,将会在 Python 中实现它。

什么是特征描述符(Feature Descriptor)

下面的两个图像。你能区分图像中的物体吗?


图1

我们可以清楚地分辨右图有一只狗,左图有一辆汽车。现在让这个任务稍微复杂一点,识别下图中显示的物体:


图2

我想你还是可以分辨出吧?图1 有包含很多信息,比如物体的形状、颜色、边缘、背景等。而图2 的信息相对少得多(只有形状和边缘),但足以区分两个图像。

我想你已经对特征描述符有一些感觉了吧?在图2 中,我们很容易区分对象,因为它具有识别对象所需的必要信息。这正是特征描述符的作用:它是图像的简化表示,仅包含有关图像的最重要信息

以下是一些最受欢迎特征描述符的:

  • HOG:Histogram of Oriented Gradients
  • SIFT:Scale Invariant Feature Transform
  • SURF:Speeded-Up Robust Feature

在本文中,我们将重点介绍 HOG (定向梯度直方图)特征描述符及其工作原理。让我们开始吧!

HOG 特征描述符简介

HOG,是一种特征描述符,常用于从图像数据中提取特征。它广泛用于计算机视觉任务中的目标检测。

让我们看一下 HOG 与其他特征描述符不同的一些重要方面:

  • HOG 描述符侧重于对象的结构或形状。现在您可能会问,这与我们为图像提取的边缘特征有何不同?在边缘特征的情况下,我们只识别像素是否是边缘。HOG 也能够提供边缘方向。这是通过提取边缘的梯度和方向来完成的。
  • 此外,这些方向是在“局部”部分计算的。这意味着完整的图像被分解为更小的区域,并为每个区域计算梯度和方向。
  • 最后,HOG 会分别为这些区域中的每一个生成直方图。直方图是使用像素值的梯度和方向创建的,因此名称为“定向梯度直方图”

对此进行正式定义:HOG 特征描述符是计算图像局部梯度方向的出现次数

计算 HOG 的过程

我们现在应该对 HOG 特征描述符是什么有了一个基本的了解。是时候深入研究其背后的核心思想了。让我们开始讨论计算 HOG 的分步过程。

考虑以下尺寸 (180 x 280) 的图像。让我们详细了解一下如何为该图像创建 HOG 特征:


0x00 预处理数据 (64 x 128)

这是大多数人都非常熟悉的步骤。预处理数据是任何机器学习项目中的关键步骤,处理图像时也不例外。

我们需要对图像进行预处理并将宽高比降低到 1:2。图像大小最好是 64 x 128。这是因为我们将把图像分成 88 和 1616 块来提取特征。具有指定的大小 (64 x 128) 将使我们所有的计算变得非常简单。事实上,这是原始论文中使用的确切值。

回到我们的例子,让调整原图像为 64 x 128。这是调整后的图像:


0x01 计算梯度(x 和 y 方向)

下一步是计算图像中每个像素的梯度。梯度是 x 和 y 方向的微小变化。这里将从图像中取出一小块并计算其梯度:


我们将获得此区域的像素值。假设我们在给定的区域生成以下像素矩阵(此处显示的矩阵仅用作示例,这些不是给定区域的原始像素值):


图三

这里突出显示了像素值 85。首先确定 x 方向的梯度(或变化),我们需要从右侧的像素值中减去左侧的值。同样,为了计算 y 方向的梯度,我们将从所选像素上方的像素值中减去下方的像素值。

因此,该像素在 x 和 y 方向上的梯度为:

  • X 方向的变化
  • Y 方向的变化

这个过程会给我们两个新矩阵——一个存储 x 方向上的梯度,另一个存储 y 方向上的梯度。这类似于使用大小为 1 的 Sobel Kernel。当强度发生急剧变化时,例如边缘周围,幅度会更高

我们分别计算了 x 和 y 方向的梯度。对图像中的所有像素重复相同的过程。下一步是使用这些值找到大小和方向。

0x10 计算幅度和方向

使用我们在上一步中计算的梯度,我们现在将确定每个像素值的大小和方向。在这一步中,我们将使用毕达哥拉斯定理,如下图所示:


梯度分为是水平和竖直,对于前面的示例,我们将 和 设为 11 和 8。应用勾股定理来计算总梯度幅度:

接下来计算其方向:

因此,角度的值将是:

计算结果是 36。对于每个像素值,我们都能计算出其梯度值和方向。我们需要使用这些梯度值和方向生成直方图。

使用梯度和方向创建直方图的不同方法

直方图是显示一组连续数据的频率分布的图。x 轴表示数据值,y 轴表示其频率。在这里,我们将用x 轴表示角度,用y 轴表示频率。

0x00 方法1

让我们从最简单的生成直方图的方法开始。我们将获取每个像素值,找到像素的方向并更新频率表。还是讨论图三中的红色像素 85。由于该像素的方向是 36,我们将在角度值 36 上添加一个数字,表示频率:


对所有像素值做重复相同的操作,我们最终得到一个频率表,表示角度和这些角度在图像中的出现次数。此频率表可用于生成 x 轴上的角度值和 y 轴上的频率的直方图。这是创建直方图的一种方法。由于每个桶的是1,所以此处生成了180个大小相同的桶。

0x01 方法2

这种方法与前面的方法类似,不同之处在于这里的每个桶的大小为 20。因此,在这里得到的桶数为 9。同样,对于每个像素,我们将检查方向,并以 9 x 1 矩阵的形式存储方向值的频率。绘制这将为我们提供直方图:


0x10 方法3

在这里,我们将像素梯度的贡献添加到像素梯度任一侧的 bin 中。更高的贡献应该是对更接近方向的 bin 值。


这正是在 HOG 特征描述符中创建直方图的方式。

计算 8×8 单元格中梯度的直方图

在 HOG 特征描述符中创建的直方图不是为整个图像生成的。相反,图像被分成 8×8 个单元格,并为每个单元格计算定向梯度的直方图。通过这样做,我们获得了较小块的特征(或直方图),这些块又代表了整个图像。我们当然可以在这里将这个值从 8 x 8 更改为 16 x 16 或 32 x 32。如果我们将图像分成 8×8 个单元格并生成直方图,我们将为每个单元格得到一个 9 x 1 的矩阵。该矩阵是使用我们在上一节中讨论的方法 3 生成的。


一旦我们为图像中的 8×8 块生成了 HOG,下一步就是对直方图进行归一化。

标准化 16×16 单元格中的梯度

我们在了解这是如何完成之前,首先了解为什么要这样做很重要。尽管我们已经为图像的 8×8 单元创建了 HOG 特征,但图像的梯度对整体照明很敏感。这意味着对于特定图片,图像的某些部分与其他部分相比会非常亮。我们无法从图像中完全消除这一点。但是我们可以通过采用 16×16 块对梯度进行归一化来减少这种光照变化。这是一个可以解释如何创建 16×16 块的示例:


在这里,我们将组合四个 8×8 的单元格来创建一个 16×16 的块。我们已经知道每个 8×8 单元格都有一个 9×1 的直方图矩阵。因此,我们将有四个 9×1 矩阵即一个 36×1 矩阵。为了标准化这个矩阵,我们将这些值中的每一个除以这些值的平方和的平方根进行归一化,结果将是大小为 36×1 的归一化向量。

提取完整图像的特征

我们现在处于为图像生成 HOG 特征的最后一步。到目前为止,我们已经为图像的 16×16 块创建了特征。现在,我们将结合所有这些来获得最终图像的特征。

您能猜出给定图像的特征总数是多少吗?我们首先需要找出一张 64×128 的图像有多少这样的 16×16 块?我们将有 105 (7×15) 个 16×16 的块。这 105 个块中的每一个都有一个 36×1 的向量作为特征。因此,图像的总特征将为 105 x 36×1 = 3780 个特征。我们现在将为单个图像生成 HOG 特征,并验证我们最终是否获得相同数量的特征。

在 Python 中实现 HOG 特征描述符

我们将看到如何在单个图像上生成 HOG 特征,以及是否可以将其应用于更大的数据集。

'''
HOG FEATURES
'''

# importing required libraries
from skimage.io import imread, imshow
from skimage.transform import resize
from skimage.feature import hog
from skimage import exposure



#reading the image
img = imread('puppy.jpeg')
#resize image
resized_img = img

#generating HOG features
fd, hog_image = hog(resized_img, orientations=9, pixels_per_cell=(8, 8),
cells_per_block=(2, 2), visualize=True, multichannel=True)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8), sharex=True, sharey=True) 

ax1.imshow(resized_img, cmap=plt.cm.gray) 
ax1.set_title('Input image') 

# Rescale histogram for better display 
hog_image_rescaled = exposure.rescale_intensity(hog_image, in_range=(0, 10)) 

ax2.imshow(hog_image_rescaled, cmap=plt.cm.gray) 
ax2.set_title('Histogram of Oriented Gradients')

plt.show()

如果不进行 resize,结果如下:


image.png

当然这也会导致速度变慢

这时我们就提取出了对象识别时输入到机器学习中的图片HOG特征了。

你可能感兴趣的:(【中级】图像特征工程:HOG 特征描述符)