视觉词袋模型BOW学习笔记及matlab编程实现

sift和surf特征提取代码

转载 http://blog.csdn.net/dulingtingzi/article/details/51223732

首先插入两个非常好的介绍BOW的ppt:

1.https://wenku.baidu.com/view/6370f28d26fff705cc170aab.html

2.https://wenku.baidu.com/view/7782de2fc281e53a5902ff03.html

BoW 模型简介

Bag of words模型最初被用在文本分类中,将文档表示成特征矢量。它的基本思想是假定对于一个文本,忽略其词序和语法、句法,仅仅将其看做是一些词汇的集合,而文本中的每个词汇都是独立的。简单说就是讲每篇文档都看成一个袋子(因为里面装的都是词汇,所以称为词袋,Bag of words即因此而来),然后看这个袋子里装的都是些什么词汇,将其分类。如果文档中猪、马、牛、羊、山谷、土地、拖拉机这样的词汇多些,而银行、大厦、汽车、公园这样的词汇少些,我们就倾向于判断它是一篇描绘乡村的文档,而不是描述城镇的。举个例子,有如下两个文档:

文档一:Bob likes to play basketball, Jim likes too.

文档二:Bob also likes to play football games.

基于这两个文本文档,构造一个词典:

Dictionary = {1:”Bob”, 2. “like”, 3. “to”, 4. “play”, 5. “basketball”, 6. “also”, 7. “football”,8. “games”, 9. “Jim”, 10. “too”}。

这个词典一共包含10个不同的单词,利用词典的索引号,上面两个文档每一个都可以用一个10维向量表示(用整数数字0~n(n为正整数)表示某个单词在文档中出现的次数):

1:

2:

向量中每个元素表示词典中相关元素在文档中出现的次数(下文中,将用单词的直方图表示)。不过,在构造文档向量的过程中可以看到,我们并没有表达单词在原来句子中出现的次序(这是本Bag-of-words模型的缺点之一,不过瑕不掩瑜甚至在此处无关紧要)。

为什么要用BOW模型描述图像

SIFT特征虽然也能描述一幅图像,但是每个SIFT矢量都是128维的,而且一幅图像通常都包含成百上千个SIFT矢量,在进行相似度计算时,这个计算量是非常大的,通行的做法是用聚类算法对这些矢量数据进行聚类,然后用聚类中的一个簇代表BOW中的一个视觉词,将同一幅图像的SIFT矢量映射到视觉词序列生成码本,这样每一幅图像只用一个码本矢量来描述,这样计算相似度时效率就大大提高了。

构建BOW码本步骤

  1. 假设训练集有M幅图像,对训练图象集进行预处理。包括图像增强,分割,图像统一格式,统一规格等等。
  2. 提取SIFT特征。对每一幅图像提取SIFT特征(每一幅图像提取多少个SIFT特征不定)。每一个SIFT特征用一个128维的描述子矢量表示,假设M幅图像共提取出N个SIFT特征。
  3. 用K-means对2中提取的N个SIFT特征进行聚类,K-Means算法是一种基于样本间相似性度量的间接聚类方法,此算法以K为参数,把N个对象分为K个簇,以使簇内具有较高的相似度,而簇间相似度较低。聚类中心有k个(在BOW模型中聚类中心我们称它们为视觉词),码本的长度也就为k,计算每一幅图像的每一个SIFT特征到这k个视觉词的距离,并将其映射到距离最近的视觉词中(即将该视觉词的对应词频+1)。完成这一步后,每一幅图像就变成了一个与视觉词序列相对应的词频矢量。
  4. 构造码本。码本矢量归一化因为每一幅图像的SIFT特征个数不定,所以需要归一化。也就是说,将每张图片的特征个数变为频数,这样就可以防止因为提取特征数不同而造成的分类不准问题了。如上述例子,归一化后为
    ,1/12*
    .测试图像也需经过预处理,提取SIFT特征,将这些特征映射到为码本矢量,码本矢量归一化,最后计算其与训练码本的距离,对应最近距离的训练图像认为与测试图像匹配。 > 设视觉词序列为{眼睛 鼻子 嘴}(k=3),则训练集中的图像变为: > > 第一幅图像:
    > > 第二幅图像:
    ……

