名字

没想好

高度相似图片检测: 3 Perceptual Hash(phash) 图片指纹

| Comments

最后一个要介绍的图片指纹生成方法: pHash, 这里是pHash算法简要:

  • 图片指纹灰值化
  • 图片缩放到32x32
  • 计算机视觉每个图片的Discrete Cosine Transform (DCT, type II)。
  • 只保留最左上部的8x8的DCT系数(有32x32大),这样保存了频率最低的那部分(图片信息的大部分)
  • 计算中值
  • 生成64维2维码,0表示系数小于中值,反之为1.

说到DCT,其实就想傅里叶转换一样的,把信号转换成很多不同频率和振幅的正玄曲线相加的结果。但是DCT只是用cosine函数。这样的话图片高频率部分会给擦去,只保留低频率部分。因为在给图片操作的时候,往往低频率的DCT系数会给保留,而且大部分图片的信息会给保留在这些低频率DCT系数里。(JPEG压缩也用这个方法来对图片进行压缩)。 DCT 会生成8x8的系数表,那最左上方的表示最低频率的元素,也是最重要的,越往右下的表示相对频率稍高的元素(好多信号出来的东西啊,头好大) 反正到最后能生成一个图片指纹,从别的作者的实验结果来看,效果是相对较好的。在这个网站上phash.org能下到开源的代码,在网站的demo上可以可以试试看计算图片的相似性,通过测试,只有DCT比较靠谱,另外两个的结果非常糟糕。相同的,这个算法的信息量为2^64,冲撞率应该不高,吧?

phash.org网站上是用c/c++写的代码,没有python的binding,在https://github.com/polachok/py-phash/可以找到一个简陋的python binding,里面有我们需要的DCT的计算方法,调用一个函数就能直接获得指纹数值。测试了几下,效果还不错。不过还是需要很大量的图片用语测试false positive的概率。 在github上能看到作者写的使用方法说明,我这里具体的代码如下:


import pHash
import sys

if __name__ == "__main__":
    hash1 = pHash.imagehash(sys.argv[1])
    hash2 = pHash.imagehash(sys.argv[2])
    print 'Hamming distance: %d (%08x / %08x)' % ( pHash.hamming_distance( hash1, hash2 ), hash1, hash2 )

Comments