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)

 

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