HOG算法

HOG算法思想

  HOG算法(方向梯度直方图)是在2005年由Navneet Dalal在论文Histograms of Oriented Gradients for Human Detection中首次提出的,主要是为了基于各像素点的梯度提取出图像中目标的轮廓,用较少的特征更好地表达图像中目标信息。本文主要参考:
https://blog.csdn.net/qq_21521561/article/details/85194921.
https://zhuanlan.zhihu.com/p/85829145

主要思想
官方解释:在一幅图像中,局部目标的表象和形状能够被梯度或边缘的方向密度分布很好的描述。
个人理解:比如我们在做动物识别时,给我们一张图,判断其为猫还是狗,首先我们已经有许多猫狗图片的训练集,但是怎么将图片中的特征提取出来,一张彩色图片其实就是一个三维矩阵,如果我们直接将这三维矩阵合并成一个向量,那么这个向量在后面进行训练时会出现几个问题:
  1、目标会受到目标所处的环境影响,环境是我们不关心的特征,如果使用整个图片的信息,将会加大我们后面识别目标的难度,所以我们主要通过提取目标的轮廓信息。
  2、原始彩图的特征信息太多,可能后面用分类算法时训练不充分,用hog算法可以对特征进行压缩,经研究实验发现,经过hog提取特征后识别的成功率会大大提升。

HOG算法步骤

  HOG算法的过程主要如下:首先读取彩色图像并将其转化为灰度图像;并对灰度图像矩阵归一化,目的是为了减少光照和背景等因素的影响,本文主要用伽马校正法;选择合适的梯度算子来计算梯度图,主要分为x和y方向上的梯度;然后计算出合梯度的幅值和方向;划分检测窗口成大小相同的cell单元;组合相邻的cell单元成更大的相互重叠的块(block),便于充分利用重叠的边缘信息,然后统计整个块的直方图;对每个块内的梯度直方图归一化,综合所有块的信息,对HOG特征描述符可视化。
  HOG具体流程和代码实现如下:
  1、读取灰度图片(彩色图片颜色信息作用不大,只需要灰度图的轮廓信息),本文以读取下面512*512大小的图片为例:

import cv2
img = cv2.imread('yang.jpg', 0)     #参数0表示读取灰度图片
cv2.imshow('IMREAD_gray', img)
cv2.waitKey(0)   #避免图片一闪而过,保证其长时间停留窗口
cv2.deatroyAllWindows()     #避免打开图片引起未响应结果

yang.jpg原图如下,其大小为512*512:
yang
所读取的灰度图如下:
yang_gray
  2、采用伽马校正法对得到的灰度图进行归一化,伽马校正可以理解通过对原灰度图归一化后的结果经过一个幂函数转化,目的是为了调节图像的对比度,降低图片背景和光照的影响,同时可以抑制噪声的干扰。本文伽马校正指数选择的是1.5。

img2 = np.power(img/float(np.max(img)), 1.5)    #幂运算,参数一为底数,参数二为指数,这是伽马矫正,使得图像更接近人眼所见

校正后的图片如下:
yang_gray2通过比较原灰度图和经过伽马校正后的图片发现,伽马校正的灰度图目标轮廓更加明显。

  3、对伽马校正后的图像计算各个像素点的梯度(包含大小和方向),目的捕获轮廓信息。常用于计算梯度的梯度算子主要有Prewitt算子、Sobel算子等等(参考几种梯度算子),本文选择最简单的Prewitt算子,在python中主要通过对cv2.Sobel函数的ksize参数选择来决定使用哪种算子,需要分别计算x方向和y方向上的梯度,代码如下:

gx = cv2.Sobel(img2, cv2.CV_64F, 1, 0, ksize=1)   #ksize为Sobel算子大小,3是矩阵大小为3
gy = cv2.Sobel(img2, cv2.CV_64F, 0, 1, ksize=1)
gx1 = np.abs(gx)    ##在计算梯度时可能存在右侧像素减去左侧像素为负值的情况,所以对其取绝对值后进行比较
gy1 = np.abs(gy)
cv2.imshow('IMREAD_gray2_gx', gx1)
cv2.imshow('IMREAD_gray2_gy', gy1)
cv2.waitKey(0)   #避免图片一闪而过,保证其长时间停留窗口
cv2.destroyAllWindows()

**注意:**上述代码中要有一个对计算的梯度取绝对值的过程,因为当计算梯度时右侧像素减去左侧像素为负值时,图片显示会将负数视作0。
x方向上的梯度图如下:
gray_gxy方向上的梯度图:
gray_gy
  4、将伽马校正后的图像划分成cell单元,本文是将其划分成16 * 16大小的cell(即每16 * 16个像素为一个cell),并计算每个cell的梯度直方图,此时每个cell单元所含有的信息有 16 × 16 × 2 = 512 16\times16\times2=512 16×16×2=512个值,因为每个像素点处有梯度的大小和方向两个值。
  接下来针对每个cell计算其梯度直方图,也就是将这512个值的信息能压缩成更少的特征,所以就用长度为9的数组来表示这 16 × 16 16\times16 16×16的信息。将角度范围0-180°划分成9份,即9 bins,也就是将像素点的梯度累计加到对应角度数组中,这也就是将一个cell中的梯度大小和方向信息用梯度直方图来表示。
  5、确定block大小,本文选择将 2 × 2 2\times2 2×2个cell作为一组,即为一个block,最终整张图片信息是通过滑动block窗口来获取的,此时一个block中包含的是4个cell,每个cell中包含的是9个值(梯度直方图),故而一个block中包含36个值。
  接下来是对每个block进行归一化,之所要归一化的原因是图像的梯度对光照环境等因素非常敏感,比如将图片像素值都除以2,此时图片光线会变暗,那么梯度的幅度值也会减少一半,因此梯度直方图中的值也就会减少一半,为了避免特征描述符不受环境影响,我们需要将直方图归一化。
  将一个block中4个cell拼接成长度为36的向量,通过对向量每个元素除以该向量的L2范数对block归一化。
  6、计算HOG特征向量,首先明确其大小,由于block从图片左上角向右下角滑动,x方向上可滑动(32-1)次,同理y方向上也可滑动(32-1)次,所以最终图片的HOG特征向量由 31 × 31 × 36 = 34596 31\times31\times36=34596 31×31×36=34596个值组成。然后对图像的HOG特征进行可视化,注意重新缩放直方图以获得更好的展示,代码如下:

from skimage import feature
from skimage import exposure
fd, hog_image = feature.hog(img, orientations=9, pixels_per_cell=(16, 16), cells_per_block=(2, 2), visualize=True)
hog_image_rescaled = exposure.rescale_intensity(hog_image, in_range=(0, 10))
cv2.imshow('img', img)
cv2.imshow('hog', hog_image_rescaled)
cv2.waitKey(0)
cv2.destroyAllWindows()

最后基于HOG特征向量重新缩放的直方图可视化如下:
yang_hog

HOG算法总结

  HOG算法是一个将图片原始信息最终压缩成一个向量的过程,当我们将一张照片通过HOG算法得到此HOG特征描述符后,相当于我们得到了图片的样本数据,就可以拿来用于机器学习中对模型进行训练,然后结合机器学习模型比如SVM来实现路上行人检测等目的。当然HOG虽然存在维度降低,忽略光照等环境因素的影响,但也存在因梯度使得描述子对噪声敏感的问题。所以可以结合SIFT和LBP算法来对图像进行处理。

  • 12
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值