您的位置:首页 > 其它

Angel Eyes基于SIFT特征点的图像搜索系统的开发

2012-02-06 11:39 267 查看
过年回来以后,Angel Eyes的团队成员又开始了紧张忙碌的工作。为了争取在这个月向外界开放API和SDK,我们又对图像特征点搜索系统开发做了进一步的研究和实验,以力求搜索,匹配的精准。以下是我们基于SIFT特征点的图像搜索系统开发日志,也算是一些心得,与各位CV的同行们分享。

一、C#验证实验阶段

1、实验框架搭建工作:配置EmguCV、编写界面。

写界面是C#的长项,不过需要怎样一个界面来做实验,倒是一开始没想清楚,折腾了几下,要是用MFC来写,就伤不起了。





2、特征点提取与XML存储

以前学习的C#的XML序列化派上用场了,几行代码轻松解决图像库的特征点存储问题,存储的XML格式片段如下:

<Objects>

<StandardObject>

<Name>U盾</Name>

<Images>

<FeaturableImage>

<Name>IMG_0819.jpg</Name>

<Featrues>

<ImageFeature>

<Descriptor>

<float>0.000823393755</float>

<float>0.0008284497</float>

…………………………………………………….

</StandardObject>

</Objects>

3、简单图像搜索,两幅图像对比时,仅考虑两幅图像中有多少比例的特征点配对





4、高级筛选:随机样本一致算法

4.1 仿射变换模型封装(6参数线性变换模型,支持旋转、平移、缩放、错切等变换的组合,不含尺度空间的尺度参数)

4.2仿射变换模型的最小二乘拟合

4.2.1 公式推导:相当于多元线性回归的最小二乘拟合

4.2.2 求解3元一次方程组,我们用的最基本的行列式和代数余子式的求法,看了一下网上的,其他人是用了列主元素消元法,没有Angel Eyes的方法精度高,最终筛选效果不行,到底是他们实现的列主元素消元法不太正确,还是方法本身的差异,Angel Eyes也没深究,因为3元一次的方程组用什么方法速度都差不多,精度够就行。

怕求余子式展开时不小心写错,试用MatLab的符号计算功能,还不错

syms a11 a12 a13

syms a21 a22 a23

syms a31 a32 a33

A=[a11,a12,a13;a21,a22,a23;a31,a32,a33];

syms y1 y2 y3;

Y=[y1;y2;y3];

linsolve(A,Y)

4.3 实现随机样本一致

按照维基百科关于随机抽样的共识(RANdom SAmple Consensus,RANSAC)的词条介绍的框架,带入仿射变换模型来实现的。

其中有一点想法,就是RANSAC每次随机选三点建立仿射变换模型,有可能重复,导致要做随机选择的次数比较多,才有充分的代表性,倒是可以设计一个每次选三点绝不重复的伪随机函数,不知道性能能否提升一丁点,不过这块不是算法的性能瓶颈,可以控制在1ms以内筛选好两幅有较多相似特征点的匹配,没功夫纠缠了。

维基百科英文RANSAC:http://en.wikipedia.org/wiki/Ransac 信息更全面

筛选后的结果如下,比没筛选的效果好太多。





5 如何利用筛选后的结果

在筛选之前,我们只考虑匹配上了多少对点,筛选之后,我们还可以利用这些点的一致性(回归的残差越小,说明拟合得越好,一致性越好),这里我们粗略建了一个评价函数,还需进一步查资料了解经典的做法是怎样。

6 特征点的搜索

如果用C#组个对比特征点(128位向量),整个搜索匹配过程会非常慢,如下图所示,差不多一幅图要耗1秒钟。





二、C++移植阶段

做C++移植主要是两个目的:一个是在算法复杂度一样的情况下,利用C的高效,尽量提高搜索效率,通过特征点的全遍历搜索来看,做这种纯数值计算,C++还是可以比C#快2-3倍;第二个目的是C++的兼容性好,可以把服务器架架设在Linux、Windows,也可以把搜索匹配做在iOS、安卓上。

1.用KDTREE实现特征点的高效搜索

提到高效检索,我们应该想到的就是HASH表和二叉平衡树了, KD树就是多关键字的二叉树,如果不考虑对结点的增删改,我们可以把这颗二叉树建得非常平衡,这样相对于顺序查找,查找效率是非常高的。

