基于SVM的猫咪图片识别器

基于SVM的猫咪图片识别器

一、实验介绍

1.1 实验内容

SVM(支持向量机)是一种常用的机器学习分类算法。本课程使用HOG+SVM算法和OpenCV实现一个图片分类器,通过自己训练分类器,达到可以判断任意图片是否是猫咪的效果。

1.2 实验知识点

  • HOG+SVM分类器的基本原理
  • OpenCV处理图片
  • 训练分类器,以得到适合自己项目的分类器
  • Python文件操作

1.3 实验环境

  • python2.7
  • Xfce终端

1.4 适合人群

本课程难度为中等,适合掌握Python基础的用户,建立对SVM分类器的基础知识。

1.5 代码获取

你可以通过下面命令将代码下载到实验楼环境中,作为参照对比进行学习。

$ wget http://labfile.oss.aliyuncs.com/courses/794/train.py
$ wget http://labfile.oss.aliyuncs.com/courses/794/predict.py

二、实验原理

SVM(支持向量机)分类器的原理是利用“分类超平面”来实现数据分类。在利用“分类超平面”对数据进行划分时,遵循“间距最大”原则。例如,将二维平面内的两组数据分类,可以确定很多个“分类超平面”,在二维维度下,超平面退化为一条直线:

此处输入图片的描述

上图中使用绿线将蓝色圆圈和红色方块进行分类,可以有多种方式。那么根据SVM原理,哪一条线是最佳分类线呢?答案是,最佳分类线因该是距离蓝色圆圈和红色方框的距离都是最大的那一条,即找到两组数据的最大间距,在最大间距中点画一条线,如下:

此处输入图片的描述

如果分类3维数据,我们就使用一个平面来分割数据。如果分类4维数据,我们将会使用一个体来分割数据。以此类推,如果分类1024维数据,我们将使用1023维平面来分割数据。1023维的平面是什么样子?天知道。所以这个时候,将1023维度的平面命名为“分类超平面”。

SVM是一个由分类超平面定义的判别分类器。也就是说给定一组带标签的训练样本,算法将会输出一个最优超平面对新样本(测试样本)进行分类。

这也是监督类型机器学习的特点,即,把一堆带有标签的数据输入到机器中,让机器根据给定的数据计算出规则,再利用这个规则,去对未知数据进行分类。说白了,就是先积累几年工作经验,然后去工作。

本实验是读入输入图片的灰度图,即黑白的。然后计算该图片的hog值,将计算得到的结果作为向量来代表该图片。对由很多张图片组成的向量集进行计算,找到最大间距的分类超平面,进而分类数据。

hog的全称是Histogram of Oriented Gradient, HOG,即方向梯度直方图。它是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。它通过计算和统计图像局部区域的梯度方向直方图来构成特征。Hog特征结合SVM分类器已经被广泛应用于图像识别中,尤其在行人检测中获得了极大的成功。HOG+SVM进行行人检测的方法是法国研究人员Dalal在2005的CVPR上提出的,今天的很多行人检测算法基本都是以HOG+SVM的思路。

  • 主要思想:在一副图像中,局部目标的表象和形状(appearance and shape)能够被梯度或边缘的方向密度分布很好地描述。(本质:梯度的统计信息,而梯度主要存在于边缘的地方)。
  • 具体的实现方法是:首先将图像分成小的连通区域,我们把它叫细胞单元。然后采集细胞单元中各像素点的梯度的或边缘的方向直方图。最后把这些直方图组合起来就可以构成特征描述器。
  • 提高性能:把这些局部直方图在图像的更大的范围内(我们把它叫区间或block)进行对比度归一化(contrast-normalized),所采用的方法是:先计算各直方图在这个区间(block)中的密度,然后根据这个密度对区间中的各个细胞单元做归一化。通过这个归一化后,能对光照变化和阴影获得更好的效果。
  • 优点:与其他的特征描述方法相比,HOG有很多优点。首先,由于HOG是在图像的局部方格单元上操作,所以它对图像几何的和光学的形变都能保持很好的不变性,这两种形变只会出现在更大的空间领域上。其次,在粗的空域抽样、精细的方向抽样以及较强的局部光学归一化等条件下,只要行人大体上能够保持直立的姿势,可以容许行人有一些细微的肢体动作,这些细微的动作可以被忽略而不影响检测效果。因此HOG特征是特别适合于做图像中的人体检测的。

