来源于阮一峰的博客
对两张图片进行相似度检测,思路就是对两张图片分别计算其指纹信息,然后对比两张图片的指纹信息的差异度。
基本算法为:
第一步,缩小尺寸。
将图片缩小到8×8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。

第二步,简化色彩。
将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。
第三步,计算平均值。
计算所有64个像素的灰度平均值。
第四步,比较像素的灰度。
将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。
第五步,计算哈希值。
将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。
=8f373714acfcf4d0
得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算”汉明距离”(Hamming distance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。
代码由Wote利用Python实现,本文是对Wote的源码做一点修改并附上详细注释。
本程序需要安装pillow,
pip install pillow
#coding: utf-8
'''
本程序运行时需要两张图片路径,需要输入两张图片路径,
'''
from PIL import Image
#计算指纹
def avhash(img):
if not isinstance(img, Image.Image):
img = Image.open(img)
img = img.resize((8, 8), Image.ANTIALIAS).convert('L') #将image压缩为8*8,转化为灰度图
avg = reduce(lambda x, y: x + y, img.getdata()) / 64. #对每个像素点的灰度累和,最后除以64,得到灰度的平均值
#这一句代码很pythonic,需要仔细消化
#map对每个像素做判断,大于平均值为1,否则为0
#enumerate函数返回一个列表的下标及该下标对应的元素,用tuple装起来: (index, element)
#reduce,对每个元素右移对应的下标位,并且与前一个元素做或运算,最终得到的结果为一个
# 64位的二进制数,每一位的0,1代表该位的像素灰度与平均像素灰度的比较结果
return reduce(lambda x, (y, z): x | (z << y), enumerate(map(lambda i: 0 if i < avg else 1, img.getdata())), 0)
#计算汉明距离
def hamming(h1, h2):
#直接对两个数按位做异或操作,这样得到一个64位的二进制数,该二进制数包含的1的个数,即为汉明距离
h, d = 0, h1 ^ h2
#求d中包含的1的个数
while d:
h += 1
d &= d - 1
return h
if __name__ == '__main__':
img1 = raw_input('请输入第一张图片路径:')
img2 = raw_input('请输入第二张图片路径:')
h1 = avhash(img1)
h2 = avhash(img2)
print "两张图片的指纹汉明距离为:%s" % hamming(h1, h2)
'''
本程序运行时需要两张图片路径,需要输入两张图片路径,
'''
from PIL import Image
#计算指纹
def avhash(img):
if not isinstance(img, Image.Image):
img = Image.open(img)
img = img.resize((8, 8), Image.ANTIALIAS).convert('L') #将image压缩为8*8,转化为灰度图
avg = reduce(lambda x, y: x + y, img.getdata()) / 64. #对每个像素点的灰度累和,最后除以64,得到灰度的平均值
#这一句代码很pythonic,需要仔细消化
#map对每个像素做判断,大于平均值为1,否则为0
#enumerate函数返回一个列表的下标及该下标对应的元素,用tuple装起来: (index, element)
#reduce,对每个元素右移对应的下标位,并且与前一个元素做或运算,最终得到的结果为一个
# 64位的二进制数,每一位的0,1代表该位的像素灰度与平均像素灰度的比较结果
return reduce(lambda x, (y, z): x | (z << y), enumerate(map(lambda i: 0 if i < avg else 1, img.getdata())), 0)
#计算汉明距离
def hamming(h1, h2):
#直接对两个数按位做异或操作,这样得到一个64位的二进制数,该二进制数包含的1的个数,即为汉明距离
h, d = 0, h1 ^ h2
#求d中包含的1的个数
while d:
h += 1
d &= d - 1
return h
if __name__ == '__main__':
img1 = raw_input('请输入第一张图片路径:')
img2 = raw_input('请输入第二张图片路径:')
h1 = avhash(img1)
h2 = avhash(img2)
print "两张图片的指纹汉明距离为:%s" % hamming(h1, h2)
1 评论