SVM、Hog特征

一.SVM(支持向量机)
1.定义:
SVM本质是一个分类器,仍然是解决分类的问题,通过寻求一个最优的超平面,来完成分类。分类可以用直线进行分类,也可以用曲线,下面案例用的是直线进行分类,即svm的核是line。
2.案例:
对人的身高体重的训练样本进行分类,从而判断是男生还是女生,且随意给出一个人的身高体重做出预测是男生还是女生。

import cv2
import numpy as np

#1.准备数据
rand1 = np.array([[155,48],[159,50],[164,53],[168,56],[172,60]]) #女生样本
rand2 = np.array([[152,53],[156,55],[160,56],[172,64],[176,65]]) #男生样本

#2.标签label
label = np.array([[0],[0],[0],[0],[0],[1],[1],[1],[1],[1]])

#3.数据
data = np.vstack((rand1,rand2)) #将数据1和2合并
data = np.array(data,dtype='float32')

#SVM所有的数据都要有label,即监督学习 0负样本 1正样本
#[155,48]——0,女生  [152,53]——1,男生
#4.SVM属性的设置
svm = cv2.ml.SVM_create() #创建SVM ml机器学习模块

#SVM属性设置
svm.setType(cv2.ml.SVM_C_SVC) #设置SVM的类型
svm.setKernel(cv2.ml.SVM_LINEAR) #设置线性分类器
svm.setC(0.01) #SVM内核

#5.开始训练
result = svm.train(data,cv2.ml.ROW_SAMPLE,label) #将svm设为简单模式

#6.预测
pt_data = np.vstack([[167,55],[162,57]]) #预测为0女生 1男生
pt_data = np.array(pt_data,dtype='float32')
print(pt_data) #打印初始样本
(par1,par2) = svm.predict(pt_data)
print(par2) #打印预测的值

输出:
[[167. 55.]
[162. 57.]]
[[0.] [1.]]
3.SVM的使用步骤
①准备样本的数据,需要正样本和负样本两种数据,数量多少无所谓;
②给每个样本的数据都要加上标签,即正负一,这就是监督学习:0负样本 1正样本;
③开始训练数据:
a.首先我们需要创建一个SVM:cv2.ml.SVM_create()
b.其次设置SVM的类型:setType(cv2.ml.SVM_C_SVC)
c.选择哪种类型的分类器:setKernel()
d.设置SVM内核的大小setC()
e.对数据进行预测

二.Hog特征
1.Hog特征定义
特征是指某个像素经过某种运算得到的结果,Haar特征是通过模板运算得到的结果,而Hog特征是通过模板运算之后还需要进一步计算得到的,所以比Haar特征更复杂。
2.工作流程
①模块划分
②计算每个模块的梯度和方向
③bin的投影
④计算整体的Hog特征
⑤特征的判决
3.专有名词解释、概念理解
在这里插入图片描述
步骤一:①模块划分
1.image(上面整张图片) windows窗体(蓝色矩形框)
block(红色矩形框)
cell(绿色矩形框)
尺寸大小:image > windows窗体 > block >cell
2.windows窗体是特征计算的最顶层单元,即包括了目标的所有特征(比如你要检验汽车,那windows窗体就是整张汽车的图片)windows窗体尺寸大小是任意的,官方推荐:64×128
3.block尺寸大小也是任意的,但windows窗体尺寸大小是block尺寸大小的整数倍,官方推荐:16×16
4.block移动时有步长setp,setp表示block在windows窗体中的滑动,尺寸为 8×8,表示block滑动的距离是水平方向和竖直方向上各8个单位
计算block的个数:block count = ((64-16)/8+1)×((128-16)/8+1)= 105 个block
5.cell的大小,推荐:8×8,block = 4 个cell((16×16)/(8×8)),给这四个cell命名为cell1,cell2,cell3,cell4
6.cell中对应的有bin,bin指的是梯度的运算
每个像素都有一个梯度的大小,称之为f(幅值),即方向(angle角度)
把0-360度每40度分成一块,即360/40 =9,分成了9个bin,如下图所示
在这里插入图片描述
7.Hog特征维度:Haar特征中计算出来的是值,而Hog计算出来的是向量(向量都是有维度的),完全描述一个目标的所有信息。
维度 = 105×4×9=3780 (每个windows窗口下block的个数为105,每个block下cell的个数为4,每个cell下bin的个数为9)

步骤二:②计算每个模块的梯度和方向
每个像素都有一个梯度,同时Hog特征中这里用了特征模板,这点和Haar类似,不过Hog特征的模块类型较少。
水平方向的特征模板:[ 1 0 -1 ] 竖直方向的特征模板:[ [ 1 ] [ 0 ] [ -1 ] ]
水平方向上的像素 a = p1×1+p2×0+p3×(-1) = 相邻像素之差
竖直方向上的像素 b = p1×1+p2×0+p3×(-1) = 上下像素之差
于是梯度大小的幅值f = 根号下(a平方+b平方)
angle = arctan(a/b)

