HOG特征与行人检测

HOG特征算子原理

HOG特征(Histogram of Oriented Gradient, 方向梯度直方图),通过计算图像局部区域的梯度方向直方图来构成特征。常用方法是结合SVM进行图像识别和分类。

HOG特征的几个专用名词

  1. image ,整个输入;
  2. windw ,要检测的范围;
  3. block ,一个滑窗;
  4. cell ,一个基本单位;
  5. bin ,直方图区间;

HOG特征提取步骤

图像预处理

1.灰度化(可选)
实现代码:cv2.imread('hog_det.jpg', 0)
第一个参数是图片,第二个参数是加载图像的颜色类型,取值为0,返回灰色图像(取值1则返回彩色图像)

如果读取彩色图像,那么先对三通道颜色值分别计算梯度,然后取梯度值最大的那个作为该像素的梯度。

2.Gamma变换
为了减少光照因素的影响,首先需要将整个图像进行规范化(归一化)。调节图像对比度,减少光照对图像的影响(包括光照不均和局部阴影),使过曝或者欠曝的图像恢复正常,更接近人眼看到的图像。
伽马矫正公式
f ( I ) = I γ f(I)=I^\gamma f(I)=Iγ
I I I表示图像, γ \gamma γ表示幂指数。

1) 当 γ < 1 \gamma<1 γ<1时,输入图像的低灰度值区域动态范围变大,进而图像低灰度值区域对比度增强;在高灰度值区域,动态范围变小,进而图像高灰度值区域对比度降低。 最终,图像整体的灰度变亮。

2) 当 γ > 1 \gamma>1 γ>1时,输入图像的高灰度值区域动态范围变小,进而图像低灰度值区域对比度降低;在高灰度值区域,动态范围变大,进而图像高灰度值区域对比度增强。 最终,图像整体的灰度变暗。
代码:
img2 = np.power(img/float(np.max(img)),1/2.2)

计算图像梯度

为了得到梯度直方图,那么首先需要计算图像水平方向和垂直方向梯度。求导操作不仅能够捕获轮廓,人影和一些纹理信息,还能进一步弱化光照的影响。
一般使用特定的卷积核对图像滤波实现,可选用的卷积模板有:soble算子、Prewitt算子、Roberts模板等等。

一般采用soble算子,OpenCV利用soble水平和垂直算子与输入图像卷积计算 d x dx dx d y dy dy
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
实现函数为gx=cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=1),其中img表示源图像,即进行边缘检测的图像;cv2.CV_32F表示32位浮点数;第三和第四个参数分别代表对X和Y方向求导数,对于图像来说就是差分;第五个参数ksize是指核的大小。

图像梯度带方向,其赋值为:
在这里插入图片描述
近似为:
在这里插入图片描述
角度为:

在这里插入图片描述
OpenCV中将梯度计算集成在函数cv2.cartToPolar(gx, gy, angleInDegrees=True)中( g x gx gx g y gy gy分别为水平和垂直方向的卷积结果 ,这个函数得到的为幅值和角度。

构建方向的直方图

在这一步中,图像被分成若干个8×8的cell,例如我们将图像resize至64x128的大小,那么这幅图像就被划分为8x16个8x8的cell单元,并为每个8×8的cell计算梯度直方图。当然,cell的划分也可以是其他大小,根据具体的场景确定。

为什么将图像分成若干个cell?
这是因为如果对一整张梯度图逐像素计算,其中的有效特征是非常稀疏的,不但运算量大,而且会受到一些噪声干扰。于是我们就使用局部特征描述符来表示一个更紧凑的特征,计算这种局部cell上的梯度直方图更具鲁棒性。

以8x8的cell为例,一个8x8的cell包含了8x8x2 = 128个值,因为每个像素包括梯度的大小和方向。

在HOG中,每个8x8的cell的梯度直方图本质是一个由9个数值组成的向量, 对应于0、20、40、60…160的梯度方向(角度)。那么原本cell中8x8x2 = 128个值就由长度为9的向量来表示,用这种梯度直方图的表示方法,大大降低了计算量,同时又对光照等环境变化更加地鲁棒。
在这里插入图片描述
左图是衣服64x128的图像,被划分为8x16个8x8的cell;中间的图像表示一个cell中的梯度矢量,箭头朝向代表梯度方向,箭头长度代表梯度大小。

右图是 8×8 的cell中表示梯度的原始数值,注意角度的范围介于0到180度之间,而不是0到360度, 这被称为“无符号”梯度,一条直线上两个完全相反的方向认为是相同的。
接下来,我们来计算cell中像素的梯度直方图,将0-180度分成9等份,称为9个bins,分别是0,20,40…160。然后对每个bin中梯度的贡献进行统计,统计方法是一种加权投票统计, 如上图所示,某像素的梯度幅值为13.6,方向为36,36度两侧的角度bin分别为20度和40度,那么就按一定加权比例分别在20度和40度对应的bin加上梯度值,加权公式为:
1)20度对应的bin: ( ( 40 − 36 ) / 20 ) ∗ 13.6 ((40-36)/20) * 13.6 (4036/20)13.6,分母的20表示20等份,而不是20度;
2)40度对应的bin: ( ( 36 − 20 ) / 20 ) ∗ 13.6 ((36-20)/20) * 13.6 (3620/20)13.6,分母的20表示20等份,而不是20度;
在这里插入图片描述

还有一个细节需要注意,如果某个像素的梯度角度大于160度,也就是在160度到180度之间,那么把这个像素对应的梯度值按比例分给0度和160度对应的bin。

对整个cell进行投票统计,正是在HOG特征描述子中创建直方图的方式,最终得到由9个数值组成的向量—梯度方向图:
在这里插入图片描述

block归一化

每个cell有9个值,一个block(2×2个cell)则有36个值,HOG是通过滑动窗口的方式来得到block的。

归一化的方法有很多:L1-norm、L2-norm、max/min等等,一般选择L2-norm。

例如对于一个[128,64,32]的三维向量来说,模长是 12 8 2 + 6 4 2 + 3 2 2 = 146.64 \sqrt{128^2+64^2+32^2}=146.64 1282+642+322 =146.64,这叫做向量的L2范数。将这个向量的每个元素除以146.64就得到了归一化向量 [0.87, 0.43, 0.22]。

采用同样的方法,一个cell有一个梯度方向直方图,包含9个数值,一个block有4个cell,那么一个block就有4个梯度方向直方图,将这4个直方图拼接成长度为36的向量,然后对这个向量进行归一化。

而每一个block将按照上图滑动的方式进行重复计算,直到整个图像的block都计算完成。

获得HOG描述子

每一个16 * 16大小的block将会得到一个长度为36的特征向量,并进行归一化。 那会得到多少个特征向量呢?

例如,对于上图被划分8 * 16个cell ,每个block有2x2个cell的话,那么cell的个数为:(16-1)x(8-1)=105。即有7个水平block和15个竖直block。

每个block有36个值,整合所有block的特征值,最终获得由36 * 105=3780个特征值组成的特征描述符,而这个特征描述符是一个一维的向量,长度为3780。

最后,把提取的HOG特征输入到SVM分类器中,寻找一个最优超平面作为决策函数。

基于OpenCV的实现(python)

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

if __name__ == '__main__':
    src = cv2.imread("hog_det.jpg")
    cv2.imshow("input", src)

    hog = cv2.HOGDescriptor()

    hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
    # Detect people in the image
    (rects, weights) = hog.detectMultiScale(src,winStride=(2,4),padding=(16, 16),scale=1.1,useMeanshiftGrouping=False)
    #8个参数:img 输入图像;foundLocations 存取检测到的目标位置;hitThreshold (可选)  特征到SVM超平面的距离的阈值;winStride(可选) HoG检测窗口移动时的步长(水平及竖直);padding(可选) 在原图外围添加像素;scale参数 控制金字塔的层数,参数越小,层数越多,检测时间也长。
    for (x, y, w, h) in rects:
        cv2.rectangle(src, (x, y), (x + w, y + h), (0, 255, 0), 2)
        cv2.imshow("hog-detector", src)
        cv2.imwrite("hog-detector.jpg",src)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

梯度可视化:

from skimage import feature, exposure
from matplotlib import pyplot as plt
import cv2
image = cv2.imread('hog_det.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

fd, hog_image = feature.hog(image,orientations=9, pixels_per_cell=(8, 8),cells_per_block=(2, 4), visualise=True)

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

cv2.namedWindow("img",cv2.WINDOW_NORMAL)
cv2.imshow('img', image)
cv2.namedWindow("hog",cv2.WINDOW_NORMAL)
cv2.imshow('hog', hog_image_rescaled)
cv2.waitKey(0)==ord('q')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值