概述
在这篇博文中,我们将会学习方向梯度直方图(HOG)特征描述符的一些细节。我们将会了解这个特征是什么,并且使用Opencv来对其进行计算。
这里有个很有趣的比喻,如果你是一名初学者,你的目标是星辰大海,那可以看看。
Q:你打算怎么吃掉大象。
A:一口一口的吃掉。
什么是图像特征描述符
简单来说,就是某个东西,能够很好的表示图像,而这个东西具有有效的信息,并且没有太多的冗余。
如果有看过一些深度学习的小伙伴,第一感觉应该是,害,不就是我绞尽脑汁搭建出来的网络所输出的东西嘛。其实不全是。
对于HOG描述符而言,如果输入图像的大小为64x128x3,那么,输出的特征向量长度为3780。
怎么计算的?后边会有给出,不要急噢~
但是,对于一幅图像来说,什么信息是有用的?什么信息又是无用的?因此,特征描述符还是得在实际任务中,才能给出明确的有用与否的定义。
一个简单的例子,如果你有一个任务,是要检测出圆形的按钮。这时,按钮的边缘对你来说,是一个十分有用的信息,而按钮的颜色,可能并没有多大的用处。
此外,特征应该还要能做出唯一性的代表。例如,你所提取的特征,在某些场合下,应该能够区分出硬币和汽车轮胎的不同。
在我们所讨论的HOG特征描述符中,将梯度(有方向的梯度)的方向分布(直方图)作为特征。
如何计算方向梯度直方图
在本节中,我们将对如何计算方向梯度直方图进行详细的讨论。为了方便描述,使用了一个图像块。
第一步,预处理
对于行人检测这个任务来说,HOG特征描述符是在一幅64x128的图像块上计算的。因此,对于我们要检测的对象,只要控制所选择的图像的宽高比为1:2即可。例如下图所示。
Dalal和Triggs的论文提到了使用gamma矫正来作为预处理步骤,但是增益较小,故作者跳过了这一步。
第二步,计算图像梯度
为了计算HOG描述符,我们首先先计算图像的水平梯度和垂直梯度,再用这些梯度信息构建梯度直方图。计算图像的梯度很简单,使用下图所示的内核对图像进行过滤计算即可。
借助Opencv,可以使用Sobel操作符(内核大小为1)可以获得相同的效果。
im = cv2.imread('image.png')
# 归一化
img = 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来完成计算。
mag, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True)
下图给出了计算梯度后的图像表示。
上图中,第一幅图为水平方向的梯度图;第二幅图为垂直方向的梯度图;第三幅图为梯度的大小。
值得注意的是,水平方向的梯度检测的是垂直方向的线,垂直方向的梯度检测的是水平方向的线。从第一幅和第二幅图像左边的道路线可以看出一二。
梯度图像删除了很多不重要的信息(例如,不变的彩色背景),但突出轮廓。
这里也好理解,轮廓部分通常会带来梯度的陡变。
第三步,计算8x8单元格的梯度直方图
什么意思呢,简单来说,就是用一个8x8的小方块,复制N份,已达到全部覆盖图像的地步。如下图所示。
这里有个疑问,就是我们为什么要这么做呢?
首先,我们使用特征描述符来描述一个图像块的重要原因是,特征描述符提供了一个紧凑的表示。
其次,对于每个8x8的图像块,它的每个像素包含两个值(梯度的大小和方向),因此,共有8x8x2=128个值。在文章的后边,会使用9个bin的直方图来表示这128个值。而这样的表示更为紧凑。
为什么是8x8呢?
可以这么理解,这是对行人进行检测,8x8能够更好的处理人脸和头顶的部分。
得到图像块的梯度方向和大小后,该如何构建直方图呢?
对于上幅图像,首先看梯度直方图,即最底端的那个条状方块。可以看到,这个条状方块分为9个块,每个块占20,总共表示了0-180。其次,看到上图的蓝色标注的数据。梯度方向为80,对应的梯度大小为2,因此,对应到梯度直方图中,就直接把2这个数据放入标号为80的块中即可。再看到上图中红色标注的数据。梯度方向为10,梯度大小为4,但是梯度直方图中没有合适的标号数据。因为10正好在0-20的中间,因此,将4平均分为2份,并分别放入标号为0和标号为20的块中。
从上述例子可以看出,所谓的平分,仅仅只是10在0-20中所占有的比例为0.5。为了更好的展示,给出下列的例子。
可以看到,5/20 = 0.25。因此,标号为160的块占地图重量的0.75,即85*0.75 = 63.75。
最后,得到的梯度直方图如下所示。
上图中,标号0和标号7和标号8占有了较大的比重,因此可以认为,在这个图像块中,上下为梯度的主方向。
第四步,将16x16的图像块正则化
在上述的步骤中,图像的梯度对光照十分的敏感,但这是一个令人讨厌的缺点。怎么解决呢?一种很简单的方法是将直方图归一化,让它们不受光照变化的影响。
上图中的蓝色方框就是所谓的16x16,它包含了4个直方图,即可以得到36x1的向量。对着36x1的向量做归一化,可以得到一个对光照不敏感的直方图。
第五步,计算HOG特征向量
在第四步中,我们知道,每个归一化块(16x16)包含了36x1的向量。为了计算整幅图像块的最终特征向量,我们需要将每个归一化块的向量进行拼接。
可以简单计算得到,每行有7个块,每列有15个块,即,共有7x15=105个归一化块。
所以,最终的特征向量的大小为36x105=3780!这个数字就是该篇博文最先出现的那个数字啦。