当然,在提取sift特征的时候,可以将图像打成很多小的patch,然后对每个patch提取SIFT特征。

总结一下,整个过程其实就做了三件事,首先提取对 n 幅图像分别提取SIFT特征,然后对提取的整个SIFT特征进行k-means聚类得到 k 个聚类中心作为视觉单词表,最后对每幅图像以单词表为规范对该幅图像的每一个SIFT特征点计算它与单词表中每个单词的距离,最近的+1,便可得到该幅图像的码本。实际上第三步是一个统计的过程,所以BOW中向量元素都是非负的。Yunchao Gong 2012年NIPS上有一篇用二进制编码用于图像快速检索的文章就是针对这类元素是非负的特征而设计的编码方案。

看完了这些理论以后,相信已经对BOW模型

在这个连接上有BOW的MATLAB实现代码及图片数据库:

https://github.com/lipiji/PG_BOW_DEMO,

这是这个连接的作者关于BOW的博客说明

http://www.zhizhihu.com/html/y2011/3536.html 已不能用。

http://www.weibo.com/pagecn微博地址
代码在windows环境下执行出错 ,因为路径的问题,吧ini.m中几行代码改一下:

rootpath='F:\论文下载\最近论文\bovw例子\PG_BOW_DEMO-master';  此处是windows下demo存放的路径
images_set=strcat(rootpath,'\images');
data=strcat(rootpath,'\data');
labels=strcat(rootpath,'\labels');
此处三行代码 第二个参数都加反斜杠。否则提示42行文件找不到。下面代码即为42行。 
pg_opts.classes = load([pg_opts.labelspath,'/classes.mat']);

视觉词袋模型BOW学习笔记及matlab编程实现_第1张图片

原来结果

新结果:

视觉词袋模型BOW学习笔记及matlab编程实现_第2张图片

2018.6.15日实验。


下面是我看这个代码所有的一点收获:

结合代码讲一下bag of visual word 的模型建立过程:

1、利用sift等特征提取算法从每张图片中提取特征点也就是视觉单词。在代码中,每张图片是200*200大小,然后步长是8,将图片分成16*16的小patch,这样就有576个小patch,在每个小patch上都进行sift提取关键点,每个小patch上有一个关键点,这样就有576个关键点,也就是每张图片最终变成了576个128维的向量(sift特征点是128维的),也就是576*128这样大小的一个矩阵。图片包括训练样本和测试样本一共有360张图片,所以数据一共就是360*576*128.    

2、利用K-means进行聚类,构建词汇表vocabulary。在代码中是找了300个聚类中心,也就是300*128,聚类中心个数的选取从几百到上千不等,一般数据越大,聚类中心越多。聚类的数据是训练数据240*576*128和测试数据120*576*128,最大迭代次数100,聚类完成后得到300个聚类中心,每个是1*128维的向量。

3、利用得到的聚类中心得到词汇表以后,对360张图片进行直方图统计,也就是看每张图片中的576个关键点与哪个聚类中心的距离最小(最相似),然后再最近的那个聚类中心所代表的1-300之间的数上加1,这样最终得到了BOW的数据300*360大小的矩阵,这里面300*240是训练数据,300*120是测试数据。注意由于这里每张图片的关键点的数目都是一样的,所以归一化的影响并不是特别的关键,但是如果每张图片上关键点的数目不是一样的,那就必须进行归一化,也就是将词数变成词频,就是除以总点数。

