Java 实现图片相似度比较 - 颜色分布法
0. 本文中实现的思路来自于以下博客:
1. 如何判断两张图片的相似性有多少
本文的代码实现已经上传到github,需要的可以自行获取,地址:calculate-pic-looklike
想看详细版的,请看这篇文章:相似图片搜索的原理。
太长不看的简略版如下:
人类比较两张图片是否类似的时候,我们其实会依据图片中图形的轮廓是否在脑海中已经存在过进行联想,然后大脑自动帮我们关联到看到的记忆上。
而对于计算机来说,判断两张图片的相似度靠的是 “感知哈希算法”。它会给每一张图片生成一个“指纹”,然后比较两张图片的指纹,结果越接近就说明图片越相似。
怎么比较两个指纹的相似度,上面的文章中提到有:皮尔逊相关系数或者余弦相似度
Pearson相关系数(Pearson Correlation Coefficient)是用来衡量两个数据集合是否在一条线上面,它用来衡量定距变量间的线性关系。
pearson相关系数衡量的是线性相关关系。若r=0,只能说x与y之间无线性相关关系,不能说无相关关系。相关系数的绝对值越大,相关性越强:相关系数越接近于1或-1,相关度越强,相关系数越接近于0,相关度越弱。
通常情况下通过以下取值范围判断变量的相关强度: 相关系数 0.8-1.0 极强相关
0.6-0.8 强相关
0.4-0.6 中等程度相关
0.2-0.4 弱相关
0.0-0.2 极弱相关或无相关
对于x,y之间的相关系数r :
当r大于0小于1时表示x和y正相关关系
当r大于-1小于0时表示x和y负相关关系
当r=1时表示x和y完全正相关,r=-1表示x和y完全负相关
当r=0时表示x和y不相关
所以,比较两个图片的相似度在于得出图片指纹(数据集合),用这两个数据集合代入皮尔逊相关系数就可以得到。
那么怎么从图片得到图片指纹呢?
1.1 图片到图片指纹
我们都知道任何图片在电子屏幕上显示都由光学三原色构成(红绿蓝),在计算机中我们对三原色用RGB来进行表示,比如:
(255 ,180, 0) 表示的颜色是:

那么我们可以通过代码获取到一张图片的所有的像素点,然后把每个像素点进行拆分都可以得到RGB数值,把这些RGB数值计数,那么就会得到:
(0,0,0) 出现次数10000次
(0,0,1) 出现次数25次
...
(0,0,1) 出现次数90次
把这些用次数收集起来,得到集合{10000,25,...,90}就是图片指纹。
分别对两个图片都这样操作,然后得到这个数据集合,再通过上面说到的皮尔逊相关系数或者余弦相似度 进行对比,就知道这两张图片的相似度了。
但是如果我们对R,G,B都采用0-255的范围进行比较,那么产生的可能性就有:
为了我们简化计算,一般采用的是这样的方式:将0~255分成四个区:0~63为第0区,64~127为第1区,128~191为第2区,192~255为第3区。这意味着红绿蓝分别有4个区,总共可以构成64种组合(4的3次方)。
如下图所示:

将表中最后一栏提取出来,组成一个64维向量(7414, 230, 0, 0, 8, ..., 109, 0, 0, 3415, 53929)。这个向量就是这张图片的特征值或者叫"指纹"。
然后代入皮尔逊相关系数进行计算