步骤三:③bin的投影:梯度的投影
bin 是将360度分为9部分,即每个bin是0—40度,而这40度并不是连续的,假设0—20度是bin1的范围,且180—200度也是bin1的范围,即对称的关系。比如某个像素点的幅值a=10,则属于bin1,a=190也属于bin1。
若某个幅值刚好在两个bin之间,若为25,则属于bin1和bin2,简单理解有个计算公式:f1 = f × f夹角
f2 = f × (1-f夹角)(PS:f夹角的范围是0-1.0,浮点数)

步骤四:④计算整体的Hog特征:cell复用
整体是3780维度,计算每个维度中某个windows窗口下的某个block下的某个cell下的某个bin的Hog特征

步骤五:⑤特征的判决
计算出3780维度的所有Hog特征
这里举svm的line训练为例,用Hog×svm若大于设定的阈值T,则判定为目标。

4.案例
步骤:
1.准备样本数据(正负样本已上传)
2.开始训练
3.对训练的结果进行预测
1.1 pos:正样本,包含所检测目标 neg:负样本,不包含检测目标 要统一图像尺寸,正负样本的比例为1:2或者1:3,样本尽可能多样

import cv2
import numpy as np

"""1.准备样本数据"""
PosNum = 820   #正样本数量820
NegNum = 1931  #负样本数量1931
windowsSize = (64,128) #设置windows窗体的大小
blockSize = (16,16) #windows = 105个 block
blockStep = (8,8) #block移动的步长
cellSize = (8,8) #cell的大小
nBin = 9 #每个cell中bin的个数

"""2.Hog的创建"""
hog = cv2.HOGDescriptor(windowsSize,blockSize,blockStep,cellSize,nBin)

"""3.创建SVM"""
svm = cv2.ml.SVM_create()

"""4.计算Hog特征"""
featureNum = int(((128-16)/8+1)*((64-16)/8+1)*4*9) #维度数3780
featureArray = np.zeros(((PosNum+NegNum),featureNum),np.float32)
#featureArray表示所有样本的Hog信息,是一个二维的数据
labelArray = np.zeros(((PosNum+NegNum),1),np.int32) #标签数
#这里之所以要设置featureArray和labelArray,是因为svm是监督学习,需要样本和标签
#而svm学习的样本,是我们原数据的Hog特征,而不是直接的样本,所以需要featureArray
for i in range(0,PosNum): #遍历每个正样本获取Hog特征
    filename = 'E:\\pictures\\pos\\' + str(i+1) + '.jpg'
    img = cv2.imread(filename)
    hist = hog.compute(img,(8,8)) #用hist装载正样本的hog特征,是3780维度的
    for j in range(0,featureNum): #将获取到的正样本hog特征装载到featureArray二维中
        featureArray[i,j] = hist[j]
        #理解:featureArray是(820+1931)*3780,hist是1*3780
        #即把每一个hist装载到featureArray的前820列
    labelArray[i,0] = 1 #正样本label 1
for i in range(0,NegNum): #遍历每个负样本获取Hog特征
    filename = 'E:\\pictures\\neg\\' + str(i + 1) + '.jpg'
    img = cv2.imread(filename)
    hist = hog.compute(img, (8, 8))  # 用hist装载正样本的hog特征,是3780维度的
    for j in range(0, featureNum):  # 将获取到的正样本hog特征装载到featureArray二维中
        featureArray[i+PosNum,j] = hist[j]
        # 理解:featureArray是(820+1931)*3780,hist是1*3780
        # 即把每一个hist装载到featureArray的前820列
    labelArray[i+PosNum, 0] = -1  # 负样本label -1

"""5.设置svm属性"""
svm.setType(cv2.ml.SVM_C_SVC)
svm.setKernel(cv2.ml.SVM_LINEAR)
svm.setC(0.01)

"""6.训练样本"""
result = svm.train(featureArray,cv2.ml.ROW_SAMPLE,labelArray)
#虽然看上去result后面没有调用,但只有SVM训练了(svm.train)后面才能用

"""7.检测"""
alpha = np.zeros((1),np.float32)
rho = svm.getDecisionFunction(0,alpha)
#rho表示svm得到Hog的一个描述信息,rho来源于svm,svm来源于svm.train
print(rho)
print(alpha)
alphaArray = np.zeros((1,1),np.float32)
support_SVMVector_Array = np.zeros((1,featureNum),np.float32)
resultArray = np.zeros((1,featureNum),np.float32)
alphaArray[0,0] = alpha
resultArray = -1*alphaArray*support_SVMVector_Array

"""8.预测"""
#创建myDetect
myDetect = np.zeros((3781),np.float32)
for i in range(0,3780):
    myDetect[i] = resultArray[0,i]
myDetect[3780] = rho[0]
#构建Hog
myHog = cv2.HOGDescriptor()
myHog.setSVMDetector(myDetect)
imageSrc = cv2.imread("E:\\pictures\\Test2.jpg",1) #下载待检测图片
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)
cv2.imshow('dst',imageSrc)
cv2.waitKey(0)

输出:
(0.2555259838518084,
array([[1.]]), array([[0]], dtype=int32))
[0.]
在这里插入图片描述

发布了25 篇原创文章 · 获赞 0 · 访问量 440

猜你喜欢

转载自blog.csdn.net/qq_45445740/article/details/104497343