How do human sketch objects?

来源:互联网 发布:whatsapp是什么软件 编辑:程序博客网 时间:2024/05/17 07:53

文章的实现,OpenCV2.3.1,VS2010。

题目为“人类怎样画草图”,文章前面论述了一大堆关于人类对草图的识别,在这里略去,有兴趣可以自行阅读。

 

在5 Sketch Representation中开始介绍了如何为sketch构造出合适的histogram:主体的思路是利用梯度信息来构造特征向量,在这里只用到梯度的方向,而忽略梯度大小。

5.1 Extracting local features

我们下下来得dataset的图片分辨率过大,首先采用降采样为256*256。

第一步,求得图片的梯度(利用SCHARR算子),这样之后每一个像素点都有一个梯度方向在0~180度之间,然后我们根据梯度方向构造出四个response images,也就是四个bins(O1,O2,O3,O4,分别代表0-45,45-90,90-135,135-180度),然后根据每个像素点梯度的方向处在的区间放入不同的bin中(可以把response images当作二值图像,也就是一个像素点,只能在一个bin中相应像素点的值为1,而其他三个bins相应点为0,当然也出现了梯度的xy方向都为0,在这里我们不将该点放入bins中)。

第二步,将降采样后的图片确定28*28=784个采样点(每个采样点之间差8个像素,第一个点和左边缘相差16个像素,这样的话就舍弃了最后8个像素没有patch,当初没考虑好),以这784个采样点为中心构建784个patches,每个patch为32*32大小。

第三步,每个patch按空间分为4*4=16个bins,也就是每个bins是8*8的块。接下来就是extract 每个块中的每个response images(O)的局部描述子Li。对于每个response images,计算所属的8*8块内的累计值,也就是把第一步中的为1的点累加起来,然后把patch中的16个块的累计值合起来就形成了一个16维的局部描述子Li。然后对于每个response images计算描述子,然后将四个局部描述子合起来形成了该patch的向量d=[L1,L2,L3,L4],为64维向量,在这里也就是patch的特征,之后再对其进行归一化处理(这里一定要归一化,不然在下文的一个参数选取上会造成很大影响)。(文中提到了用能量累积的方法得到d,但是没有采用这个方法实现)

5.2 Building a visual vocabulary

第四步,如上步所做,一幅图就有784个特征向量,于是很多图的所有的特征向量就构成了所谓的bag-of-features,D={di}。在这里我们对选取了前1,000,000(由于考虑到概率问题,个人认为前100000个向量和随机选取1000000个向量在概率上是相等的,所以就没有采用文中所说的随机选取)个特征向量进行k-means聚类,取k=500,聚类完成之后得到了500个中心向量{ui},这里也可以认为是words。(关于bag-of-features或bag-of-words的问题可以看http://blog.csdn.net/tinyway/article/details/9240821)

5.3 Quantizing features

第五步,这一步中,我们就要构建出属于一个sketch的histogram。首先还是计算出784个d,之后将每个d与500个ui进行高斯核的计算距离K(d,u),形成了一个500维的距离向量q(d)=[K(d,u1),K(d,u2)....K(d,u500)],然后再将q(d)进行归一化(这里的归一化使用绝对值和来归一化,同第三步里d的归一化不同)。在计算完784个q(di)之后,将所有di累加起来,再除以784,就形成了sketch的histogram。



在这里,关于sketch的特征提取就差不多完成了,接下里就考虑分类问题。

问中还提到了很多分类问题,在这里就利用svm进行分类预测,下文讲的是自己的摸索过程,毕竟从没用过svm,大神绕道。

我暂时只取了25类进行分类训练,第一次是进行多分类训练,也就是只训练出一个模型,之后发现结果超级不行,再重看文章后发现文章不是这样实现的,在7.1中提到了,为每个sketch训练了250个分类器,用于将该sketch和其他类的sketch辨别出来,在预测的时候,通过比较每个分类器的classifier function来确定输入样本所属的类别。

同时,由于高斯核距离的计算中,选择了不同的sigma,有不同的效果,当sigma小的时候,sketch的histogram有很多维为0,但是当sigma取大的时候,预测的结果很差,所以还是取小的sigma。

svm的训练方法:

1.直接训练出多分类器:

该方法很直接,但是准确率也不是很高。

2.训练25个二分类器(样本有25类):

同文中7.1所说的方法进行预测,结果同样很不准。每个类取了60个正样本,而其他24个类取了60*24个负样本,这样子训练之后发现classifier function完全一样,看来是正负样本的比例失常导致,故重新训练,正样本取60个,每个类取2个负样本,一共48个负样本,结果也不怎么好,因为有一个分类器的classifier function总是特别大,于是很容易选到那个类别去。(后来改成10类)

3.训练10*9/2个分类器(共10类,两两一个分类器)

一轮轮判断,类似于二叉树查询,最多10次即可得出适合的预测。

结果同样不准确,在我的观点看来,两两一个分类器,若输入样本不在这两类中,就很容易出现误差,可能出现classifier function的值特别大,从而干扰到预测,只是若预测前几个的话会有正确的预测。

4.训练9*10个二分类器(共十类,两类之间有两个分类器,分别为其中之一的正样本分类器)

结果很不稳定,有的预测很准确能到达90%,有的很不准确,在25%左右。

5.一个二分类器(共两类)

输入为两类中的其中之一,这样的话预测的结果很准。



这个算法的实现花了大概两周的时间,前期看文章看了两天,第三天向的师姐请教,算是了解了整个算法的实现过程。之后花了两天时间把patch descriptor提取出来并利用k-means聚成500类,但是到5.3的quantizing features的时候发现量化后500维几乎都为0了,给文章作者Mathias Eitz发了封邮件询问了这个问题,很开心他回复了,让我调大高斯核函数中的sigma试试看,调大之后发现情况并没有好转,虽然为0的维数减少了,但是都是e-100以上的量级,后来又读了一遍文章发现在patch descriptor的提取中忘了对其进行归一化处理,归一化后在进行quantizing features情况有所好转,但是还是有很大一部分为0(我觉得有可能这里导致了之后分类效果差)。之后就进行svm训练预测,效果不太好。最后根据多个不同的svm的处理方法得到了几个不同的预测方法,然后用mfc做了个界面,让大家简单的试试看吧。