计算机视觉爱好者必看:特征工程HOG特征描述子指南
全文共4499字,预计学习时长9分钟
特征工程在机器学习算法领域中可以说是“改变游戏规则”的存在。特征工程是进行最多实验的领域——根据现有内容设计新特征并改善模型的表现。
一些世界上顶尖的数据科学家依靠特征工程提高自己在黑客马拉松中的排行榜得分。
那么此项技术可以扩展应用于非结构化数据吗,例如图像?这对计算机视觉爱好者来说是一个有趣的谜题,本文将揭晓答案。准备好对图像数据应用特征提取技术,从而执行特征工程。
事实上,特征提取有众多方法。
本文将介绍一种热门的图像特征提取方法——方向梯度直方图(Histogram of Oriented Gradients),称作HOG更为熟知。具体包括:理解HOG特征描述子是什么、工作机制(算法背后完整的数学运算),以及在Python中的应用。
目录
1. 什么是特征描述子?
2. HOG特征描述子介绍
3. HOG计算过程
3.1 数据预处理
3.2 梯度计算
3.3 幅值和方向计算
4. 使用梯度和方向创建直方图的方法
5. HOG计算过程
5.1 梯度直方图计算
5.2 梯度规范化
5.3 完整图像特征
6. 在Python中应用HOG特征描述子
什么是特征描述子?
请看下面两张图片。你能辨别出图片中的物体吗?
可以清楚地看到,左图中有一辆汽车,右图中有一条狗。接下来,把这个问题变得稍微复杂点——辨别下图中的物体。
还是很简单,对吧?你知道两个问题的区别吗?第一组图片包含很多信息,如物体形状、颜色、边缘和背景等。
相比来看,第二组图片中的信息少多了(只有形状和边缘),但这些信息足以辨别图片中物体。
你知道我们接下来要讲什么了吗?在第二组图片中,可以轻松辨识物体,因为其中包含了识别物体所需的必要信息。而这也就是特征描述子的作用:
特征描述子是图片的简略替代,其中只包含图像最重要的信息。
此外还有很多种特征描述子。以下是最热门的几种:
· HOG: 方向梯度直方图
· SIFT: 尺度不变特征变换
· SURF: 加速稳健特征
本文聚焦HOG特征描述子及其工作机制。现在开始吧!
HOG特征描述子介绍
HOG,也称作方向梯度直方图,是常用于提取图像数据特征的一种特征子。其广泛应用于计算机视觉任务以进行目标检测。
一同看看HOG与其它特征描述子的区别:
· HOG特征描述子关注物体的结构或形状。你可能会问,这和提取的图像边缘信息有什么区别?就边缘信息而言,只能辨别此像素是否属于边缘。而HOG还能提供边缘的方向。这是通过提取边缘的梯度和方向实现的。
· 另外,这些方向是在“局部”区域计算得出的。这就意味着一张完整的图片被分成了几个小部分,针对每个区域计算其梯度和方向。更多相关细节会在下文提及。
· 最后,HOG会分别为这些部分生成直方图。由于它们是使用像素值的梯度和方向创造出来的,所以得名“方向梯度直方图”。
其正式定义为:
HOG特征描述子用于统计和计算图片中局部区域出现的梯度方向。
使用类似OpenCV的工具应用HOG非常简单。由于skimage.feature库中已有被称为hog的预定义函数,所以只需几行代码即可。然而,本文的重点聚焦这些特征到底是怎样计算出来的。
HOG计算过程
通过上文,想必你对HOG特征描述子已有基本了解。现在该开始研究本文背后的核心思想了。大家共同逐步讨论HOG的计算过程。
思考下图尺寸(180 x 280)。一同详细了解这张图像的HOG特征是如何创建的。
第1步:数据预处理(64 x 128)
你们中大多数人应该都很熟悉这一步。数据预处理在任何机器学习项目中都是关键步骤,处理图像时也不例外。
在此需要对图像进行预处理,将宽高比降为1:2。图像最佳尺寸为64 x 128。这是因为需要将图片分为8*8和16*16的小块以提取特征。使用特定的尺寸(64 x 128)会让后续运算非常简便。实际上,这个数据就是原始论文(http://lear.inrialpes.fr/people/triggs/pubs/Dalal-cvpr05.pdf)中使用的值。
回到本文所给出的例子上,选用64 x 28这一大小的图像作为当前的标准图像尺寸。下图是修改尺寸后的图像。
第2步:梯度计算(x和y方向)
下一步是计算图像中每一像素的梯度。梯度是x和y方向所发生的微小变化。本文中,笔者从图像中取一小块区域,并计算其梯度:
从上图的小块区域中得到像素值。对此区域,生成了如下的像素矩阵(下图所示的矩阵仅用作例子,且不是所示区域的初始像素值):
图源:机器学习应用课程
笔者已将像素值85高亮表示。现在,确定x方向的梯度(或变化),需要用像素值85右侧值减去其左侧值。相应地,计算y方向的梯度,需要用所选像素值85上方的值减去其下方的值。
由此计算出这一像素在x和y方向的梯度为:
· x方向变化(Gx) = 89 – 78 = 11
· y方向变化(Gy) = 68 – 56 = 8
此过程得出两个新矩阵——一组x方向的存储梯度,一组y方向的存储梯度。这与使用大小为1的索伯算子类似。密度上有剧烈变化时,如边缘周围的密度,幅度则会升高。
目前已分别计算求得x和y方向的梯度。请对图像中所有像素重复同一步骤。下一步就是使用这些值计算出幅值和方向。
第3步:幅值和方向计算
使用上一步中计算出的梯度,然后确定每个像素值的幅值和方向。在此步骤中,会运用到勾股定理(是的,就是你在学校学过的那个!)。
请看下图:
梯度基本上对应的都是类似图中的底边和垂直边。所以,上例的Gx为11,Gy为8。 应用勾股定理计算总斜率幅值:
总斜率幅值= √[(Gx)2+(Gy)2]
总斜率幅值= √[(11)2+(8)2] = 13.6
接下来,计算每个像素的方向。可以用tan计算角度。
tan(Φ) = Gy / Gx
因此,角度值为:
Φ = atan(Gy / Gx)
把值带入函数后,得出的方向值为36。所以至此,已经有每个像素值的总梯度和方向。然后需要使用这些梯度和方向值生成直方图。
但等等——在深入了解HOG特征描述子中的直方图是如何创建的之前,先休息一下。把这想作整个过程中的一个小步骤。文中将先讨论使用已拥有的两个值——梯度和方向来创建直方图的一些简单方法。
使用梯度和方向创建直方图的方法
直方图是展示一组连续数据分布频率的图表。已有x轴上的变量(bin形式)和y轴上的频率。本文中使用x轴上的角度或方向,y轴上的频率。
方法1:
首先是最简单的生成直方图的方式。使用每个像素值,找出像素的方向并更新频率表。
下图是高亮的像素值(85)的过程。因为此像素的方向值为36,所以针对此值在36上方填入一个数字,以表示频率:
来源: 机器学习应用课程
对所有像素值重复此过程,直至标记完图像中这些角度和出现频率表。这个频率表可使用x轴的角度值和y轴的频率值生成直方图。
这是创建直方图的一种方法。注意,此处直方图的bin值为1。由此得到约180个不同的bucket,每个代表一个方向值。另一种方法是为更大的bin值创建直方图特征。
方法2:
此法与方法1类似,唯一的不同是bin的大小为20。所以,得出bucket的数量为9。
随后,检查每个像素的方向并存储9x1矩阵中方向值的频率。绘制此图得出直方图:
来源: 机器学习应用课程
方法3:
以上两种方法仅用方向值生成直方图,没有将梯度值考虑在内。方法3是生成直方图的另一种方法——将梯度幅值填入矩阵,而不是频率。请看下图示例:
来源:机器学习应用课程
可能会注意到,使用方向值30,只更新为20的bin值。另外,还应该给其它bin增加一些权重。
方法4:
此法对方法4做出一些微调。在此,将像素梯度的contribution值加到像素梯度任意一边的bin中。请记住,bin值越接近方向值的,contribution更高。
来源:机器学习应用课程
这就是HOG特征描述子创建直方图的方式。
第4步:计算8x8单元(9x1)的梯度直方图
HOG特征描述子中创建的直方图不是为整幅图像生成的。相反,图像被分成8x8的几个单元,且为每个单元计算定向梯度直方图。你觉得这会发生什么呢?
这样做得到更小区域的特征(或直方图),相应地代表整幅图像。在此当然可以将8x8的值改为16x16或32x32。
如果将图像分为8x8单元并生成直方图,相应每个单元会得到一个9x1的矩阵。此矩阵使用上文提到的方法4生成。
一旦为图片中8x8的区域生成HOG,接下来就是进行直方图规范化。
第5步:在16x16单元(36x1)中进行梯度规范化
理解规范化如何进行之前,先理解这样做的原因很重要。
尽管已经为图像8x8单元创建了HOG特征,图像的梯度对整体的亮度尤为敏感。这意味着对于一张特定图片,图像的某一部分与其他部分相比会非常明亮。
虽然无法从此图像中彻底清除亮度的差别,但是可以通过对16x16区域进行梯度规范化来减弱亮度变化。下图例子可以解释16x16区域是如何创建出来的。
在此合并四个8x8单元创建一个16x16的区域。已知每个8x8的单元的直方图有一个9x1矩阵。所以,此处应有4个9x1矩阵或者一个36x1矩阵。为对矩阵进行规范化,用每一个值除以值的平方和的平方根。给定的向量V的数学表示为:
V = [a1, a2, a3, ….a36]
计算平方和的平方根数值:
k = √(a1)2+ (a2)2+ (a3)2+ ….(a36)2
用向量V中的每一个值除以k:
结果将是一个大小为36x1的规范化向量
第6步:完整图像特征
目前处于为图像生成HOG特征的最后一步。至此,已经为图像中的16x16区域创建特征。现在将所有特征合并用于获得最终图片的特征。
你能猜出给定图像最终的特征总数是多少吗?首先需要求出一个64×128图像可以得到多少16×16大小的区域:
105(7x15)块16x16区域。每一块都有一个36x1的向量作为特征。因此,图片的特征总数为105x36x1=3780个。
现在已为一幅图片生成了HOG特征,文末还会验证是否得到了相同数量的特征。
在Python中应用HOG特征描述子
是时候打开Python了!笔者敢保证这是本文最令人期待的部分。一起看下去吧。
下文将显示一幅图的HOG特征是如何生成的,以及同样的方法能否应用于更大的数据集。首先下载所需的数据库和即将要创建HOG特征的图像:
#importing required libraries
from skimage.io import imread, imshow
from skimage.transform import resize
from skimage.feature import hog
from skimage import exposure
import matplotlib.pyplot as plt
%matplotlib inline
#reading the image
img = imread('puppy.jpeg')
imshow(img)
print(img.shape)
(663, 459, 3)
由上可见,图像大小为663x459。需要将图像大小变为64x128。请注意,文中所使用的是skimage,其需要输入高度x宽度。
#resizing image
resized_img = resize(img, (128,64))
imshow(resized_img)
print(resized_img.shape)
(128, 64, 3)
本文中将直接使用skimage.features的hog函数。因此不必单独计算梯度、幅值(总梯值)和方向。hog函数将在内部计算它并返回特征矩阵。
此外,如果设置参数为‘visualize = True’,它将返回一张HOG的图像。
#creating hog features
fd, hog_image = hog(resized_img, orientations=9, pixels_per_cell=(8, 8),
cells_per_block=(2, 2), visualize=True, multichannel=True)
在继续前,先介绍一下这些超参数都代表什么。
· orientations是所创建的bucket数量。因为本文中想得到一个9x1的矩阵,所以将orientations设置为9。
· pixels_per_cell定义所创建直方图的单元尺寸。本文中所涉及的例子都使用了8x8单元,在此将设置相同的值。正如上文所提,你可以选择改变这个值。
· 另一个超参数cells_per_block指所规范化的直方图上的小块区域大小。本文提到的单元是指每小块区域,而不是像素的数量。所以,此处用2x2表示,而不是16x16。
函数的特征矩阵存储在变量fd中, 图像存储于hog_image中。检查一下特征矩阵的大小:
fd.shape
(3780,)
正如预期那样,共有3780个图像特征,这验证了之前在第7步中所做的计算。你可以选择更改超参数的值,这将提供不同大小的特征矩阵。
最后,来看一看HOG图像:
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()
留言 点赞 关注
我们一起分享AI学习与发展的干货
欢迎关注全平台AI垂类自媒体 “读芯术”
(添加小编微信:dxsxbb,加入读者圈,一起讨论最新鲜的人工智能科技哦~)