赞
踩
SVM(支持向量机)是一种常用的机器学习分类算法。使用HOG+SVM算法和OpenCV实现一个图片分类器,通过训练分类器,达到可以判断任意图片是否是动物的效果;本节实验是利用hog来计算图像数据的特征描述,从而获得基于图片的特征向量,再利用SVM分类超平面来实现数据分类,并能够利用训练好的模型进行图像预测。
实验时长:90分钟
主要步骤:
数据准备
编写图片识别代码
编写模型训练代码
编写模型预测代码
运行程序,查看结果
6.1数据准备
6.1.1本次实验使用系统自带的python2.7的环境
6.1.2进入虚拟环境,打开命令行终端;切换到root用户,密码是zkpk;然后在Linux终端安装OpenCV
[zkpk@master ~]$ su
[root@master zkpk]# yum install -y opencv-python
[root@master zkpk]# exit # 回退到普通用户
6.1.3解压**./experiment/MLcase**包下的数据文件
[zkpk@master ~]$ cd experiment/MLcase
[zkpk@master MLcase]$ unzip cat.zip
[zkpk@master MLcase]$ unzip other.zip
[zkpk@master MLcase]$ unzip predict.zip
[zkpk@master MLcase]$ ls
6.1.3.1数据介绍:cat包全是猫的图片,other包中不包括猫的其它图片,以及predict包用于测试SVM分类器的数据集
6.1.3.2这些图片都是测试图片,如果想使用自己上传的图片也可以,但是需要设置成固定像素64*128大小的图片
6.2编写代码解析训练数据集并训练模型
6.2.1我们使用HOG+SVM算法进行训练,需要先计算每张图片的HOG值;HOG值再作为SVM分类器的输入向量。计算该值的一般过程如下:
6.2.1.1灰度化(OpenCV处理图像时,一般会将图像处理为灰度图像,忽略颜色干扰);
6.2.1.2采用Gamma校正法对输入图像进行颜色空间的标准化(归一化);目的是调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪声的干扰;
6.2.1.3计算图像每个像素的梯度(包括大小和方向);主要是为了捕获轮廓信息,同时进一步弱化光照的干扰;
6.2.1.4将图像划分成小cells(例如6*6像素/cell);
6.2.1.5统计每个cell的梯度直方图(不同梯度的个数),即可形成每个cell的descriptor;
6.2.1.6将每几个cell组成一个block(例如3*3个cell/block),一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征descriptor;
6.2.1.7将图像image内的所有block的HOG特征descriptor串联起来就可以得到该image(要检测的目标)的HOG特征descriptor。此结果就是最终可供分类算法使用的特征向量。
6.2.2在/home/zkpk目录下创建脚本文件Animal.py (本实验随后的代码都写入此文件中);以下使用vim文本编辑器编辑文件,若不熟悉vim的使用,也可以使用gedit代替
[zkpk@master MLcase]$ cd
[zkpk@master ~]$ vim Animal.py
6.2.3在Animal.py文件中开始编写代码;首先导入numpy包、opencv包、os系统路径相关包、sys包和glob包
import numpy as np
import cv2
from os.path import dirname, join, basename
import sys
from glob import glob
6.2.4设置梯度值为16*16
bin_n = 16*16
6.2.5定义hog方法,该方法读取图片,计算图片的特征向量(HOG值);
接下来涉及大量opencv的编程,若有需要,可访问opencv官网docs.opencv.org查看相应版本的文档,本实验使用OpenCV-Python 2.4.5版本
6.2.5.1定义x轴和y轴的像素值
def hog(img):
x_pixel,y_pixel=194,259
6.2.5.2分别计算x轴和y轴方向上的Sobel导数
gx = cv2.Sobel(img, cv2.CV_32F, 1, 0) # 边沿检测;img作为输入图片;第二个参数指定输出图片的深度;第三个参数dx、第四个参数dy表示这个方向的求导的阶数;0表示这个方向没有求导,一般为0、1、2
gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
6.2.5.3将直角坐标转换为极坐标,获取每个像素的梯度和方向
mag, ang = cv2.cartToPolar(gx, gy) # cart表示cartesian笛卡尔;polar极地的;第一个参数gx为x轴坐标组成的数组;第二个参数gy是y轴坐标组成的数组;magnitue极径,返回值mag是一个array,其中保存着一系列极径,mag的size与shape与参数gx的相同;angle极角,返回值ang是一个array,其中保存着一系列极角,它的size与shape也与参数gx的相同
6.2.5.4将梯度量化成16*16个整数值
bins = np.int32(bin_n*ang/(2*np.pi))
6.2.5.5将图像分成4个子图块
bin_cells = bins[:x_pixel/2,:y_pixel/2], bins[x_pixel/2:,:y_pixel/2], bins[:x_pixel/2,y_pixel/2:], bins[x_pixel/2:,y_pixel/2:]
mag_cells = mag[:x_pixel/2,:y_pixel/2], mag[x_pixel/2:,:y_pixel/2], mag[:x_pixel/2,y_pixel/2:], mag[x_pixel/2:,y_pixel/2:]
6.2.5.6对于每个子图块,计算它的bin的个数,4个子模块共返回16*16*4个bin的向量值
hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)] # 使用了python的列表解析语法;bincount计算输入数组中每个值出现的次数,有三个参数x, weights, minlength,第一个参数表示输入的一维数组,第二个表示weights权重,与x的shape一样,第三个表示输出数组中元素的最小个数。关于方法,若有疑问可查阅docs.scipy.org中的文档
6.2.5.7将每个模块返回的向量值利用numpy进行水平堆叠(按列),然后返回该值
hist = np.hstack(hists)
return hist
6.2.6定义字典img用于存储图片,定义num表示字典的key
img={}
num=0
6.2.7循环读取实验文件中的cat文件夹下的所有jpg文件,利用imread方法参数设置为0,读取图片黑白数据,也称作灰度化
# dirname函数获得路径;join函数将多个路径连接起来;glob函数返回由路径组成的list
for fn in glob(join(dirname('/home/zkpk/experiment/MLcase/cat/'), '*.jpg')):
img[num] = cv2.imread(fn,0) # imread函数用于读取图片文件,第二个参数flag若为0,表示返回3-channel颜色的图片
num=num+1
6.2.8读取cat文件夹下的图片后,我们打印下num看看有多少个文件,并将其赋值给positive
print num,' num'
positive=num
6.2.9同样,循环读取实验文件中的other文件夹下的所有jpg文件,利用imread方法参数设置为0,读取图片黑白数据
for fn in glob(join(dirname('/home/zkpk/experiment/MLcase/other/'), '*.jpg')):
img[num] = cv2.imread(fn,0)
num=num+1
6.2.10我们再次打印出num的值和positive的值
print num,' num'
print positive,' positive'
6.2.11遍历字典中的值,按顺序添加到列表trainpic中
trainpic=[]
for i in img:
trainpic.append(img[i])
6.2.12设置SVM模型的参数
6.2.12.1kernel_type:SVM的内核类型
6.2.12.2svm_type:指定SVM的类型
6.2.12.3C是惩罚系数,即对误差的宽容度。c越高,说明越不能容忍出现误差,容易过拟合。C越小,容易欠拟合。C过大或过小,泛化能力变差
6.2.12.4gamma是选择RBF函数作为kernel后,该函数自带的一个参数。隐含地决定了数据映射到新的特征空间后的分布,gamma越大,支持向量越少,gamma值越小,支持向量越多。支持向量的个数影响训练与预测的速度
svm_params = dict( kernel_type = cv2.SVM_LINEAR, svm_type = cv2.SVM_C_SVC, C=2.67, gamma=5.383 )
6.2.13调用hog方法,将trainpic中的图片都分别计算其特征向量,打印输出看下hogdata的结构
hogdata = map(hog,trainpic)
print np.float32(hogdata).shape,' hogdata'
6.2.14将所有图片的特征向量赋值给trainData,打印输出
trainData = np.float32(hogdata).reshape(-1,bin_n*4)
print trainData.shape,' trainData'
6.2.15利用numpy的repeat方法生成一列值全为1.0的数据,个数为trainData的行数,也就是89;再将从positive下标到89下标的数据置为-1.0;因为从上面输出的num和positive我们知道,是猫的图片是positive个;最后这一个新创建的列将作为标签值进行模型训练,我们先打印输出responses的结构看下
responses = np.float32(np.repeat(1.0,trainData.shape[0])[:,np.newaxis]) # np.newaxis相当于None
responses[positive:trainData.shape[0]]=-1.0
print responses.shape,' responses'
6.2.16调用cv2的SVM方法,创建支持向量机模型,再利用该模型对上面得到的训练数据、标签值和模型参数进行模型训练
svm = cv2.SVM()
svm.train(trainData,responses, params=svm_params)
6.2.17模型训练完成之后,我们就可以读取一张测试文件夹下的图片进行测试;例如读取predict文件夹下01.jpg,通过hog方法计算出其特征向量,打印输出,然后利用svm模型的predict方法对该特征向量进行预测,得到它的结果(标签值);我们还可以自定义一些自己的判断和输出等
img = cv2.imread('/home/zkpk/experiment/MLcase/predict/01.jpg',0)
hogdata = hog(img)
testData = np.float32(hogdata).reshape(-1,bin_n*4)
print testData.shape,' testData'
result = svm.predict(testData)
print result
if result > 0:
print 'this pic is a cat!'
6.2.18这次我们对predict下的所有文件进行分类预测;首先我们定义一个列表testpic;然后循环读取predict文件夹下的所有图片文件(灰度化);并添加到列表testpic中;打印输出testpic的长度
testpic=[]
for fn in glob(join(dirname('/home/zkpk/experiment/MLcase/predict/'), '*.jpg')):
img=cv2.imread(fn,0)
testpic.append(img)
print len(testpic),' len(tespic)'
6.2.19再利用map方法将testpic中的所有图片数据,调用hog方法,计算出每张图片的特征向量值,格式化后作为测试数据testData,打印输出查看testData的结构
hogdata = map(hog,testpic) # 其中hog为之前定义的函数
testData = np.float32(hogdata).reshape(-1,bin_n*4)
print testData.shape,' testData'
6.2.20利用for循环从testData中读取每张图片的特征向量值,利用svm的predict方法做分类预测,并将结果保存到result列表中,打印结果列表
result = [svm.predict(eachone) for eachone in testData]
print result
6.2.21至此,基于SVM的动物图片识别代码编写完毕
6.2.22编辑完成后,利用Esc键回到命令行模式,再输入shift+:,输入wq保存文件并退出vim编辑器
6.3运行程序
[zkpk@master ~]$ python2.7 Animal.py
6.3.1注意文件路径
6.3.2查看终端输出结果
6.3.2.1从代码中不难发现我们定义SVM分类器中1是猫,而-1不是猫,并且我们提供的predict测试数据集里,没有一张图片是猫,而分类器认为第3张和第11张是猫,其余不是猫。这明显是误判了。一次训练的结果肯定达不到完全分类正确,所以才需要迭代重复训练,让机器再次学习。把分类器认错的图片,丢进other文件夹下,再训练一次,下一次遇到该图片就能够识别了
在本节实验中我们使用SVM机器学习算法和OpenCV实现了一个判断一张图片是否是猫的分类器,并通过该分类器对测试集图片进行了图像预测。通过本实验的学习,我们应当充分理解了hog方向梯度直方图处理图片特征、SVM分类器的原理等,并可以达到可自己建立的图片分类器,训练分类器达到合适的分类精度的效果。
全分类正确,所以才需要迭代重复训练,让机器再次学习。把分类器认错的图片,丢进other文件夹下,再训练一次,下一次遇到该图片就能够识别了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。