一、HOG方向梯度直方图
1.HOG简介
方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。它通过计算和统计图像局部区域的梯度方向直方图来构成特征。Hog特征结合SVM分类器已经被广泛应用于图像识别中。HOG的思想就是在一副图像中,局部目标的表象和形状(appearance and shape)能够被梯度或边缘的方向密度分布很好地描述。
2.HOG基本步骤简述
(1)标准化gamma空间和颜色空间
第一步,为了减少光照因素的影响,首先需要将整个图像进行规范化(归一化)。在图像的纹理强度中,局部的表层曝光贡献的比重较大,所以,这种压缩处理能够有效地降低图像局部的阴影和光照变化。因为颜色信息作用不大,通常先转化为灰度图;
(2)计算图像梯度
第二步,计算图像横坐标和纵坐标方向的梯度,并据此计算每个像素位置的梯度方向值;求导操作不仅能够捕获轮廓,人影和一些纹理信息,还能进一步弱化光照的影响。
(3)为每个细胞单元构建梯度方向直方图
第三步,为每个细胞单元构建梯度方向直方图的目的是为局部图像区域提供一个编码,同时能够保持对图像中人体对象的姿势和外观的弱敏感性。我们将图像分成若干个“单元格cell”,例如每个cell为66个像素。假设我们采用9个bin的直方图来统计这66个像素的梯度信息。但bin并不是连续的,而是20度为一个bin,然后相同bin是关于180度对称。
(4)把细胞单元组合成大的块(block),块内归一化梯度直方图
第四步,由于局部光照的变化以及前景-背景对比度的变化,使得梯度强度的变化范围非常大。这就需要对梯度强度做归一化。归一化能够进一步地对光照、阴影和边缘进行压缩,方法是把各个细胞单元组合成大的、空间上连通的区间(blocks)。例如本次实验所使用的block是(16, 16),窗口(即图片)大小是(64, 128),block的滑动步长是(8,8),共有105个block,block内的cell是(8, 8),共有4个cell,而cell内的bin是9个,那么总共有36715=3780个特征。
(5)收集HOG特征
最后一步就是将检测窗口中所有重叠的块进行HOG特征的收集,并将它们结合成最终的特征向量供分类使用,在opencv中使用相应的方法。图1 HOG检测步骤流程。
图1 HOG检测步骤流程
二、SVM支持向量机
支持向量机(支持向量机(Support Vector Machine, SVM)是一类按监督学习(supervised learning)方式对数据进行二元分类的广义线性分类器(generalized linear classifier),将样本分为正样本和负样本,其决策边界是对学习样本求解的最大边距超平面(maximum-margin hyperplane)。SVM一般用于解决模式识别领域中的数据分类问题,属于有监督学习算法的一种。
三、实验流程
1.数据集准备
数据集分为正负样本数据集,2个文件夹,分别存储在pos(pos1为作者的图片数据集)和neg文件夹下,正样本有820张图片,负样本有1931张图片,均是64*128的格式。
2.图像预处理
对图像进行3以下3步的预处理:首先将视频分解为图片,其次是图片缩放,最后是将图片裁剪为64 * 128。
3.实验结果
图2和图3分别是我仿造源作者代码的实验结果以及作者的实验结果,明显的看出我的实验结果并不准确。
图2 自己的实验结果
图3 原作的实验结果
四、程序代码
1.视频图像的预处理
(1)视频分解
'''
视频分解图片 video_Decomposition(video_name)
1 load 2 info 3 parse 4 imshow imwrite
负样本 64*128 正样本:64*128
'''
import cv2
import numpy
as np
def video_Decomposition(video_name
, begin
):
cap
= cv2
.VideoCapture
(video_name
)
isOpened
= cap
.isOpened
print(isOpened
)
fps
= cap
.get
(cv2
.CAP_PROP_FPS
)
width
= int(cap
.get
(cv2
.CAP_PROP_FRAME_WIDTH
))
height
= int(cap
.get
(cv2
.CAP_PROP_FRAME_HEIGHT
))
print(fps
, width
, height
)
i
= 0 + 205 * (begin
- 1)
while(isOpened
):
if(i
== 205 * (begin
- 1) + 205):
break
else:
i
= i
+ 1
(flag
, frame
) = cap
.read
()
fileName
= 'pos_Original//' + str(i
) + '.jpg'
print(fileName
)
if flag
== True:
cv2
.imwrite
(fileName
, frame
, [cv2
.IMWRITE_JPEG_QUALITY
,100])
print(i
)
print("video_Decomposition OK!")
for i
in range(1, 5):
video_Decomposition
(str(i
) + '.mp4', i
)
(2)图片裁剪缩放
'''
裁剪缩放图片 def img_Resize(path, imgNum)
'''
import cv2
def img_Resize(pos_path
, imgNum
):
for i
in range(1, imgNum
+ 1):
img
= cv2
.imread
(pos_path
+ str(i
) + '.jpg', 1)
print(pos_path
+ str(i
) + '.jpg')
imgInfo
= img
.shape
print(imgInfo
)
height
= imgInfo
[0]
width
= imgInfo
[1]
mode
= imgInfo
[2]
dstHeight
= int(height
* 0.2)
dstWidth
= int(width
* 0.05)
dst
= cv2
.resize
(img
, (dstWidth
, dstHeight
))
imgInfo
= dst
.shape
print(imgInfo
)
cv2
.imwrite
('pos//'+ str(i
) + '.jpg', dst
)
print("img_Resize OK!")
img_Resize
('pos_Original//', 820)
(3)图片的裁剪
'''
图片的裁剪 def img_Spilt(pos_path, imgNum)
'''
def img_Spilt_and_Rotation(pos_path
, imgNum
):
for i
in range(1, imgNum
+ 1):
img
= cv2
.imread
(pos_path
+ str(i
) + '.jpg', 1)
print(pos_path
+ str(i
) + '.jpg')
img
= img
[10:138, :]
imgInfo
= img
.shape
print(imgInfo
)
cv2
.imwrite
("pos//" + str(i
) + '.jpg', img
)
print(imgInfo
[0])
print("img_Spilt OK!!")
img_Spilt_and_Rotation
('pos//', 820)
2.使用HOG与SVM进行目标检测
(1)
import cv2
import numpy
as np
import matplotlib
.pyplot
as plt
posNum
= 820
negNum
= 1931
winSize
= (64, 128)
blockSize
= (16, 16)
blockStride
=(8, 8)
cellSize
= (8, 8)
nBin
= 9
hog
= cv2
.HOGDescriptor
(winSize
, blockSize
, blockStride
, cellSize
, nBin
)
featureNum
= int(((winSize
[0] - blockSize
[0]) / blockStride
[0] + 1) * ((winSize
[1] - blockSize
[1])/blockStride
[1] + 1) * 4 * nBin
)
print(featureNum
)
'''
featureArray和labelArray用于svm函数中
'''
featureArray
= np
.zeros
(((posNum
+ negNum
), featureNum
), np
.float32
)
print(featureArray
.shape
)
labelArray
= np
.zeros
(((posNum
+ negNum
), 1), np
.int32
)
print(labelArray
.shape
)
print("label and feature OK")
(2)
for i
in range(0, posNum
):
fileName
= 'pos1//' + str(i
+ 1) + '.jpg'
img
= cv2
.imread
(fileName
)
print(fileName
)
hist
= hog
.compute
(img
, (8, 8))
for j
in range(0, featureNum
):
featureArray
[i
, j
] = hist
[j
]
labelArray
[i
, 0] = 1
for i
in range(0, negNum
):
fileName
= 'neg//' + str(i
+ 1) + '.jpg'
print(fileName
)
img
= cv2
.imread
(fileName
)
hist
= hog
.compute
(img
, (8, 8))
for j
in range(0, featureNum
):
featureArray
[i
+ posNum
, j
] = hist
[j
]
labelArray
[i
+ posNum
, 0] = -1
print("dataset already OK!")
svm
= cv2
.ml
.SVM_create
()
svm
.setType
(cv2
.ml
.SVM_C_SVC
)
svm
.setKernel
(cv2
.ml
.SVM_LINEAR
)
svm
.setC
(0.01)
ret
= svm
.train
(featureArray
, cv2
.ml
.ROW_SAMPLE
, labelArray
)
print("SVM train OK!")
alpha
= np
.zeros
((1), np
.float32
)
rho
= svm
.getDecisionFunction
(0, alpha
)
print(rho
)
print(alpha
)
alphaArray
= np
.zeros
((1, 1), np
.float32
)
supportVArray
= np
.zeros
((1, featureNum
), np
.float32
)
resultArray
= np
.zeros
((1, featureNum
), np
.float32
)
alphaArray
[0, 0] = alpha
resultArray
= -1 * alphaArray
* supportVArray
myDetect
= np
.zeros
((3781), np
.float32
)
for i
in range(0, 3780):
myDetect
[i
] = resultArray
[0, i
]
myDetect
[3780] = rho
[0]
myHog
= cv2
.HOGDescriptor
()
myHog
.setSVMDetector
(myDetect
)
print("myhog ok")
imageSrc
= cv2
.imread
('test1.jpg', 1)
imgInfo
= imageSrc
.shape
height
= imgInfo
[0]
width
= imgInfo
[1]
mode
= imgInfo
[2]
dst
= cv2
.resize
(imageSrc
, (90, 160))
objs
= myHog
.detectMultiScale
(imageSrc
, 0, (8, 8), (32, 32), 1.05, 2)
x
= int(objs
[0][0][0])
y
= int(objs
[0][0][1])
w
= int(objs
[0][0][2])
h
= int(objs
[0][0][3])
cv2
.rectangle
(imageSrc
, (x
, y
), (x
+ w
, y
+ h
), (255, 0, 0), 2)
imageSrc
= cv2
.cvtColor
(imageSrc
, cv2
.COLOR_BGR2RGB
)
plt
.rcParams
['figure.figsize'] = (4.0, 4.0)
plt
.imshow
(imageSrc
)
plt
.title
("res")
plt
.savefig
('res.png')
cv2
.destroyAllWindows
()
五.总结与反思
这周的代码我参考了慕课网学习资料的代码,学习了HOG特征以及SVM支持向量机的基本原理以及代码实现的重点,并尝试自己设置正样本数据集,但自己并没有成功,因为自己通过预处理得到的图片并不难很好的在myHog.detectMultiScale方法中成功。我需要在日后的学习生活中继续改进, 不太能理解和作者的数据集都是64*128,为什么我会在detectMultiScale方法返回的objs报错:
objs
= myHog
.detectMultiScale
(imageSrc
, 0, (8, 8), (32, 32), 1.05, 2)
---> x
= int(objs
[0][0][0])
IndexError
: tuple index out of
range
很郁闷,应该是显示图片根本没有读进去,不知道是不是图片转换后太不清晰的原因,希望大佬赐教。
参考资料: https://blog.csdn.net/qq_35992440/article/details/80987664 https://blog.csdn.net/Fredric18/article/details/85057050#commentBox https://blog.csdn.net/qq_25352981/article/details/52605768 https://blog.csdn.net/zouxy09/article/details/7929348