以上是基本的BOW建立的过程,作者的程序中有一个pyramid BOW的程序CompilePyramid,这里面是spatial pyramid程序。BOW与pyramid BOW在统计每张图的词频时是一样的 ,关键是对这些词频的处理不一样,BOW是全局进行统计词频,而pyramid BOW如名字所示,是分层次的,在代码中,是首先将图片分成4*4小块,对每小块进行300个聚类中心的词频统计,并用2^-1进行加权,然后在将图片分成2*2小块进行300个聚类中心的词频统计,并用2^-2进行加权,最后再对整个图片全局的直方图进行直方图统计,并用2^-2进行加权,最后将这些直方图连在一起,这样最终的数据是6300*360这样的数据去进行训练。也就是说,源程序里面是有两种词袋的数据结果,BOW和pyramid BOW,然后作者用BOW+径向基核函数的SVM进行分类,精度是77.5%,pyramid+径向基核函数的SVM进行分类,精度是82.5%;作者有自己定义了一种和函数,称之为inter吧,BOW+inter核函数的分类精度是81.6667%,pyramid BOW+inter核函数的分类精度是最高的,为90.8333%。


附录:

聚类、K-Means、例子、细节


聚类#####

今天说聚类,但是必须要先理解聚类和分类的区别,很多业务人员在日常分析时候不是很严谨,混为一谈,其实二者有本质的区别。

分类其实是从特定的数据中挖掘模式,作出判断的过程。比如Gmail邮箱里有垃圾邮件分类器,一开始的时候可能什么都不过滤,在日常使用过程中,我人工对于每一封邮件点选“垃圾”或“不是垃圾”,过一段时间,Gmail就体现出一定的智能,能够自动过滤掉一些垃圾邮件了。这是因为在点选的过程中,其实是给每一条邮件打了一个“标签”,这个标签只有两个值,要么是“垃圾”,要么“不是垃圾”,Gmail就会不断研究哪些特点的邮件是垃圾,哪些特点的不是垃圾,形成一些判别的模式,这样当一封信的邮件到来,就可以自动把邮件分到“垃圾”和“不是垃圾”这两个我们人工设定的分类的其中一个。

** 聚类**的的目的也是把数据分类,但是事先我是不知道如何去分的,完全是算法自己来判断各条数据之间的相似性,相似的就放在一起。在聚类的结论出来之前,我完全不知道每一类有什么特点,一定要根据聚类的结果通过人的经验来分析,看看聚成的这一类大概有什么特点。

K-Means#####

聚类算法有很多种(几十种),K-Means是聚类算法中的最常用的一种,算法最大的特点是简单,好理解,运算速度快,但是只能应用于连续型的数据,并且一定要在聚类前需要手工指定要分成几类。

下面,我们描述一下K-means算法的过程,为了尽量不用数学符号,所以描述的不是很严谨,大概就是这个意思,“物以类聚、人以群分”:

  1. 首先输入k的值,即我们希望将数据集经过聚类得到k个分组。
  2. 从数据集中随机选择k个数据点作为初始大哥(质心,Centroid)
  3. 对集合中每一个小弟,计算与每一个大哥的距离(距离的含义后面会讲),离哪个大哥距离近,就跟定哪个大哥。
  4. 这时每一个大哥手下都聚集了一票小弟,这时候召开人民代表大会,每一群选出新的大哥(其实是通过算法选出新的质心)。
  5. 如果新大哥和老大哥之间的距离小于某一个设置的阈值(表示重新计算的质心的位置变化不大,趋于稳定,或者说收敛),可以认为我们进行的聚类已经达到期望的结果,算法终止。
  6. 如果新大哥和老大哥距离变化很大,需要迭代3~5步骤。
简单的手算例子#####

我搞了6个点,从图上看应该分成两推儿,前三个点一堆儿,后三个点是另一堆儿。现在手工执行K-Means,体会一下过程,同时看看结果是不是和预期一致。

视觉词袋模型BOW学习笔记及matlab编程实现_第3张图片
case

1.选择初始大哥:
我们就选P1和P2

2.计算小弟和大哥的距离:
P3到P1的距离从图上也能看出来(勾股定理),是√10 = 3.16;P3到P2的距离√((3-1)2+(1-2)2 = √5 = 2.24,所以P3离P2更近,P3就跟P2混。同理,P4、P5、P6也这么算,如下:

视觉词袋模型BOW学习笔记及matlab编程实现_第4张图片
round1

P3到P6都跟P2更近,所以第一次站队的结果是:

  • 组A:P1
  • 组B:P2、P3、P4、P5、P6

3.人民代表大会:
组A没啥可选的,大哥还是P1自己
组B有五个人,需要选新大哥,这里要注意选大哥的方法是每个人X坐标的平均值和Y坐标的平均值组成的新的点,为新大哥,也就是说这个大哥是“虚拟的”。
因此,B组选出新大哥的坐标为:P哥((1+3+8+9+10)/5,(2+1+8+10+7)/5)=(6.2,5.6)。
综合两组,新大哥为P1(0,0),P哥(6.2,5.6),而P2-P6重新成为小弟

4.再次计算小弟到大哥的距离:

视觉词袋模型BOW学习笔记及matlab编程实现_第5张图片
round2

这时可以看到P2、P3离P1更近,P4、P5、P6离P哥更近,所以第二次站队的结果是:

  • 组A:P1、P2、P3
  • 组B:P4、P5、P6(虚拟大哥这时候消失)

5.第二届人民代表大会:
按照上一届大会的方法选出两个新的虚拟大哥:P哥1(1.33,1) P哥2(9,8.33),P1-P6都成为小弟

6.第三次计算小弟到大哥的距离:

视觉词袋模型BOW学习笔记及matlab编程实现_第6张图片
round3

这时可以看到P1、P2、P3离P哥1更近,P4、P5、P6离P哥2更近,所以第二次站队的结果是:

  • 组A:P1、P2、P3
  • 组B:P4、P5、P6

我们发现,这次站队的结果和上次没有任何变化了,说明已经收敛,聚类结束,聚类结果和我们最开始设想的结果完全一致。

K-Means的细节问题#####
  1. K值怎么定?我怎么知道应该几类?
    答:这个真的没有确定的做法,分几类主要取决于个人的经验与感觉,通常的做法是多尝试几个K值,看分成几类的结果更好解释,更符合分析目的等。或者可以把各种K值算出的SSE做比较,取最小的SSE的K值。

  2. 初始的K个质心怎么选?
    答:最常用的方法是随机选,初始质心的选取对最终聚类结果有影响,因此算法一定要多执行几次,哪个结果更reasonable,就用哪个结果。 当然也有一些优化的方法,第一种是选择彼此距离最远的点,具体来说就是先选第一个点,然后选离第一个点最远的当第二个点,然后选第三个点,第三个点到第一、第二两点的距离之和最小,以此类推。第二种是先根据其他聚类算法(如层次聚类)得到聚类结果,从结果中每个分类选一个点。

  3. K-Means会不会陷入一直选质心的过程,永远停不下来?
    答:不会,有数学证明K-Means一定会收敛,大致思路是利用SSE的概念(也就是误差平方和),即每个点到自身所归属质心的距离的平方和,这个平方和是一个函数,然后能够证明这个函数是可以最终收敛的函数。

  4. 判断每个点归属哪个质心的距离怎么算?
    答:这个问题必须不得不提一下数学了……
    第一种,欧几里德距离(欧几里德这位爷还是很厉害的,《几何原本》被称为古希腊数学的高峰,就是用5个公理推导出了整个平面几何的结论),这个距离就是平时我们理解的距离,如果是两个平面上的点,也就是(X1,Y1),和(X2,Y2),那这俩点距离是多少初中生都会,就是√( (x1-x2)2+(y1-y2)2) ,如果是三维空间中呢?√( (x1-x2)2+(y1-y2)2+(z1-z2)^2 ;推广到高维空间公式就以此类推。可以看出,欧几里德距离真的是数学加减乘除算出来的距离,因此这就是只能用于连续型变量的原因。
    第二种,余弦相似度,余弦相似度用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小。相比距离度量,余弦相似度更加注重两个向量在方向上的差异,而非距离或长度上。下图表示余弦相似度的余弦是哪个角的余弦,A,B是三维空间中的两个向量,这两个点与三维空间原点连线形成的角,如果角度越小,说明这两个向量在方向上越接近,在聚类时就归成一类:

    视觉词袋模型BOW学习笔记及matlab编程实现_第7张图片
    cosine

    看一个例子(也许不太恰当):歌手大赛,三个评委给三个歌手打分,第一个评委的打分(10,8,9) 第二个评委的打分(4,3,2),第三个评委的打分(8,9,10)
    如果采用余弦相似度来看每个评委的差异,虽然每个评委对同一个选手的评分不一样,但第一、第二两个评委对这四位歌手实力的排序是一样的,只是第二个评委对满分有更高的评判标准,说明第一、第二个评委对音乐的品味上是一致的。
    因此,用余弦相似度来看,第一、第二个评委为一类人,第三个评委为另外一类。
    如果采用欧氏距离, 第一和第三个评委的欧氏距离更近,就分成一类人了,但其实不太合理,因为他们对于四位选手的排名都是完全颠倒的。
    总之,如果注重数值本身的差异,就应该用欧氏距离,如果注重的是上例中的这种的差异(我概括不出来到底是一种什么差异……),就要用余弦相似度来计算。
    还有其他的一些计算距离的方法,但是都是欧氏距离和余弦相似度的衍生,简单罗列如下:明可夫斯基距离、切比雪夫距离、曼哈顿距离、马哈拉诺比斯距离、调整后的余弦相似度、Jaccard相似系数……

  5. 还有一个重要的问题是,大家的单位要一致!
    比如X的单位是米,Y也是米,那么距离算出来的单位还是米,是有意义的
    但是如果X是米,Y是吨,用距离公式计算就会出现“米的平方”加上“吨的平方”再开平方,最后算出的东西没有数学意义,这就有问题了。
    还有,即使X和Y单位一致,但是如果数据中X整体都比较小,比如都是1到10之间的数,Y很大,比如都是1000以上的数,那么,在计算距离的时候Y起到的作用就比X大很多,X对于距离的影响几乎可以忽略,这也有问题。
    因此,如果K-Means聚类中选择欧几里德距离计算距离,数据集又出现了上面所述的情况,就一定要进行数据的标准化(normalization),即将数据按比例缩放,使之落入一个小的特定区间。去除数据的单位限制,将其转化为无量纲的纯数值,便于不同单位或量级的指标能够进行计算和比较。
    标准化方法最常用的有两种:

  • min-max标准化(离差标准化):对原始数据进行线性变换,是结果落到【0,1】区间,转换方法为 X'=(X-min)/(max-min),其中max为样本数据最大值,min为样本数据最小值。
  • z-score标准化(标准差标准化):处理后的数据符合标准正态分布(均值为0,方差为1),转换公式:X减去均值,再除以标准差
  1. 每一轮迭代如何选出新的质心?
    答:各个维度的算术平均,比如(X1,Y1,Z1)、(X2,Y2,Z2)、(X3,Y3,Z3),那就新质心就是【(X1+X2+X3)/3,(Y1+Y2+Y3)/3,(Z1,Z2,Z3)/3】,这里要注意,新质心不一定是实际的一个数据点。

  2. 关于离群值?
    答:离群值就是远离整体的,非常异常、非常特殊的数据点,在聚类之前应该将这些“极大”“极小”之类的离群数据都去掉,否则会对于聚类的结果有影响。但是,离群值往往自身就很有分析的价值,可以把离群值单独作为一类来分析。

  3. 用SPSS作出的K-Means聚类结果,包含ANOVA(单因素方差分析),是什么意思?
    答:答简单说就是判断用于聚类的变量是否对于聚类结果有贡献,方差分析检验结果越显著的变量,说明对聚类结果越有影响。对于不显著的变量,可以考虑从模型中剔除。

五、聚类分析中业务专家的作用#####

业务专家的作用非常大,主要体现在聚类变量的选择和对于聚类结果的解读:

  1. 比如要对于现有的客户分群,那么就要根据最终分群的目的选择不同的变量来分群,这就需要业务专家经验支持。如果要优化客户服务的渠道,那么就应选择与渠道相关的数据;如果要推广一个新产品,那就应该选用用户目前的使用行为的数据来归类用户的兴趣。算法是无法做到这一点的
  2. 欠缺经验的分析人员和经验丰富的分析人员对于结果的解读会有很大差异。其实不光是聚类分析,所有的分析都不能仅仅依赖统计学家或者数据工程师。

你可能感兴趣的:(bow)