pHash算法python+opencv实现

"感知哈希算法"(Perceptual hash algorithm),它的作用是对每张图片生成一个"指纹"(fingerprint)字符串,然后比较不同图片的指纹。结果越接近,就说明图片越相似。

一般步骤:

  • 缩小图片:32 * 32是一个较好的大小,这样方便DCT计算
  • 转化为灰度图:把缩放后的图片转化为256阶的灰度图。(具体算法见平均哈希算法步骤)
  • 计算DCT:DCT把图片分离成分率的集合
  • 缩小DCT:DCT计算后的矩阵是32 * 32,保留左上角的8 * 8,这些代表的图片的最低频率
  • 计算平均值:计算缩小DCT后的所有像素点的平均值。
  • 进一步减小DCT:大于平均值记录为1,反之记录为0.
  • 得到信息指纹:组合64个信息位,顺序随意保持一致性。
  • 最后比对两张图片的指纹,获得汉明距离即可。

实现代码:

import cv2
import numpy as np
from itertools import chain

class PHash(object):
    @staticmethod
    def pHash(img_name):
        """
        get image pHash value
        """
        # 加载并调整图片为32x32灰度图片
        img = cv2.imread(img_name, 0)
        img = cv2.resize(img, (64, 64), interpolation=cv2.INTER_CUBIC)

        # 创建二维列表
        h, w = img.shape[:2]
        vis0 = np.zeros((h, w), np.float32)
        vis0[:h, :w] = img  # 填充数据

        # 二维Dct变换
        vis1 = cv2.dct(cv2.dct(vis0))
        # cv.SaveImage('a.jpg',cv.fromarray(vis0)) #保存图片
        vis1.resize((32, 32), refcheck=False)

        # 把二维list变成一维list
        img_list = list(chain.from_iterable(vis1))

        # 计算均值
        avg = sum(img_list) * 1. / len(img_list)
        avg_list = ['0' if i < avg else '1' for i in img_list]
    
        # 得到哈希值
        return ''.join(['%x' % int(''.join(avg_list[x:x + 4]), 2) for x in range(0, 32*32, 4)])

    @staticmethod
    def hammingDist(s1, s2):
        """
        计算两张图片的汉明距离
        """
        assert len(s1) == len(s2)
        return sum([ch1 != ch2 for ch1, ch2 in zip(s1, s2)])


if __name__ == '__main__':
    HASH1 = PHash.pHash('001.jpg')
    HASH2 = PHash.pHash('002.jpg')
    distance = PHash.hammingDist(HASH1, HASH2)
    print(distance)
    out_score = 1 - distance * 1. / (32 * 32 / 4)
    print(out_score)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章