1.1 调用or自己写?

KDTree的基本原理和实验数据仍然是从博客园的博文http://archive.cnblogs.com/a/2241247/参考的。在网上找了几个KdTree的实现代码,感觉实现得比较好的是OpenCV的_kdtree.hpp,不过OpenCV的那段代码太多C的技巧和特殊优化的处理,没看太懂怎么用起来就放弃了,我们自己实现一遍吧,有什么特殊需求也好修改。从OpenCV哪里倒是借鉴了一次性全部申请树的所有结点的方法,不然按数据结构教科书的套路,差点弄成每个结点单独动态申请了,效率降很多还不好存储到磁盘文件。另外可能有一小点创新的是,在生成KDTree做排序划分的时候,没有去移动特征向量,而是做了一个小标集map,排序的是map中的下标,这样排序的移动代价小了128倍,最后查找使用时,也没增加复杂度,唯一的坏处是得自己写排序算法,c语言标准的qsort不好支持这样的排序需求。

1.2 几个经典的bug(缺陷)调试

第一个缺陷是:建立的KDTree数据量小的时候没问题,数据量大就报告栈溢出,一查看原来是qsort递归次数太多,再一看怎么会这么递归多呢?原来是qsort遇到了最坏情况,数据是有序的,每次只能把数据分成1和n-1个,这个n很大时,递归次数当然很多。为什么运气会这么差呢?再以分析,应该在建立KDTree时,有些作过划分维的维度,已经有序了。我们自己心里当然明白,按说有三个方法解决,一个是舍伍德算法也就是乱序再来,感觉费劲还效果不一定好,一个是每次取中位数做划分依据,实现太麻烦,最后选择实现了一个非递归的MergeSort,轻松实现又不依赖于人品,什么样顺序的数据都可以稳定的表现。

第二个缺陷是:用C#做顺序搜索,然后筛选,查找,结果很好。同样搜索参数,用KDTree做下来很差,反复分析分析分析之后,发现我们在C#中用标准图中的每个点在未知图中找最相似的匹配点,因为标准图没有多余的特征点,这样匹配下来的有效率很高。而对于KDTree,我们只能用未知图的特征点在KDTree中搜索在每幅标准图中的最相似点,而未知图的背景比较复杂,对于最终正确的匹配,无效特征点很多,这样做就会出很多无效匹配点,挤占了有效匹配点的比例,导致RANSAC算法的一个前提条件不成立:就是内点要达到一定比例才能用RANSAC。发现了就有办法解决,具体不说了。

第三个缺陷是:居然KDTree没有顺序搜索速度快,不管是5000个特征点的标准库(都是5秒),还是22000个特征点的标准库(都是18秒),居然和顺序搜索一样,毫无点,严重的打击了我们团队的斗志,岂不是白忙活一阵子,完全不能用?然后深入调节参数,在保证搜索准确率不降低的情况下,把KDTree的搜索效率大幅度提高。同时

在5017个特征点中搜索火机图,需要171ms,29.3个特征点/ms

在22228个特征点中搜索火机图,需要578ms,38.5个特征点/ms

在32643个特征点中搜索火机图,需要812ms,40.2个特征点/ms



以上数据初步说明当特征点越多的时候,检索效率越高,KDTree有一定效果,按这个升高趋势,在10幅图中检索要超过100ms,在100幅图中检索在1000ms以内,在1000幅图钟检索应该在6000ms左右。

三、性能深度优化阶段

1、考虑多线程,预计8核提高5倍

2、考虑分布式计算,预计提高10-100倍,视资源多少而定

3、考虑SSE等CPU多媒体指令级别的优化,预计提高10-50倍

4、考虑设计KDTree以外的更高效的多关键字检索算法,有一定想法,希望提高10-200倍

5、显卡计算,CUDA不是很通用,暂时不考虑

6、考虑服务端被大量用户并发访问,性能降低1000倍。

我们的产品Angel Eyes预计将会在这个月向开发者开放API和SDK,希望对计算机视觉(CV)和Angel Eyes感兴趣的朋友能够时刻关注我们的信息,并申请内测。

我们的网址:www.angeleyes.it

我们的微博:http://weibo.com/u/2597388234

我们的电邮:angeleyes.tech@gmail.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: