您的位置:首页 > 其它

计算图像相似度

2008-05-05 12:36 225 查看
本文转载自『恋花蝶的博客!』
http://blog.csdn.net/lanphaday
更多精彩内容,欢迎访问恋花蝶的博客! 计算图像相似度——《Python也可以》之一
新一篇: 蒙特卡罗算法在游戏(围棋)AI中的应用
计算图像相似度——《Python也可以》之一

声明:本文最初发表于赖勇浩(恋花蝶)的博客http://blog.csdn.net/lanphaday,如蒙转载,敬请确保全文完整,未经同意,不得用于商业用途。

关于《Python也可以》系列:这是我打算把这几年里做的一些实验和代码写出来,涉及的面比较广,也比较杂,可能会有图像处理、检索等方面的内容,也会有中文分词、文本分类、拼音、纠错等内容。毫不掩饰地说:在博客发这系列文章的原因在于宣传 python ,所以这系列文章都会带有源码和相关的测试用例,这也是特色之一。但这系列文章都是“浅尝辄止”的,不会深入到专属领域,只是为了表明 python 功能很强大,不仅适合于web 或者 game 开发,也适合于科学研究。

--------------------------------------------------------------------------------

要计算图像的相似度,肯定是要找出图像的特征。这样跟你描述一个人的面貌:国字脸,浓眉,双眼皮,直鼻梁,大而厚的嘴唇。Ok,这些特征决定了这个人跟你的同事、朋友、家人是不是有点像。图像也一样,要计算相似度,必须抽象出一些特征比如蓝天白云绿草。常用的图像特征有颜色特征、纹理特征、形状特征和空间关系特征等。颜色特征的算是最常用的,在其中又分为直方图、颜色集、颜色矩、聚合向量和相关图等。直方图能够描述一幅图像中颜色的全局分布,而且容易理解和实现,所以入门级的图像相似度计算都是使用它的;作为一篇示例性的“浅尝辄止”的文章,我们也不例外。

在进行我们试验之前,我们需要找到一批图片来作为测试用例。我上穷碧落下黄泉,最后终于在我的前同事西门的博客(http://blog.163.com/johnal1 )找到了一系列他在公司组织的年度旅游时去西藏林芝拍的一组风光图片(http://blog.163.com/johnal1/blog/static/9394912200812105654784 ),实在是难得之佳品,简直可以说得到了它们我们的实验已经完成了90%。哦耶!下面来看一下我们最重要的一组照片(两张):

找到一组很好的测试图片之后,我们需要再给 Python 环境安装一个图像库,我的选择是PIL(Python image library)。PIL 为 Python 提供了图像处理功能,并且支持数十种图像格式。(关于 PIL 的介绍,可以查看我之前的文章《用Python做图像处理》http://blog.csdn.net/lanphaday/archive/2007/10/28/1852726.aspx

虽然这两张图片大小都是一样的,但为了通用性,我们有必要把所有的图片都统一到特别的规格,在这里我选择是的256x256的分辨率。

因为 PIL 为 RGB 模式的图像计算的 histogram 样点数为 768,计算量并不算太大,所以本文就直接使用,没有再作降维处理了。

6 def make_regalur_image(img, size = (256, 256)):

7 return img.resize(size).convert('RGB')

转化为规则图像之后,可以调用 img.histogram() 方法获得直方图数据,如上文两图的直方图如下:

得到规则图像之后,图像的相似度计算就转化为直方图的距离计算了,本文依照如下公式进行直方图相似度的定量度量:

Sim(G,S)=,其中G,S为直方图,N 为颜色空间样点数

转换为相应的 Python 代码如下:

19 def hist_similar(lh, rh):

20 assert len(lh) == len(rh)

21 return sum(1 - (0 if l == r else float(abs(l - r))/max(l, r)) for l, r in zip(lh, rh))/len(lh)

22

23 def calc_similar(li, ri):

24 return hist_similar(li.histogram(), ri.histogram())

短短十行代码不到就完成了图片相似度的计算,再加上从硬盘读取图像的函数和测试代码,也不过二十行上下:

28 def calc_similar_by_path(lf, rf):

29 li, ri = make_regalur_image(Image.open(lf)), make_regalur_image(Image.open(rf))

30 return calc_similar(li, ri)

31

32 if __name__ == '__main__':

33 path = r'test/TEST%d/%d.JPG'

34 for i in xrange(1, 7):

35 print 'test_case_%d: %.3f%%'%(i, calc_similar_by_path('test/TEST%d/%d.JPG'%(i, 1), 'test/TEST%d/%d.JPG'%(i, 2))*100)

那么这样做的效果到底怎么样呢?且来看看测试结果(测试用例和代码请猛击这里下载):

test_case_1: 63.322%

test_case_2: 66.950%

test_case_3: 51.990%

test_case_4: 70.401%

test_case_5: 32.755%

test_case_6: 42.203%

结合我们肉眼对测试用例的观察,这个程序工作得还算可以。不过 test_case_4 就暴露了直方图的缺点:它只是图像中颜色的全局分布的描述,无法描述颜色的局部分布和色彩所处的位置。test_case_4 的规则图如下:

可以看到它们的色彩局部分布有相当大的不同,但事实上它们的全局直方图相当相似:

虽然从直方图来看两图是极其相似的,但上述算法计算出相似度为70.4%的结果肯定是不可接受的。那么,怎么样才能克服直方图的缺点呢?答案是把规则图像分块,再对相应的小块进行相似度计算,最后根据各小块的平均相似度来反映整个图片的相似度。在实验中,我们把规则图像分为 4x4 块,每块的分辨率为 64x64:

分割图像的代码为:

9 def split_image(img, part_size = (64, 64)):

10 w, h = img.size

11 pw, ph = part_size

12

13 assert w % pw == h % ph == 0

14

15 return [img.crop((i, j, i+pw, j+ph)).copy() /

16 for i in xrange(0, w, pw) /

17 for j in xrange(0, h, ph)]

相应地,把计算相似图的函数calc_similar()修改为:

23 def calc_similar(li, ri):

24 # return hist_similar(li.histogram(), ri.histogram())

25 return sum(hist_similar(l.histogram(), r.histogram()) for l, r in zip(split_image(li), split_image(ri))) / 16.0

进行这样的改进后,算法已经能够在一定的程序上反映色彩的局倍分布和颜色所处的位置,可以比较好的弥补全局直方图算法的不足。新的算法计算出来的结果如下:

test_case_1: 56.273%

test_case_2: 54.925%

test_case_3: 49.326%

test_case_4: 40.254%

test_case_5: 30.776%

test_case_6: 39.460%

可以看到,test_case_4的相似度由 70.4% 下降到 40.25%,基本上跟肉眼的判断是切合的;另外其它图像的相似度略有下降,这是因为加入了位置因子之的影响。从而可见基于分块的直方图相似算法是简单有效的。

图像的相似度计算是图像检索、识别的基础,本文只是浅尝辄止地介绍了其中最基本的计算方法,如果你要学习和研究更好的算法,也请记住 Python 也能帮助你哦~

本实验的所有代码和测试用例请猛击这里下载,再次感谢提供图片支持的西门同学。

发表于 @ 2008年04月24日 20:24:00|评论(20)|编辑

旧一篇: “Python性能优化”讲稿分享

有创意也能获得1000美元奖金+MID设备
证明你的实力,秀出你的创意,轻松拿大奖 Intel公司联合CSDN举办此次大赛,让更多的
秀DOMINO开发创意 赢取2万元大奖
捕捉灵光一闪的创意,赢取万元现金大奖! 秀创意,拿现金大奖,一切就这么简单!评论
#ideasky 发表于2008-04-25 10:52:12 IP: 221.218.78.*
好文,居然没人留言!#cayson 发表于2008-04-25 12:45:46 IP: 61.144.207.*
python 很好的工具,希望继续看到后面的文章,呵呵#liigo 发表于2008-04-25 13:07:09 IP: 60.20.0.*
PIL(Python image library)是一个完全用C语言开发的Python库,在本文中,Python做了什么(核心)工作?这似乎跟易语言/EF走的同一个路子,用C++给它开发一批支持库/类库出来,它就看起来非常强大了。当然我并不是说这样不好,能使用其它编程语言的资源当然很好。#沈崴 发表于2008-04-25 13:39:14 IP: 58.41.30.*
此帖不留名, 更待何时?#tir 发表于2008-04-25 15:01:01 IP: 203.186.8.*
这个...出来了结果是好的 但貌似走错了方向... 楼主可以多看看图像方面的论文
2008-04-26 09:56:50作者回复
好的,谢谢您的提点。我不是专业搞图像的,所以未免有点外行。不过,我这个算法也是很多资料都提到的哦。是不是你关注太多高端算法,这种基本的早已忘却了呢?#Cure 发表于2008-04-25 15:56:32 IP: 117.32.131.*
很好很强大#tianyaxiao 发表于2008-04-25 17:15:05 IP: 221.238.24.*
我猛击了#ttkk1024 发表于2008-04-25 19:40:50 IP: 221.204.94.*
简单就行了,管它什么语言实现的!小顶python#tangl_99 发表于2008-04-26 00:55:59 IP: 211.83.147.*
还是matlab做数值计算最方便吧。

2008-04-26 09:53:10作者回复
python 完全可以代替 matlab 的,你可以搜索一下 numpy/scipy/sega 等第三方库(程序)。相对于 matlab,python 优势在于效率和免费,另外代码的可维护性也要好得多。#tangl_99 发表于2008-04-26 10:58:52 IP: 118.112.218.*
matlab, C++, java都有很多第三方的库,第三方库都不少。

matlab相对于python做数值计算,有三大优势:

1) matlab做数值计算,不需要第三方库,而且方便一些。
2) matlab底层的数值计算库,很多funtran写的,无论是数学方法,还是代码效率,都接近最优化。
3) 还有行业传统的关系。很多人搞图像,信号的人,基本都熟悉matlab。很多图像和信号,数值计算的教科书上就是以matlab来讲解的。

2008-04-30 11:21:10作者回复
内容:如果没有盗版,中国几乎没有人用得起 matlab,另外,如果你经常访问国外的科研人员、学者的网站,会发现他们中的许多人正在转向 python 或用 python 开发的软件(如 sage)。 #Border 发表于2008-04-26 14:12:42 IP: 125.33.196.*
很好很强大, #wukongco 发表于2008-04-26 17:41:46 IP: 58.251.30.*
外行能成这样 不错#lnwuyaowei 发表于2008-04-27 10:11:30 IP: 221.202.199.*
与语言无关,与类库有关.#hacker47 发表于2008-04-27 11:40:04 IP: 60.172.215.*
支持liigo:

PIL(Python image library)是一个完全用C语言开发的Python库,在本文中,Python做了什么(核心)工作?这似乎跟易语言/EF走的同一个路子,用C++给它开发一批支持库/类库出来,它就看起来非常强大了。当然我并不是说这样不好,能使用其它编程语言的资源当然很好。
2008-04-30 11:16:04作者回复
pil 没有计算图像相似度的功能,在这个实验中,python 做了这件工作。python 的强大之处在于他的代码足够简洁,如果你喜欢用其它的,那显然也没问题。#injie 发表于2008-04-27 22:47:55 IP: 222.125.219.*
这题目开的也太大了,我以为你至少也用PCA或者SVM做吧,原来只是用histogram做。。。#zhrln 发表于2008-04-28 10:43:34 IP: 116.252.173.*
那还不如用汉编#zlAItlj 发表于2008-04-28 18:05:01 IP: 222.95.196.*
其实完全没有必要坚持某一些语言多好,但是为了证明某一种语言的能力那么就是另外一种说法了。记得当初刚刚开始接触Java的时候我觉得这种语言很好,可是现在却发现他有很多可能永远没有办法解决的问题了。所以,语言——适合需求最好。#Y 发表于2008-04-28 21:15:10 IP: 121.32.210.*
牛 我正要去学puthon 好文章 希望都能看到这样系列的文章 谢谢#xu 发表于2008-04-29 08:24:41 IP: 60.7.82.*
非常好
看来国内很多人对python缺乏了解
matlab固然不错 但是有用matlab做game开发 手机编程的么
python目前在科学计算和工程领域的应用正在迅速发展
连微软都在开发ironpython
matlab是搞算法研究的人玩一玩
用python却可以做实际的工程开发
python在底层固然依赖c语言,但是它的语法简洁性,可解释执行,面向对象等 弥补了c语言的一些不足
python还有大量 很好的代码库和开发团队
最重要的是 他是免费的 公开源代码 呵呵 还有什么比这个更让我喜欢的呢#xu yong hong 发表于2008-04-29 08:33:46 IP: 60.7.82.*
补充一下
看了你的帖子 我觉得基本明白图像分类是怎么回事了
其实简单的算法 往往是最实用的算法
比如自动控制中算法很多 最常用的还是PID
模式识别的算法很多 很多算法除了所谓精度更高 和复杂度剧增以外 到底还有多少高深之处呢
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: