图片搜索之感知哈希算法

 
  TinEye是如何工作的呢?这里面也许有十分复杂的原理。不过从结果看来,它使用了一种叫做“感知哈希算法(以下简称PHA)”的东西。
          PHA是一类比较哈希方法的统称。图片所包含的特征被用来生成一组指纹(不过它不是唯一的),而这些指纹是可以进行比较的。
          PHA与加密哈希方法(以下简称CHA),如MD5、SHA1等,是不同的概念。CHA的哈希值是随机的。用来生成哈希的数据的行为就像随机种子,所以相同的数据产生相同的结果,反之亦然。读者可以如下做ruby测试:
          require 'digest/sha2'
          ......
          #生成加密后的散列值
          def self.encrypt(string)
              return Digest::SHA256.hexdigest(string)
          end
          我对这方面未做深层研究,如有错误,不吝赐教。此文的重点不是CHA,恕草草带过。
       
          如果想要深入理解下文内容的话,不妨读读我在ftp里的fourier相关文档,会有所收获。当然,不读也不会造成大的影响。(ftp具体在文末有提及)

        对于图片来说,高频得到细节,低频得到轮廓。所以小图缺少细节,是低频的。我先叙述一个阮一峰先生提及的最简单PHA,在此表示感谢。大家可一睹为快。

      感知哈希算法浅析

     

      第一步,缩小尺寸。

      最快速的去除高频和细节,只保留结构明暗的方法就是缩小尺寸。

      将图片缩小到8x8的尺寸,总共64个像素。摒弃不同尺寸、比例带来的图片差异。

    感知哈希算法浅析 

      第二步,简化色彩。

      将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。

      第三步,计算平均值。

      计算所有64个像素的灰度平均值。

      第四步,比较像素的灰度。

      算法的精髓,简单、有趣,又充满深意。

      将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。

      第五步,计算哈希值。

      将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了(例如,自左到右、自顶向下、big-endian)。

      感知哈希算法浅析 = 8f373714acfcf4d0

      得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算Hammingdistance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。

        这个算法非常好,无论你改变图片的高宽、亮度甚至颜色,都不会改变哈希值。最关键的是速度极快!cool!

        我在ftp里放了这个算法的python版本(使用了PIL库),如果读者会ruby的话,不妨使用RMagick库,同样强大(文档:http://www.imagemagick.org/RMagick/doc/项目:http://rubyforge.org/projects/rmagick/)

        有没有更好的方法来判断相似度呢?有,pHash。这种方法稍复杂写,运用了DCT来降低频度,比起平均值方法更精确了。DCT参见http://en.wikipedia.org/wiki/Discrete_cosine_transform
        下面来看它的过程。
        第一步,缩小尺寸。
                              与平均值方法类似,不过要比8X8大些,32X32是个好尺寸,这样做是为了简化DCT的计算,而不是降频。

        第二步,简化色彩。
                              改成灰度图,也是为了减少DCT计算量。

        第三步,计算DCT。
                              DCT将图片分成了频度和纯量的集合。当JPEG使用8X8的DCT时,算法就使用32X32的DCT。

        第四步,降低DCT。
                              当DCT是32X32时,只保留顶左的8X8,这部分代表了图片的最低频。这是神奇的一步。
       
        第五步,计算平均值。
                              只用8X8的DCT低频值,因为DC系数和其他值相差很大,会破坏平均值。
 
        第六步,进一步缩小DCT
                              将每个像素的灰度(64比特),与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。图片结构不变,结果就不会变。这完成了关键的一步。

        第七步,构造哈希。
                                将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。
       
        感知哈希算法浅析 = 8a0303f6df3ec8cd
        看上去很随机的blob,其实仔细看容易发现,黑点是头部轮廓和原图右边背景的垂直线。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值