名字

没想好

高度相似图片检测: 2图片缩小指纹

| Comments

图片缩小之后其实保留个部分图片的信息,可以用来当做图片的指纹,在查找相关资料的时候发现了一个很不错的博客 在这个博客里,几乎所有的和图片相似性计算的算法都在了(除了基于语义的)。超级不错。里面的很多算法的实现是用pearl的,而本身抱着学习的态度我决定重新用python对其中的某些算法实现一遍。

这里是图片缩小指纹的算法:

  • 缩放到160x160的图片
  • 灰值化
  • 模糊图片,把噪音去除掉
  • equalize,让图片反差更大
  • 计算图片平均值
  • 缩放到16x16的图,并且降到2维,更具图片pixel值:大于平均值的为1,反之为0

这样就生成了图片的指纹,信息总量有2^256, 哈希冲撞应该不大。 计算的图片相似度的时候直接使用xor。公式可以是这样: 1 - xor(p1,p2)/256

具体python实现代码如下:

from PIL import Image
import sys
import ImageFilter
import ImageOps 
import numpy as np

def normalize(img, size = (160, 160)):
    return ImageOps.equalize(img.resize(size).convert('L').filter(ImageFilter.BLUR))

def calculate_fingerprint(img):
    img = normalize(img)
    mean_value = np.mean(np.array(img.getdata()))
    img = img.resize((16,16))
    return np.array(img.getdata())>mean_value

def calculate_simility_by_path(img_path1, img_path2):
    img1 = Image.open(img_path1)
    img2 = Image.open(img_path2)
    fingerprint1 = calculate_fingerprint(img1) 
    fingerprint2 = calculate_fingerprint(img2) 
    return 1 - (0.0+np.sum(np.logical_xor(fingerprint1, fingerprint2)))/fingerprint1.size

if __name__ == "__main__":
    print calculate_simility_by_path(sys.argv[1],sys.argv[2])

更好的implementation可以在这个链接找到,虽然做法上不一样,但是原理应该都差不多。在代码的注释里,能看到这个类算法的优点和缺点,如果图片相似度较高的话,识别起来没什么问题。最大的缺点是,很多false positive,如果图片是一张大海的话 会出现一下情况

1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000

作者还说到对于大规模数据的话,性能会降低很多。但是貌似这个能用bloomfilter解决,现在先不管他

Comments