计算机视觉04_HOG

一、基本原理

HOG(Histogram of Oriented Gradients,方向梯度直方图)是一种用于计算机视觉和图像处理领域的特征描述子,HOG特征描述符可以将3通道的彩色图像转换成一定长度的特征向量。

二、HOG特征描述符的具体步骤

2.1 图像预处理

HOG特征通过在一张64×128的图片块上计算得到以用于行人检测。当唯一的要求就是图片块需要有固定的长宽比。在我们的例子中,图片块需要保持1:2 的纵横比。比如:100×200, 128×256都可以,但102×198就不满足要求。

下面给出一张图像(宽×高=100×200)为例:

import cv2
import numpy as np

# 读取图像并转为灰度图
img = cv2.imread('img.png', 0)
cv2.imshow('img1',img)

# Wait for the user to press a key
cv2.waitKey(0)
# print(np.max(img)) 为253
img2 = np.power(img/float(np.max(img)), 1.5)

print(f'img2的值{img2}')

灰度处理是可选操作,因为灰度图像和彩色图像都可以用于计算梯度图,对于彩色图像,先对三通道颜色值分别计算梯度,然后取梯度值最大的那个作为该像素的梯度。

这里我们为进一步降低光照对图像的影响(包括光照不均和局部阴影),降低曝光,更接近人的视角,对图像进行伽马矫正处理。

 γ ​越大,图像越暗;为1时,表示没有变化。(PS:注意,伽马矫正收益不一定大,剩下的步骤忽略伽马矫正,想要的读者自行使用)

2.2 计算梯度图

要想得到梯度直方图,先需要计算水平梯度和垂直梯度,我们借用内核过滤图像进行计算。本次采用内核大小为1的Sobel算子计算。

Sobel(1)算子:    [-1,0,1]                 用于计算水平梯度 

                                 [ [-1], [0], [1] ]       用于计算垂直梯度

然后再计算x和y方向梯度的合梯度,包括幅值和方向:(PS:梯度方向会取绝对值,因此得到的角度范围是 [0,180°],例如1或179表示梯度方向指向近似正上方或者正下方)

 代码展示:

import cv2
import numpy as np

# 读取图像并转为灰度图
img = cv2.imread('img.png', 0)
img = np.float32(img) / 255.0  # 归一化

# 计算x和y方向的梯度
gx = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=1)
cv2.imshow('gx',gx)
cv2.waitKey(0)

gy = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=1)
cv2.imshow('gy',gy)
cv2.waitKey(0)

# 计算合梯度的幅值和方向(角度)
mag, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True)
cv2.imshow('mag',mag )
cv2.waitKey(0)

cv2.imshow('angle',angle )
cv2.waitKey(0)

该代码会生成四个图像,读者自行运行查看。x方向梯度图会强化垂直边缘特征,y方向梯度图会强化水平边缘特征。

2.3 计算梯度直方图

计算梯度直方图的目的是简化运算量,因为图像的梯度图有效特征非常少,我们将图像分成若干个8×8的小单元,称为cell,并计算每个cell的梯度直方图。这样一共cell包含8×8×2个值,2为梯度的大小与方向。

我们来看一下图片中的一个cell中的梯度:

中间那张图中的箭头表示梯度,箭头方向表示梯度方向,箭头长度表示梯度大小。

右上方那张图为梯度大小,右下角那张图为梯度方向,注意角度的范围介于0到180度之间,而不是0到360度, 这被称为“无符号”梯度,因为两个完全相反的方向被认为是相同的。

现在我们来计算cell中像素的梯度直方图,先将角度范围分成9份,也就是9 bins,每20°为一个单元,也就是这些像素可以根据角度分为9组。将每一份中所有像素对应的梯度值进行累加,可以得到9个数值。直方图就是由这9个数值组成的数组,对应于角度0、20、40、60... 160。HOG

还有一个细节需要注意。如果梯度方向大于160°。此时梯度的角度位于160°和180°之间。我们知道0°和180°是一样的(无符号梯度),因此在下面的例子中,梯度方向为165°的像素按比例将梯度大小分配到0°和160°的bin中。

8×8的cell中所有像素处的梯度按照方向将梯度大小累加到9个bin以创建最后的梯度直方图。上图中的cell对应的梯度直方图如下:

 可以看到直方图中,0度和160附近有很大的权重,说明了大多数像素的梯度向上或者向下,也就是这个cell是个横向边缘。

2.4 Block 归一化

HOG将8×8的一个区域作为一个cell,再以2×2个cell作为一组,称为block。由于每个cell有9个值,2×2个cell则有36个值,HOG是通过滑动窗口的方式来得到block的,如下图所示:

动图封面

在前面的步骤中,我们基于图像的梯度对每个cell创建了一个直方图。

但是图像的梯度对整体光照非常敏感,比如通过将所有像素值除以2来使图像变暗,那么梯度幅值将减小一半,因此直方图中的值也将减小一半。 理想情况下,我们希望我们的特征描述符不会受到光照变化的影响,那么我们就需要将直方图“归一化” 。

知道了如何归一化,现在来对block的梯度直方图进行归一化(注意不是cell),一个block有4个直方图,将这4个直方图拼接成长度为36的向量,然后对这个向量进行归一化。

因为使用的是滑动窗口,滑动步长为8个像素,所以每滑动一次,就在这个窗口上进行归一化计算得到长度为36的向量,并重复这个过程。

2.5 计算HOG特征向量

终于可以计算整个图像的特征描述符了,每滑动一次,一个block就得到一个长度为36的特征向量,那会得到多少个特征向量呢?

比如上面这个图,将整幅图像划分成cell的个数为8x16,就是横向有8个cell,纵向有16个cell。每个block有2x2个cell的话,那么block的个数为:(16-1)x(8-1)=105。即有7个水平block和15个竖直block。

再将这105个block合并,就得到了整个图像的特征描述符,长度为 105×36=3780。

三、代码实现

from skimage import feature, exposure
import cv2
image = cv2.imread('img.png',0)
fd, hog_image = feature.hog(image, orientations=9, pixels_per_cell=(16, 16),
                    cells_per_block=(2, 2), visualize=True)

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

cv2.imshow('img', image)
cv2.imshow('hog', hog_image_rescaled)
cv2.waitKey(0)==ord('a')

 feature.hog函数介绍:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值