近期尝试使用MATLAB实现对图像的bag of words分类。在此记录一些心得体会,望与小伙伴们交流。
一. filterResponses
将图片放入不同的filterBank中,输出结果
输入:
W×H×3的图像
N个filterBank
输出:
W×H × N×3 的矩阵
这一步比较简单,使用convn即可得到
此外,我是先把每个filter后的结果保存到一个cell里面,最后用vertcat(垂直合并矩阵)把结果变成一个W×H
×N×3
的矩阵。
二. Dictionary
这一步是构建字典。
把一堆图片的每个像素通过N个filter后的结果(每个像素的60个outputs作为一个元素),通过Kmeans生成字典。
因为图片太多,使用rand随机抽取像素点。
输出的dictionary大小为: K(自行定义的分成多少类)
×N×3
btw:这一步耗时比较长,如果电脑有多核,使用parfor快很多!
我使用了20个filter,分成了K=300类,建立成的字典大小为300×60。(最后我的randam像素点选取了200个,k分成了305类,这个需要在不断测试中获得比较好的数字选取。)
三. Visual Words
有了dictionary后,下一步是把所有的图片的每个像素变成字典“文字”。
简单来说就是把每个图片过filter得到的整个filterResponse(每一行代表一个像素的结果,即每一行都有60列,共有W×H行)的每一行跟dictionary比较,该像素跟dictionary最相似的那一行就是那个像素的visual word。用dictionary行数(ID)代替visual Word编码,把每张图片表示成W×H的wordMap矩阵,并且保存成.mat。
这里使用到了pdist2函数。
D = pdist2(X,Y,distance)
矩阵中一行代表一个元素,D(i,j)表示X的i行与Y的j行的距离
用 imagesc(wordMap) 可以可视化图片的visual Word表示。
这里一开始比较纠结的是怎么可视化呢?怎样知道每个visual word代表的像素RGB呢?如果你也开始纠结这个问题,说明——恭喜你,你也被我带跑了!其实,并不需要考虑每个visual Word代表的像素RGB,只用把同一个visual Word用一种RGB表示就可以了,所以直接用每个Word的ID代替就OK了,展现出来的是。
四. Image Features
如何获得每张图片的特征呢?这里可以使用直方图。
上一步得到的每一个图片的wordMap后,可对每张图片每个单词出现的次数进行统计,统计出来的直方图便是图片的特征。
直方图十分好计算,输入:W×H的wordMap矩阵,输出:K×1的矩阵。记得要归一化。
★然而,对于整张图的直方图计算,没有空间信息。因此使用金字塔空间匹配SPM。简单来说就是把image分割成n×n的cell,再对每个cell计算直方图,再把每个cell的直方图拼接在一起,变成了K([4^(LayerNum)-1]/3)
×1
的矩阵。
拼接的时候,level0和level1取1/2^(-L)
倍,其余取1/2^(l-L-1)
倍。
这里使用mat2cell可以直接分割wordMap。要注意的是,有时候图片的大小不一定是被2或4整除的,因此可以前面向下取整,最后一块是所有剩下的即可。
当LayerNum=3,即L=2时,得到的结果大小为6300×1。(最后我用了LayerNum=4)
五. Recognize System
有的教程在这里先写distance的代码,但是我发现,没有做recognize之前,我实在搞不清楚distance的输入和输出是怎么一回事。因此我先写了recognize system。
recognize system是要得到一个vision.mat里面包含:
filterBank
dictionary
train_features
train_labels
其中filterBank、dictionary、train_labels是从前面得到的数据以及已有的数据可以直接load的,需要做的其实只有train_features。
train_features是什么呢?它其实是T张用来训练的图片每个通过一系列的计算得到的SPM直方图的集合矩阵,大小为K([4^(LayerNum)-1]/3)
×T
,每一列代表一张图片。
看起来很简单的样子,只是从已有的wordMap.mat中导入wordMap的时候要使用wordMap.wordMap。然后每个wordMap用前面的直方图计算函数一计算,全部拼接(horzcat矩阵水平拼接),完成!
六. Distance
这时候就可以回过头来看distance了。distance是在测试的时候,通过这个函数判断测试的图片跟train_features的每一列的差距。
使用直方图相交相似即可。也就是sum(min(h,train_features))(当然这只是意会,代码具体不是这样的,我使用了bsxfun运算)。
七. 测试
选定一些测试图片输入测试,预测的分类与图片标签进行对比。我的精确度大约能做到58%-64%。
还在摸索如何提升精确度,也希望小伙伴们提提意见。