三、开发准备

打开Xfce终端,下载并安装 OpenCV的相关依赖。

$ sudo pip install numpy
$ sudo apt-get install python-opencv

遇到是否安装的询问时,输入y,按回车键继续安装。安装时间较长,并且视网络状态而定。

下载实验所需的图片数据:

$ wget http://labfile.oss.aliyuncs.com/courses/794/cat.zip
$ wget http://labfile.oss.aliyuncs.com/courses/794/other.zip
$ wget http://labfile.oss.aliyuncs.com/courses/794/predict.zip

这三组数据分别是含有猫的图片,没有猫的图片,以及用于测试SVM分类器的数据集。

下载后,解压得到图片:

$ unzip cat.zip
$ unzip other.zip
$ unzip predict.zip

这些图片都是从网上下载的。如果想使用自己下载的图片,也没有问题。需要注意爹是,输入到分类器的图片都是固定像素的。我们需要对下载的图片数据进行处理,使其符合我们程序的要求。将大图片裁减成固定像素的小图片的程序如下:

# -*- coding: utf-8 -*-
import numpy as np
import cv2
from os.path import dirname, join, basename
from glob import glob

num=0
for fn in glob(join(dirname(__file__)+'\other', '*.jpg')):
    img = cv2.imread(fn)
    res=cv2.resize(img,(64,128),interpolation=cv2.INTER_AREA)
    cv2.imwrite(r'D:\ECLIPSE-PROJECT\Python\my_opencv\other_64_128\test'+str(num)+'.jpg',res)
    num=num+1

print 'all done!'  

cv2.waitKey(0)
cv2.destroyAllWindows()

使用程序时,请替换输出路径为一个已存在的路径,即替换这一句中的路径:

cv2.imwrite(r'D:\ECLIPSE-PROJECT\Python\my_opencv\other_64_128\test'+str(num)+'.jpg',res)

这段代码会扫描Python脚本所在的文件夹的子文件夹other文件夹下的所有.jpg文件,然后使用OpenCV读取图片数据,并按照指定的大小进行缩放,将缩放后的结果写入到指定目录下的指定图片中。

四、实验步骤

4.1 训练数据集

首先,我们根据已经分类好的数据集来对分类器进行训练。我们的cat文件夹下全是猫的照片,而other文件夹下全不是猫,已经完成了贴标签这个过程了。让程序从这两组数据里学习,计算分类的方法。

使用HOG+SVM算法进行训练前,需要先计算每张图片的HOG值以得到供SVM分类器使用的输入向量。计算该值的算法实现的一般过程为:

  • 灰度化(OpenCV处理图像时,一般都处理为灰度图像,忽略颜色干扰)
  • 采用Gamma校正法对输入图像进行颜色空间的标准化(归一化);目的是调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰;
  • 计算图像每个像素的梯度(包括大小和方向);主要是为了捕获轮廓信息,同时进一步弱化光照的干扰。
  • 将图像划分成小cells(例如6*6像素/cell);
  • 统计每个cell的梯度直方图(不同梯度的个数),即可形成每个cell的descriptor;
  • 将每几个cell组成一个block(例如3*3个cell/block),一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征descriptor。
  • 将图像image内的所有block的HOG特征descriptor串联起来就可以得到该image(你要检测的目标)的HOG特征descriptor了。这个就是最终的可供分类使用的特征向量了。

在本实验中,没有严格按照上述的过程实现,我们采用了下述方法:我们在每个cell内计算XY方向的Sobel导数。然后找到每个像素的梯度和方向。此梯度被量化为16*16个整数值。把每个图像分成四个子图方块。对于每个子正方形,计算加权其幅度的方向(16*16bins)的直方图。因此,每个子图给我们一个包含16*16个值的向量。四个这样的向量(分别代表四个子图的16*16向量)一起给我们一个特征向量包含1024个值。这就是我们用来训练数据的特征向量。这部分的代码如下所示:

