目录
简介
提取HOG特征的步骤
1、预处理获取要计算其特征的输入图像
2、计算图像的梯度
3、计算8×8细胞梯度直方图
4、直方图归一化
5、计算HOG特征向量
Opencv利用HOG特征实现行人检测
HOG特征与SVM分类器结合,已经被广泛应用于图像识别中,尤其在行人检测,HOG的核心思想是所检测的局部物体外形能够被光强梯度或边缘方向的分布所描述。通过将整幅图像分割成小的连接区域,称为cells,每个cell生成一个方向梯度直方图或者cell中像素的边缘方向,这些直方图的组合可表示出所检测目标的目标的HOG特征。
具体计算图像HOG特征的方法步骤如下:
如前所述的HOG特征用于行人检测,是在64×128大小图像计算,当然,图像可能是任意大小的。通常在多个尺度上分析多个图像位置,唯一的限制是被分析的滑动窗口(win)具有固定的长宽比(纵横比)。在我们的例子中,滑动窗口需要有一个长宽比为1:2。然后再将滑动窗口的图像调整为128x64像素的大小,该设置在行人检测任务中可以获得更好的结果。为了说明这一点,下面展示了一个大尺寸的512×480图像。我们选择一块大小100×200的区域计算我们的HOG特征。并且调整我们裁剪的窗口图像大小为64×128。
图 9-8 获得输入图像
梯度是通过结合图像的大小和角度来获得的。考虑3x3像素的块,首先计算每个像素的和。对于每个像素值,首先使用以下公式计算和:
其中r为像素点的横坐标,c为像素点的纵坐标,为图像像素点的像素值,在计算 和 后,使用下面提到的公式计算每个像素的梯度幅值和角度:
使用opencv中内核大小为1的Sobel算子实现计算图像的水平和垂直梯度,并计算每个像素的梯度和角度如下:
import cv2
#导入图片
img = cv2.imread("G:\workdate\python\demo\image\soccer2.bmp",0)
#计算水平和垂直梯度
gx=cv2.Sobel(img,cv2.CV_32F,1,0,ksize=1)
gy=cv2.Sobel(img,cv2.CV_32F,0,1,ksize=1)
#计算梯度图像与角度图像
m,arg=cv2.cartToPolar(gx,gy)
cv2.imshow("gx",gx)
cv2.imshow("gy",gy)
cv2.imshow("m",m)
cv2.imshow("arg",arg)
cv2.waitKey(0)
图 9-9 运行结果
如图9所示图水平梯度在垂直线方向延伸,垂直梯度在水平线方向延伸。
在获得每个像素的梯度后,梯度矩阵(梯度和角度矩阵)被划分为8x16个大小为8x8的单元细胞(cell),如下图10所示。
图 9-10 8x8细胞单元
我们之所以把图像分为8×8细胞是因为它提供了一个紧凑的特征表示。8×8单元细胞包含8x8 = 64像素值。这个单元细胞梯度每像素包含2个值(大小和方向),那就变成8x8x2 = 128个数。通过后面我们会看到这128个数字是用9-bin直方图(可存储为长度9的数组,通俗地说是分别装到9个箱子里)表示。不仅是表示更简洁,计算在细胞梯度直方图具有更强的鲁棒性。个别的颜色梯度可能有噪音,但用一个8x8单元细胞梯度来表示梯度直方图对噪声不敏感,换句话说,就是受噪音影响不大。如图11所示,让我们看一个8×8单元细胞的图像梯度的面貌。
图 9-11 细胞梯度与角度矩阵
上图显示了用箭头表示梯度的图像的贴片,箭头显示梯度的方向,其长度显示大小。注意箭头的方向指向强度的变化方向,其大小表示差异的大小。在右边,我们看到原始的数字表示在8×8细胞有一个小的差异,那就是角度是0度和180度的梯度,而不是0到360度之间。这些被称为“无符号”渐变,因为梯度正值和它的负值用相同的数字表示。换句话说,梯度箭头和与之相对的180度箭头被认为是相同的。但是,为什么不使用0 - 360度呢?经验表明,无符号梯度课要更好地用于行人检测。在计算HOG的一些实现方法中,将允许您指定是否使用带符号的渐变。下面我们创建一个8×8细胞梯度直方图。直方图包含9个数对应角度0, 20, 40…160,其实现过程如图12所示。
图 9-12 计算8×8细胞梯度直方图
如上图所示,我们寻找在8×8细胞梯度和方向矩阵同一位置的数值。根据方向选择箱子,并根据大小选择投票(进入箱子的值)。让我们首先关注环绕在蓝色中的像素。它的角度(方向)为80度,大小为2。所以它放入到第五个箱子。用红色包围的像素的梯度方向为10度,大小为4。由于10度是0和20之间的一半,所以像素的也是均匀地分成两个箱子。还有一个细节需要注意。如果角度大于160度,则在160到180之间,我们知道角度绕成0和180相等。比如角度为165度的像素正比于0度的箱子和160度的箱子。从180-165/165-160=3可知,梯度数值在分配时,0箱子分4/1,160箱子分4/3。
在前面的步骤中,我们根据图像的梯度创建了一个直方图。图像的梯度对整体亮度是敏感的。如果通过将所有像素值除以2来使图像变暗,则梯度矩阵元素将改变一半,因此直方图值将改变一半。理想情况下,我们希望特征描述符不受光照变化的影响。换句话说,我们希望使直方图归一化,这样它们不会受到光照变化的影响。你可能会认为在计算HOG特征时可以将9x1的直方图直接看成的9×1矢量进行归一化。可以是可以,但更好的办法是归一化一个更大尺寸的16×16的图像块,而不是8×8的单元细胞矩阵大小。16×16图像块用4个直方图可级联成一个36×1元矢量,最后归一化36×1的向量。
计算整个图像的单元细胞后的最终的特征向量,36×1载体连接成一个巨大的载体。这个向量的大小是多少?原图截取100*200—>resize—>64*128,我们有多少个16×16图像块吗?有7个水平和15个垂直位置,总共105个16×16图像块。每16×16块由36×1矢量表示。所以当我们连接成一个巨大的载体,最后得到了36×105 = 3780维向量。
用opencv实现输入图像的HOG特征的可视化代码如下:
from skimage import feature, exposure
import cv2
image = cv2.imread('image/soccer2.bmp')
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
fd, hog_image = feature.hog(image,orientations=3,pixels_per_cell=(8, 8), cells_per_block=(2, 2), block_norm='L2-Hys',feature_vector=True,visualize=True)
cv2.imshow('hog', hog_image)
cv2.waitKey(0)
图 9-13 hog特征可视化
HOG 是根据细胞单元格创建的,这些细胞单元格组合成区块,并且区块之间可以重叠,因此很难对它进行直观显示。不过可以通过显示每个单元格的直方图来表示HOG。如图14所示,显示方向直方图时,不使用柱状图,而是采用更加直观的星形图,每个线条的方向与 bin 对应,长度与 bin 的数量成正比。可以用这种方法在图像上绘制 HOG。
Opencv利用HOG特征实现行人检测,包括了HOG的特征提取和SVM识别两部分。利用OpenCV自带的行人检测其实现行人检测主要有三步:
使用opencv的自带的hog目标检测模型结合其训练好的SVM实现行人检测的代码如下:
import cv2
base_path = 'image/people.jpg'#待检测图像的文件路径
img=cv2.imread(base_path)
hog = cv2.HOGDescriptor() #初始化HOG描述子
# 设置支持向量机,其为一个预先训练好的行人检测器
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
#检测行人
rects, wei = hog.detectMultiScale(img, winStride=(4, 4), padding=(8, 8), scale=1.05)
for (x, y, w, h) in rects:
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2) #将检测结果在图像中圈出来
cv2.imshow("people detect", img) #显示图像
cv2.waitKey(0)
图 9-18 行人检测
如上图所示我们使用opencv自带模型很好的实现了图像中行人的检测,下面对我们用到的检测器进行简单的介绍。
cv2.HOGDescriptor():OpenCV中的HOG特征提取功能使用了HOGDescriptor这个类来进行封装。其中包含了许多函数,下面列举了常用的一些函数: