计算机视觉基础系列(python与opencv的操作与运用/tensorflow的基础介绍)(二十四)---Hog+SVM的识别

本文详细介绍如何利用Hog+SVM技术进行图像目标检测,包括样本准备、特征提取及模型训练等步骤,并通过实际代码演示整个过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

训练数据的时候,首先需要做下面几步:

1.准备训练样本;2.对样本进行Hog+Svm的训练;3.运用test图片进行预测

一、准备样本

样本分为正样本和负样本,样本的准备可以运用视频的分帧截取图片存储。这里pos文件夹下包含正样本,包含所检测的目标;neg不包含检测的目标为负样本。样本的准备的时候,图片的尺寸需要注意,这里的尺寸是64x128。

样本的获取的手段:1.来源于网络;2.自己收集。一个好的样本远胜过一个复杂的神经网络,容量大。通常我们是自己收集样本的,会通过视频截取帧来得到的,比如说一秒28帧,有100秒,则可以得到2800张图片。

正样本的特点:尽可能多样性,这里的多样性一般是指的环境的多样性,干扰性因素多,这样检测的效果较好。这里有截取本数据集的部分代码。如下,代码有部分解释,也较为简单,可以看懂:

# 视频分解成图片
# 1 load加载视频 2 读取info 3 解码 单帧视频parse 4 展示 imshow
import cv2
# 获取一个视频打开cap
cap = cv2.VideoCapture('1.mp4')
# 判断是否打开
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
while(isOpened):
	if i == 100:
		break
	else:
		i = i+1
	(flag,frame) = cap.read() # 读取每一张 flag读取是否成功 frame内容
	fileName = 'imgs\\'+str(i) + '.jpg'
	print(fileName)
	if flag == True:
		#写入图片
		cv2.imwrite(fileName,frame,[cv2.IMWRITE_JPEG_QUALITY,100])
print('end!')

图片分解完后,我们这里其实准备的数据集的尺寸是64x128,所以这里我们需要裁剪和截取。下面是裁剪和截取的代码,这里的代码前面有所介绍,这里可以看到具体介绍

# 540 * 960 ==>64*128
import cv2

for i in range(0,100):
	fileName = 'imgs\\'+str(i+1)+'.jpg'
	print(fileName)
	img = cv2.imread(fileName)
	imgInfo = img.shape
	height = imgInfo[0]
	width = imgInfo[1]
	mode = imgInfo[2]
	dstHeight = 128
	dstWidth = 64
	dst = cv2.resize(img,(dstWidth,dstHeight))
	cv2.imwrite(fileName,dst)

这里准备的正样本的数量是820个,负样本是1931个,一般来说,正负样本的比例是1:2或者1:3。

二、训练样本

在训练样本的时候,要注意一些问题,在代码注释中会有详细说明,如下,代码很多地方都有,可以看一下说明注释:

可以结合上一篇博客来看,就会较快的理解。

第七步(检测)的重点介绍:
没有直接运用svm.predict来进行预测。

resultArray是3780维的,rho是一个一行一列一维的,而最终的的数组myDetect是3781维度的,所以3780的维是来自resultArray的,最后一个维度是来自rho的。

检测需要创建myhog,需要用myhog进行检测,用detectMultiScale进行检测,没有用predict方法,得到宽高等信息返回,才能把目标绘制出来。代码如下:

# 1.参数的设置   2.hog的创建(实例对象)  3.获取SVM的参数
# 4.计算hog   5.label标签    6.完成train训练    7.完成predicr     8.绘图draw
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 1 参数的设置:设置全局变量 在一个windows窗体中有105个block,每个block下有4个cell,每个cell下有9个bin,总共3780维
PosNum = 820      # 正样本的个数
NegNum = 1931     # 负样本的个数
winSize = (64, 128)       # 窗体大小
blockSize = (16, 16)      # 105个block
blockStride = (8, 8)      # block的步长
cellSize = (8, 8)
nBin = 9

# 2 hog对象的创建,HOGDescriptor创建的方法,参数设置:1.窗体的大小,2.block的大小,3.步长,4.cell的大小,5.Bin的数量
hog = cv2.HOGDescriptor(winSize, blockSize, blockStride, cellSize, nBin)

# 3 SVM分类器的创建,定义一个SVM的对象,来自机器学习的SVM创建的模块
svm = cv2.ml.SVM_create()

# 4 计算当前的hog,需要准备各种参数,并且我们需要把参数计算完后保存在某个地方,所以我们需要新设置一定的数组,或者是当前hog特征的维度
featureNum = int(((128-16)/8+1)*((64-16)/8+1)*4*9)
# 3780,特征的维度,是一个int类型;((128-16)/8+1)是block的数量,((64-16)/8+1)为windows的宽度,4就是指的一个block里面有4个cell,9是一个cell里面有9个Bin,这样计算可以的恶道3780维
# 还需要创建一个feature数组和一个label数组用于装载当前的特征,为接下来的第五步和第六步作准备,将标签和特征准备好
featureArray = np.zeros(((PosNum+NegNum), featureNum), np.float32)
# featureArray是一个二维的数组,第一个(PosNum+NegNum)是正负样本的个数,featureNum特征的维度
labelArray = np.zeros(((PosNum+NegNum), 1), np.int32)       # 定义一个标签,也是一个二维的,参数和上面的一样
# SVM 是监督学习,所以需要样本和标签 SVM进行学习,而学习的是图片中的的hog特征,所以我们可以说hog特征可以说做是SVM真正的样本,标签是我们在进行SVM训练的时候,进行监督学习使用的
# 遍历所有的图片:正负样本都需要遍历
for i in range(0, PosNum):
	fileName = 'pos\\'+str(i+1)+'.jpg'
	img = cv2.imread(fileName)             # 图片的读取
	hist = hog.compute(img, (8, 8))        # 当前hog的计算 3780维的数据,用hist装载特征,计算HOG描述子,检测窗口移动步长(8,8)
	# 当前的问题是:我们需要将hog特征装载到featureArray中,而featureArray是一个二维的,而计算出来的只是一个hist,那么这一步怎么完成呢?
	# 其实我们这里的hist是一个3780维的,而featureArray是一个二维的,且第一个参数是正负样本的个数,第二个参数是featureNum,我们可以这么操作:
	for j in range(0,featureNum):
		# featureArray装载的是hog的特征,比如说i=1的时候,第一个hog表示为hog1,i=2的时候为hog2,第二个特征,每一个特征是3780维的,所以hist[j]要放到i行,第j列中
		featureArray[i,j] = hist[j]        # hog特征的装载
	labelArray[i,0] = 1          # 正样本标签为1,labelArray也是一个二维的,n行1列的,所以纵坐标放置的是0,正样本处理完毕,接下来的负样本的设置是一样的

for i in range(0, NegNum):
	fileName = 'neg\\'+str(i+1)+'.jpg'
	img = cv2.imread(fileName)
	hist = hog.compute(img,(8,8))
	for j in range(0,featureNum):
		featureArray[i+PosNum,j] = hist[j]         # 同样要把特征放在featureArray中,所以i+PosNum是要记录负样本的时候必须装载在正样本的后面
	labelArray[i+PosNum,0] = -1 # 负样本标签为-1

# 设置SVM的属性,setType设置属性,添加当前类型,再来设置setKernel为SVM的线性内核,再来设置setC
svm.setType(cv2.ml.SVM_C_SVC)
svm.setKernel(cv2.ml.SVM_LINEAR)
svm.setC(0.01)

# 6 train,调用train进行训练,参数:1.特征数组;2.机器学习ROW_SAMPLE;3.标签数组。返回值为ret
ret = svm.train(featureArray, cv2.ml.ROW_SAMPLE, labelArray)

# 预测可以运用svm.predict来进行预测,这里我们不用,使用其他方法来进行检测
# 7 预测(创建myHog--->myDect参数得到-->来源于resultArray(公式得到) rho(训练得到))
# rho是svm得到的一个hog的描述信息,这个在最后的阈值判决的时候起作用,在累加的时候起作用
# 深入到hog以及svm最后的判决中看
alpha = np.zeros((1), np.float32)
# getDecisionFunction方法最核心的还是svm的计算,svm来源于训练方法,样本准备好后训练可以得到svm,然后得到rho
rho = svm.getDecisionFunction(0, alpha)
print(rho)
print(alpha)

# resultArray,定义alphaArray,我们需要用alphaArray和支持向量机数组进行相乘
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     # 一行一列的,所以第一个元素是[0, 0]
resultArray = -1*alphaArray*supportVArray       # 计算公式;resultArray 计算,支持向量的个数,只需要当成参数就行

# mydect参数,构建detect
myDetect = np.zeros(3781, np.float32)
for i in range(0, 3780):
	# 是一个一维的,myDetect
	myDetect[i] = resultArray[0,i]
myDetect[3780] = rho[0]
# myHog的创建很重要
# 构建好Hog,用HOGDescriptor方法构建
myHog = cv2.HOGDescriptor()
# 返回的myHog,用setSVMDetector设置属性
myHog.setSVMDetector(myDetect)

# 待检测图片的加载
imageSrc = cv2.imread('test2.jpg', 1)
# 检测小狮子 (8,8)winds的滑动步长 1.05 缩放系数 (32,32)窗口大小
# 完成检测,返回的目标包含哪些信息,myHog有个方法detectMultiScale,和人脸识别比较类似,缩放。
# 它可以检测出图片中所有的目标,并将目标用vector保存各个目标的坐标、大小(用矩形表示),函数由分类器对象调用;1.05是缩放,(8, 8)windows的滑动步长,(32, 32)窗体大小
# myHog的创建很重要
objs = myHog.detectMultiScale(imageSrc, 0, (8, 8), (32, 32), 1.05, 2)
# 起始位置、宽和高 objs三维信息,获取目标的坐标,是三维的,所以我们需要定义一个三维的坐标,这些信息放在三维中的最后一维
x = int(objs[0][0][0])       # 坐标,w和h是宽高
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))
# 目标的展示
cv2.imshow('dst', imageSrc)
cv2.waitKey(0)


实验相关数据集点击此处下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值