bin_n = 16*16 # Number of bins

def hog(img):
    x_pixel,y_pixel=194,259
    gx = cv2.Sobel(img, cv2.CV_32F, 1, 0)
    gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
    mag, ang = cv2.cartToPolar(gx, gy)
    bins = np.int32(bin_n*ang/(2*np.pi))    # quantizing binvalues in (0...16)
    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:]
    hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
    hist = np.hstack(hists)     # hist is a 64 bit vector
#    print hist.shape
#    print type(hist)
    return hist

完整的代码如下所示,程序首先扫描catother文件夹内的图片,然后用灰度方式读入,计算每个图片的hog值,然后建立SVM分类器,使用输入的数据进行训练,将训练结果保存于svm_cat_data.dat文件中。

#file name:train.py
import numpy as np
import cv2
#from matplotlib import pyplot as plt
from os.path import dirname, join, basename
import sys
from glob import glob


bin_n = 16*16 # Number of bins

def hog(img):
    x_pixel,y_pixel=194,259
    gx = cv2.Sobel(img, cv2.CV_32F, 1, 0)
    gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
    mag, ang = cv2.cartToPolar(gx, gy)
    bins = np.int32(bin_n*ang/(2*np.pi))    # quantizing binvalues in (0...16)
    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:]
    hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
    hist = np.hstack(hists)     # hist is a 64 bit vector
#    print hist.shape
#    print type(hist)
    return hist

#print glob(join(dirname(__file__)+'/cat','*.jpg'))
img={}
num=0
for fn in glob(join(dirname(__file__)+'/cat', '*.jpg')):
    img[num] = cv2.imread(fn,0)#参数加0,只读取黑白数据,去掉0,就是彩色读取。
#    print img[num].shape
    num=num+1
print num,' num'
positive=num
for fn in glob(join(dirname(__file__)+'/other', '*.jpg')):
    img[num] = cv2.imread(fn,0)#参数加0,只读取黑白数据,去掉0,就是彩色读取。
#    print img[num].shape
    num=num+1
print num,' num'
print positive,' positive'

trainpic=[]
for i in img:
#    print type(i)
    trainpic.append(img[i])

svm_params = dict( kernel_type = cv2.SVM_LINEAR,
                    svm_type = cv2.SVM_C_SVC,
                    C=2.67, gamma=5.383 )
#img = cv2.imread('02.jpg',0)
#hist_full = cv2.calcHist([img],[0],None,[256],[0,256])
#print hist_full
#plt.plot(hist_full)
#plt.show()

#img1 = cv2.imread('02.jpg',0)
#temp=img[0].ravel()
#print temp
#print len(temp)
temp=hog(img[0])
print temp.shape

#hogdata = [map(hog,img[i]) for i in img]
hogdata = map(hog,trainpic)
print np.float32(hogdata).shape,' hogdata'
trainData = np.float32(hogdata).reshape(-1,bin_n*4)
print trainData.shape,' trainData'
responses = np.float32(np.repeat(1.0,trainData.shape[0])[:,np.newaxis])
responses[positive:trainData.shape[0]]=-1.0
print responses.shape,' responses'
print len(trainData)
print len(responses)
print type(trainData)

svm = cv2.SVM()
svm.train(trainData,responses, params=svm_params)
svm.save('svm_cat_data.dat')

注意,如果想要运行此程序并得到正确的结果,需要在控制台输入:

$ python /home/shiyanlou/train.py

如果只输入:

$ python train.py

也能看到输出,只不过执行到一半会报错。

这其中的原因,主要是程序中使用了glob包来枚举文件夹下的某个类型的文件。

正常运行后,可以见到文件夹下生成的数据:

此处输入图片的描述

同时也会看到,当导入OpenCV包的时候,程序报错libdc1394 error: Failed to initiallize libdc1394,这个错误,是因为没有加载摄像头驱动。实验楼使用的云服务器,很可能没有摄像头,所以报错。但这个错误并不影响我们的实验,所以忽略即可。在自己的笔记本上或者台式机上,只要正确安装了驱动,不会有这个错误。

4.2 使用训练好的SVM分类器进行分类

机器学习是一个不断迭代的过程。训练的数据集越大越好,训练时间当然也是越长效果越好。当机器认错了图片的时候,我们要把这个图片拿出来,标记正确,输入机器再训练一遍,如此迭代下去。本实验只训练了一次以演示原理。

我们得到了训练好的数据svm_cat_data.dat后,可以用它来分类测试图片。

建立程序如下:

#file name:predict.py
import numpy as np
import cv2
#from matplotlib import pyplot as plt
from os.path import dirname, join, basename
import sys
from glob import glob

#my_svm=cv2.SVM()
#my_svm
#bin_n = 16 # Number of bins
bin_n = 16*16 # Number of bins

def hog(img):
    x_pixel,y_pixel=194,259
    gx = cv2.Sobel(img, cv2.CV_32F, 1, 0)
    gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
    mag, ang = cv2.cartToPolar(gx, gy)
    bins = np.int32(bin_n*ang/(2*np.pi))    # quantizing binvalues in (0...16)
    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:]
    hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
    hist = np.hstack(hists)     # hist is a 64 bit vector
#    print hist.shape
#    print type(hist)
    return hist

#print glob(join(dirname(__file__)+'/cat','*.jpg'))
img={}
num=0
for fn in glob(join(dirname(__file__)+'/cat', '*.jpg')):
    img[num] = cv2.imread(fn,0)#参数加0,只读取黑白数据,去掉0,就是彩色读取。
#    print img[num].shape
    num=num+1
print num,' num'
positive=num
for fn in glob(join(dirname(__file__)+'/other', '*.jpg')):
    img[num] = cv2.imread(fn,0)#参数加0,只读取黑白数据,去掉0,就是彩色读取。
#    print img[num].shape
    num=num+1
print num,' num'
print positive,' positive'

trainpic=[]
for i in img:
#    print type(i)
    trainpic.append(img[i])

svm_params = dict( kernel_type = cv2.SVM_LINEAR,
                    svm_type = cv2.SVM_C_SVC,
                    C=2.67, gamma=5.383 )

temp=hog(img[0])
print temp.shape

#hogdata = [map(hog,img[i]) for i in img]
hogdata = map(hog,trainpic)
print np.float32(hogdata).shape,' hogdata'
trainData = np.float32(hogdata).reshape(-1,bin_n*4)
print trainData.shape,' trainData'
responses = np.float32(np.repeat(1.0,trainData.shape[0])[:,np.newaxis])
responses[positive:trainData.shape[0]]=-1.0
#print responses[40:80]
print responses.shape,' responses'
print len(trainData)
print len(responses)
print type(trainData)

svm = cv2.SVM()
svm.load('svm_cat_data.dat')

img = cv2.imread('/home/shiyanlou/predict/01.jpg',0)
#print img.shapes,' img_test0'
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!'

test_temp=[]
for fn in glob(join(dirname(__file__)+'/predict', '*.jpg')):
    img=cv2.imread(fn,0)#参数加0,只读取黑白数据,去掉0,就是彩色读取。
    test_temp.append(img)
print len(test_temp),' len(test_temp)'

hogdata = map(hog,test_temp)
testData = np.float32(hogdata).reshape(-1,bin_n*4)
print testData.shape,' testData'
result = [svm.predict(eachone) for eachone in testData]
print result

运行该程序,同样,需要提供完整的路径:

$ python /home/shiyanlou/predict.py

程序输出结果如下:

此处输入图片的描述

注意SVM分类器认为1是猫,而-1不是猫。我们提供的测试数据集里,没有一张图片是猫,而分类器认为第3张和第11张是猫,其余不是猫。这明显是误判了。一次训练的结果肯定达不到100%分类正确,所以才需要迭代重复训练。把分类器认错的图片,再丢进other文件夹下,再训练一次,下次再遇到,就认识了。

五、实验总结

使用SVM机器学习算法和OpenCV实现了一个判断一张图片是否是猫的分类器。通过本课程的学习,学员应理解SVM分类器的原理,可以建立自己的图片分类器,训练分类器达到合适的分类精度。

六、课后习题

在本实验中,分类器误判了两张图片,请重复训练让分类器正确分类它们;增加图片数量,训练一个更加精确的分类器;使用HOG+SVM进行行人检测。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 计算机视觉猫狗识别SVM,是一种基于支持向量机算法的猫狗图像分类器。这种分类器使用大量的有标签的猫狗图像数据来进行训练,并从中学习出一组狗和猫的特征,然后将这些特征用来对新输入的图像进行分类SVM是一种常用的机器学习算法,通过将多维数据映射到支持向量面上,进行非线性分类、回归、降维等任务。在猫狗识别中,SVM算法可以对图像特征进行降维、分类,用来判断输入的图像是猫还是狗。 在使用SVM算法进行猫狗识别之前,首先需要将图像数据转换成数字矩阵,提取出图像的特征作为训练的数据。这些特征可以是颜色、纹理、形状等。提取出图像的特征后,使用SVM算法对特征进行分类,将猫和狗进行区分。 在实际运用中,需要利用大量的有标签数据对SVM模型进行训练,并对训练结果进行评估和调整。随着机器学习和计算机视觉技术的不断发展,计算机视觉猫狗识别SVM算法也可以进行不断的升级和优化,以提高准确率和效率。 ### 回答2: 计算机视觉猫狗识别的SVM(Support Vector Machine)是一种基于机器学习算法的分类器,常用于图像分类和目标检测。在猫狗识别任务中,SVM可以通过学习猫狗图像数据集中特征点的差异,建立一个分类模型,将未知的图像分为猫或狗的类别。 SVM的实现步骤包括特征提取、数据集划分、模型训练和测试。首先需要从图像数据集中提取出有代表性的特征,如HOG(Histogram of Oriented Gradients)或SIFT(Scale-Invariant Feature Transform),用于构建数据集。然后将数据集按一定比例划分为训练集和测试集,并进行标签化。接着,在训练阶段,使用SVM算法从训练集中学习猫和狗之间的区别,并通过调优模型参数来提高模型效果。最后,在测试阶段,使用SVM模型对测试集中的图像进行分类预测,并评估模型的分类性能。 要构建一个高准确率的SVM猫狗识别系统,需要充足的图像数据集和良好的特征提取方法。同时,需要对SVM的参数设置和调优有足够的理解和掌握,以确保模型的训练效果和分析结果可靠性。除此之外,还需要考虑模型的实时性和复杂度,以满足实际应用场景需求。 ### 回答3: 计算机视觉猫狗识别是一种基于机器学习算法的图像识别技术,通过图像处理和特征提取等技术,将输入的猫或狗图像进行分类。而支持向量机(SVM)是一种常用的分类器,它利用所谓的核函数将训练数据映射到高维空间,通过分类面划分不同的类别,并预测新数据的分类。 在猫狗识别中,SVM主要通过学习训练数据集的特征和是否为猫或狗进行训练,然后利用训练好的分类器对新的输入数据进行分类。具体而言,基于SVM的猫狗识别流程包括以下几个步骤: 1. 数据集准备:需要收集大量的猫和狗的图像数据,同时进行数据清洗和预处理,包括图像增强、白平衡、去噪等。 2. 特征提取:可以使用深度学习算法如卷积神经网络(CNN)来自动提取图像的特征,或者手动设计特征。例如,我们可以通过颜色直方图、纹理、形状和边缘等特征来描述猫和狗的不同属性。 3. 分类器训练:利用SVM算法对已提取的特征进行训练,得到分类器模型。在训练过程中,我们需要选择核函数类型和参数,并进行交叉验证等操作来优化模型的性能。 4. 数据分类:将新的输入数据输入到已训练好的分类器中,进行分类识别,判断是猫还是狗。 总之,利用支持向量机算法进行计算机视觉猫狗识别技术,可以通过对大量数据和特征的学习和分类,实现准确的猫狗图像识别。未来,该技术还将在人工智能、自动驾驶、医学图像分类等领域得到广泛应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值