hog特征提取
- https://blog.csdn.net/q123456789098/article/details/52748918
- https://blog.csdn.net/zouxy09/article/details/7929348
实现方法
首先将图像分成小的连通区域
,我们把它叫细胞单元。然后采集细胞单元中各像素点的梯度的或边缘的方向直方图
。最后把这些直方图组合起来就可以构成特征描述器。
实现过程
-
1)图像灰度化
cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
-
2)采用Gamma校正法对输入图像进行颜色空间的标准化(归一化);目的是 调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰;
I ( x , y ) = I ( x , y ) g a m m a I(x,y)=I(x,y)^{gamma} I(x,y)=I(x,y)gamma 比如可以取
Gamma=1/2
-
3)计算图像每个像素的梯度(包括大小和方向);主要是为了捕获轮廓信息,同时进一步弱化光照的干扰。
图像中像素点(x,y)的梯度为:
最常用的方法是:首先用`[-1,0,1]`梯度算子对原图像做卷积运算,得到x方向(水平方向,以向右为正方向)的梯度分量gradscalx,然后用`[1,0,-1]T`梯度算子对原图像做卷积运算,得到y方向(竖直方向,以向上为正方向)的梯度分量gradscaly。然后再用以上公式计算该像素点的梯度大小和方向。
-
4)将图像划分成小cells(例如
6*6
像素/cell);我们将图像分成若干个“单元格cell”,例如每个cell为
6*6
个像素。假设我们采用9个bin的直方图来统计这6*6个像素的梯度信息。也就是将cell的梯度方向360度分成9个方向块,如图所示:例如:如果这个像素的梯度方向是20-40度,直方图第2个bin的计数就加一,这样,对cell内每个像素用梯度方向在直方图中进行加权投影(映射到固定的角度范围),就可以得到这个cell的梯度方向直方图了,就是该cell对应的9维特征向量(因为有9个bin)。像素梯度方向用到了,那么梯度大小呢?梯度大小就是作为投影的权值的。例如说:这个像素的梯度方向是20-40度,然后它的梯度大小是2(假设啊),那么直方图第2个bin的计数就不是加一了,而是加二(假设啊)。
-
5)把细胞单元组合成大的块(block),块内归一化梯度直方图
由于局部光照的变化以及前景-背景对比度的变化,使得梯度强度的变化范围非常大。这就需要对梯度强度做归一化。归一化能够进一步地对光照、阴影和边缘进行压缩。
作者采取的办法是:把各个细胞单元组合成大的、空间上连通的区间(blocks)。这样,一个block内所有cell的特征向量串联起来便得到该block的HOG特征。这些区间是互有重叠的,这就意味着:每一个单元格的特征会以不同的结果多次出现在最后的特征向量中。我们将归一化之后的块描述符(向量)就称之为HOG描述符。
区间有两个主要的几何形状——矩形区间(R-HOG)和环形区间(C-HOG)。R-HOG区间大体上是一些方形的格子,它可以有三个参数来表征:每个区间中细胞单元的数目、每个细胞单元中像素点的数目、每个细胞的直方图通道数目。
例如:行人检测的最佳参数设置是:3×3细胞/区间、6×6像素/细胞、9个直方图通道。则一块的特征数为:3*3*9
;
-
6)收集HOG特征
最后一步就是将检测窗口中所有重叠的块进行HOG特征的收集,并将它们结合成最终的特征向量供分类使用。 -
7)那么一个图像的HOG特征维数是多少呢?
顺便做个总结:Dalal提出的Hog特征提取的过程:把样本图像分割为若干个像素的单元(cell),把梯度方向平均划分为9个区间(bin),在每个单元里面对所有像素的梯度方向在各个方向区间进行直方图统计,得到一个9维的特征向量,每相邻的4个单元构成一个块(block),把一个块内的特征向量联起来得到36维的特征向量,用块对样本图像进行扫描,扫描步长为一个单元。最后将所有块的特征串联起来,就得到了人体的特征。例如,对于
64*128
的图像而言,每16*16
的像素组成一个cell,每2*2
个cell组成一个块,因为每个cell有9个特征,所以每个块内有4*9=36
个特征,以8个像素为步长,那么,水平方向将有7个扫描窗口,垂直方向将有15个扫描窗口。也就是说,64*128
的图片,总共有36*7*15=3780
个特征。图像大小
64x128
;cell大小16x16
;block大小2x2
cell 对应的像素大小32x32
;每个cell有9个特征;每个block内有4*9=36
个特征; 以8个像素为步长(stride)
实现代码
# @Time: 2021/6/9 16:47
# @Author: wucong
# @File: computer_hog.py
# @Software: PyCharm
# @Version: win10 Python 3.7.6
# @Version: torch 1.8.1+cu111 torchvision 0.9.1+cu111
# @Version: tensorflow 2.4.1+cu111 keras 2.4.3
# @Describe:
"""
https://blog.csdn.net/q123456789098/article/details/52748918
https://blog.csdn.net/zouxy09/article/details/7929348
首先将图像分成小的连通区域,我们把它叫细胞单元。
然后采集细胞单元中各像素点的梯度的或边缘的方向直方图。
最后把这些直方图组合起来就可以构成特征描述器。
"""
import cv2
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import normalize
from numba import jit
from scipy import signal
import time
# from skimage.feature import hog
# %matplotlib tk
# %matplotlib inline
def computer_cell(cell_x, cell_y, cell_size,bins=9):
hist = [0]*bins
for y in range(cell_size):
for x in range(cell_size):
g_value = np.sqrt(cell_x[y, x] ** 2 + cell_y[y, x] ** 2)
if cell_x[y, x]==0:
hist[-1] += g_value # int(g_value.round())
continue
g_direct = np.arctan(cell_y[y, x]/cell_x[y, x])/np.pi*180
if g_direct < 0:g_direct = 180+g_direct
hist[int(g_direct//(180//bins))] += g_value # int(g_value.round())
return np.array(hist)
def computer_block(tgx,tgy,block_size,cell_size,bins=9):
feature = np.zeros([block_size,block_size,bins])
for cy in range(block_size):
for cx in range(block_size):
cell_x = tgx[cy, cx, ...]
cell_y = tgy[cy, cx, ...]
feature[cy,cx]=computer_cell(cell_x, cell_y, cell_size,bins)
# 归一化
return normalize(feature.reshape(-1)[None])[0]
def hog(img:np.array,gamma=0.5,cell_size=6,block_size=3,stride=0,bins=9,h=64,w=64):
"""
Args:
img: 默认是 BGR格式
gamma:
cell_size: 6 表示6x6 个像素 组成一个cell
block_size: 3 3x3 个cell 组成一个block
bins: 9 表示9个方向 180/9=20 每20度划分一个bin
h: resize的大小
w: resize的大小
Returns:
"""
# 1.灰度化
if img.ndim>2:img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img = cv2.resize(img, (w, h))
# 2.Gamma校正
img = img ** gamma
# 3 计算图像梯度
gx = cv2.filter2D(img, -1, np.array([[-1, 0, 1]]))
gy = cv2.filter2D(img, -1, np.array([-1, 0, 1])[..., None])
stride = cell_size // 2 if stride==0 else stride
kernel = cell_size * block_size
feature = []
for i in range(0, h - kernel, stride):
for j in range(0, w - kernel, stride):
tgx = gx[i:i + kernel, j:j + kernel]
tgy = gy[i:i + kernel, j:j + kernel]
tgx = tgx.reshape(block_size, block_size, cell_size, cell_size)
tgy = tgy.reshape(block_size, block_size, cell_size, cell_size)
feature.append(computer_block(tgx,tgy,block_size,cell_size,bins))
feature = np.stack(feature).reshape(-1)
return feature
if __name__=="__main__":
start = time.time()
img = cv2.imread('./6_36_1.jpg')
feature = hog(img,cell_size=12,stride=3)
end = time.time()
print(feature.shape,'cost time:%.5f'%(end-start))