摘要
图片分类问题是计算机视觉中比较常见的问题。图片分类在日常的生活中,以及图片搜索中等方面都有很多很实际的用途。如何准确快速有效的进行图片分类,提高图片分类的准确率和召回率是现在主要要解决的问题。因此一个好的分类学习的算法以及一个好的特征提取的方式是非常重要的。本文所采取的学习算法是朴素贝叶斯算法。这种算法的结构简单,同时对于简单的文字或是图片处理效果非常的好。特征提取的方式是提取图片的颜色直方图。也是具有简单易操作的特点。
关键词:图片分类,学习,贝叶斯, 特征提取
Abstract
Image classification is more popular and common in computer vision . Image classification, in everyday life, as well as in image searching, has a lot of practical application. How to perform accurate image classification quickly and effectively, and how to improve image classification precision and recall rate are now the main problem to be solved. Thus, a good learning classification algorithm and a good feature extraction is very important. Learning algorithm is adopted here is Naive Bayes algorithm. This algorithm has a simple structure, but the effect for simple text or image processing is very good. Feature extraction approach is to extract the image color histogram. Also has a advantage of simple and easy .
Keywords:Image classification, learning, Bayesian, feature extraction
1. 引言
机器学习算法在计算机视觉,语音识别,数据挖掘以及很多其他的人工智能领域有非常重要的意义。机器学习算法的研究和发展极大的推动了这些领域的发展。因此机器学习算法的研究具有非常重要的意义。机器学习的算法主要分为产生式和判别式模型。通俗的来讲,产生式模型就是要学习到一个联合概率分布。而判别式模型则不需要学习随机变量的概率分布。所以文章中用到的贝叶斯模型是一个产生式模型。最终是要求得一个随机变量的联合概率分布。
在图片文类或是文本分类当中,我们要从已知的数据集当中得到计算机能够理解的数据。这也就是提取特征的过程了。下面主要是针对图像特征的提取。图像特征的提取有很多种方式。比如说,HOG特征,颜色特征,haar特征,SIFT特征等等。HOG特征是对图片的梯度直方图进行统计;颜色特征则是对图片的RGB颜色进行记录,具有简单直观的特点;harr特征这是定义不同的矩形块里面的灰度差异来表征图片的特征,通过积分图像来计算的话,计算的速度还是非常不错的;SIFT特征具有很多的不变性,能够很好的表示出图片的特征,最终得到的是一个108维的特征向量,是通过DOG(高斯积分图像)得到的,最大的缺点就是计算的速度比较慢。对于我们这次的图片分类的任务来讲,本身就具有两种图片,且二者二者的区分度很大。所以我们的重点是了解如何用我们所学到的机器学习的算法来实践具体的项目。所以我们在这里选择计算简单且效果不错的颜色特征。
所以本文采取的是贝叶斯模型通过颜色特征对图像来进行分类。首先通过所有的数据集构造一个字典,然后将所有的图片用这个字典映射为一个向量通过两种图片训练出一个图片分类器。
文章接下来的安排是这样的:在第二部分,我们将介绍整体的框架和步骤。贝叶斯的基本原理将在第三部分介绍。然后我们将在第四部分介绍特征的提取部分。有了基本的理论知识以后,我们将在第五部分介绍实验的相关部分。随后是整篇文章的总结和相关的参考文献。
2. 总体流程
总体流程图:
具体到各个步骤:
1、收集数据集,最好是使用python爬虫实现;
2、提取颜色特征:为了简化过程,训练的过程中选择相同数量的正负样本,使得先验概率相等。然后,从每一个样本图片上面提取出25*25的patch块。对于每一个patch块计算它的颜色直方图,得到的是一个6+6+6的向量。它相当于是一个高维空间上的一个点;
3、聚类:对于所有的这些patch块聚类为1000个中心;形成图片空间的词包。
4、训练贝叶斯分类器:选择5分之4的正负样本集,获取其在词包字典上的映射向量,统计在每一个中心上的patch块的个数,得到一个整体的样本分布的似然概率向量组。
5、测试分类:将训练好的贝叶斯模型应用到余下来的1/5的图片的分类;
6、根据分类的结果和实际的标签得到分类的分类的准确率和召回率。
3. 贝叶斯原理简介
3.1贝叶斯模型
朴素贝叶斯模型是基于贝叶斯原理与特征条件独立假设的分类方法。对于给定的训练集,首先基于条件独立假设学习输入输出的联合概率分布,然后基于此模式对于给定的x,利用贝叶斯模型求出最大后验概率最大的那个类型并输出。
在在这里讲朴素贝叶斯模型应用于图片分类。首先由构造的词包模型的字典计算出训练样本中出现的词语的频率。由此作为词语的先验概率。在进行训练的时候,通过这些先验概率以及训练样本集中词语出现的频率计算出在每一种图片的分类当中的最大后验概率。得到其中概率最大的那种类型作为训练集的输出类型。
3.2 贝叶斯图片分类的伪代码:
Input:已提取过特征的图片集(正负样本都有),以及他们的标签
Output:正负样本各个字典分量上面的概率,以及先验概率。
计算输入的训练样本图片的总数numTrainPicture,以及正负样本的数目
计算出正负样本的先验概率
对于图片中的正样本:
计算各个词出现的概率
计算出现的词的总个数
计算出各个词的释然概率
对于图片中的负样本:
计算各个词出现的概率
计算出现的词的总个数
计算出各个词的释然概率
返回 各个词的释然概率,正负样本先验概率
4. 图片的特征提取方法
图片特征的提取过程需要从已经下载好的文档集合中逐个读取文件,然后切出patch块,得到图片的特征。因为我们所有的图片的尺寸都是一样的,所以使得具体的操作也非常的简单,如下:
1,将收集到的正负样本,分别放在两个文件夹当中,逐个取出其中的每一张照片;
2,对读出来的每一张照片,因为数据集当中照片的尺寸为800*600,而一般照片的主题都在照片的中心位置。所以选择图片中心400*400的位置提取出其中的2000个左右的25*25的patch块(每隔8个像素提取一次);
3,对其中的每一个patch块统计它的颜色直方图:分别统计RGB上面的颜色直方图,得到的一个向量(分别在RGB上面分6个区域进行统计),将得到这个18维的向量。所以每一张图片就可以用一个1000*216的数组表示。(我目前还不能想象216维的向量是咋呢么提取得,所以我的特征向量就只有18维,是直接将他们拼接起来的。)
所以完成特征提取的过程需要三个函数,一个是读出文件中的图片;一个是获得patch块,另一个是统计patch块的颜色特征。
下面说一下对于整个数据集提取特征并进行聚类的过程
1,读入文件夹,每一次读入一张照片,;
2,对于每一张照片,调用提取特征的函数。得到的是一个900patch*18维的向量。队友所有的图片进行这样的操作,得到的应该是一个270000*18的向量;
3,对于这270000个特征向量进行聚类,得到1000个聚类中心。形成一个词典模型。
到上面这一步字典模型就建立好了。但是要将以后的训练图片和测试图片用这个表示。所以还有一步映射的过程。
4,对于输入的每一张图片,密集采样,得到一大堆的patch块,将每一个patch快转化为一个18维的向量(相当于一个字典里面的字)。然后在字典里面找到相应的字。统计整个图片在这个字典中出现的词以及出现的词的次数;
上面得到的一个1000维的向量就是这个图片对应的特征了。
5. 实验
选择照片中的4/5进行训练,接下来的1/5用来测试。对于每一张照片的每一个patch块,找到和他最近的那个词。如此将每一张照片用字典来表示。
训练的时候:
为了方便选择的正负样本的数目相等,也就是说他们的先验概率相等。同时知道他们的标签。输入所有的正样本,利用字典,得到他们的字典特征向量。利用贝叶斯模型,得到一个释然概率向量。(这是一个1000维的概率向量,对它取自然对数)
负样本也进行这样的操作。
测试的时候:
对于输入的每一张图片,得到它的字典向量(1000维),然后分别和他的正负概率向量相乘,得到的值比较大小。判断出他的类别。
5.1 数据集与性能评估标准
所使用的样本数据集如下所示:
图一、飞机负样本
图二、花正样本
5.2 实验结果与分析
在这篇论文中有几个明显没有按照要求来做的地方。第一,所取得向量不是216维而是18维;第二,训练字典的时候所采用的patch块基本上来至于中心图附近;第三在负样本集中存在不一样大小的图片。
当存在上述的问题以后,我发现我得到的结果为:准确率91.6%,召回率73.33%。基本上可以达到要求了。若是我再除去那个不符合规范的图片,我们可以得到更好的结果。于是我知道我的几个基本的假设是成立的:1、如果一张图片相似,那么它在R或是G或是B上面的颜色直方图也应该基本相同(这里我们假设都是6个bin 的直方图)。那么在R和G和B上的直方图也应该相似。因此,我直接将这三个通道的上的直方图直接拼接成一个18维的向量,也应该是相似的;2、图片内容中表达信息的位置一般来讲应该是图片的中心位置的。所以在远离中心的位置的大多数信息都是冗余的。
正是在这两个基本的假设上面我开始了我的实验。这样做的原因是明显提高了计算的速度。同时也解决了那种内存不足的缺点。得到的结果是基本可以满足要求的。因此,我选择了这种实验的方式。
7.总结
机器学习的算法的研究和发展使得计算机视觉领域有了长足的进步。作为计算机视觉领域中一个重要的风向:图片分类有非常重要的使用,同时也应用到图片搜索的相关领域。采用贝叶斯模型来进行图片分类的相关的工作,具有简单易操作,有效的效果。本文使用贝叶斯模型,通过提取图片的颜色直方图获得图片的特征向量。然后再训练出一个基于贝叶斯的分类器,实现了图片的分类,取得了较好的效果。让我掌握了计算机视觉项目开发的基本框架模型。而在实际问题的解决中也得到了很好的心得这次小项目的实践有很重要的价值。
参考文献
[1] 统计学习方法,李航,清华大学出版社,2013
[2] 机器学习实战,Peter Harington,人民邮电出版社,2012
附录(附上关键代码)
#!/usr/bin/env python
# encoding: utf-8
import cv2
import numpy as np
import os
def imgtohistvetor(img):
dx=8
dy=8
im=cv2.imread(img)#'' need or not?
b,g,r=cv2.split(im)
mask = np.zeros(im.shape[:2], np.uint8)
histvetor=[]
for i in range(30):
for j in range(30):
mask[300+j*dx:325+j*dx, 200+i*dy:225+i*dy] = 255
hist_maskb = cv2.calcHist([b],[0],mask,[6],[0,256])
hist_maskg = cv2.calcHist([g],[0],mask,[6],[0,256])
hist_maskr = cv2.calcHist([r],[0],mask,[6],[0,256])
histvetor.append(list(hist_maskb)+list(hist_maskg)+list(hist_maskr))
return histvetor
def createdic(possample,negsample):
dic0=[]
dic1=[]
for f in os.listdir(possample):
fl=os.path.join(possample,f)
vector1=imgtohistvetor(fl)
dic1=dic1+vector1
np.savetxt('posdata.txt',dic1)
for f in os.listdir(negsample):
fl=os.path.join(negsample,f)
vector0=imgtohistvetor(fl)
dic0=dic0+vector0
np.savetxt('negdata.txt',dic0)
#dic=np.array(dic)
#dicvector=kmeans(dic,1000)[0]
dic=dic0+dic1
np.savetxt('dicdata.txt',dic)
def imgtodicvector(datafilename,dicfile):
f=np.loadtxt(datafilename)
dic=np.loadtxt(dicfile)
nlen=len(dic)
imgdicvector=np.ones((nlen))
dicvector=[]
for i in range(120):
for j in range(900):
inputmat=np.tile(f[900*i+j],(nlen,1))
distance=(inputmat-dic)**2
dissum=np.sum(distance,axis=1)
index=np.argsort(dissum)
imgdicvector[index[0]]=imgdicvector[index[0]]+1
for j in range(30):
imgdicvectort=np.zeros((nlen))
for i in range(900):
inputmat=np.tile(f[900*120+j*900+i],(nlen,1))
distance=(inputmat-dic)**2
dissum=np.sum(distance,axis=1)
index=np.argsort(dissum)
imgdicvectort[index[0]]=imgdicvectort[index[0]]+1
dicvector.append(list(imgdicvectort))
numall=np.sum(imgdicvector)
p=np.log(imgdicvector/numall)
dicvector=np.array(dicvector)
return p,dicvector
def bayesdicision():
p1,postestvector=imgtodicvector('posdata.txt','dic.txt')
p0,negtestvector=imgtodicvector('negdata.txt','dic.txt')
p11=np.tile(p1,(30,1))*postestvector
p10=np.tile(p0,(30,1))*postestvector
p00=np.tile(p0,(30,1))*negtestvector
p01=np.tile(p1,(30,1))*negtestvector
p11=np.sum(p11,axis=1)
p10=np.sum(p10,axis=1)
p00=np.sum(p00,axis=1)
p01=np.sum(p01,axis=1)
Tp=0.0
Fp=0.0
Tn=0.0
Fn=0.0
for i in range(30):
if p11[i]>p10[i]:
Tp=Tp+1
else:
Fn=Fn+1
if p00[i]>p01[i]:
Tn=Tn+1
else:
Fp=Fp+1
print Tp/(Tp+Fp),Tp/(Tp+Fn)
if __name__=='__main__':
#dicdata=np.loadtxt('dicdata.txt')
#dicdata=np.float32(dicdata)
#criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
#ret,label,center=cv2.kmeans(dicdata,1000,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
#np.savetxt('dic.txt',center)
#np.savetxt('postestvector.txt',postestvector)
#print postestvector
bayesdicision()
print 'ok'