感知哈希算法计算图像相似度

实现图片相似度比较的哈希算法有三种:均值哈希算法,差值哈希算法,感知哈希算法
下文简单介绍感知哈希算法,其他算法等后续文档再述。
感知哈希算法是一个比均值哈希算法更为健壮的一种算法,与均值哈希算法的区别在于感知哈希算法是通过DCT(离散余弦变换)来获取图片的低频信息。
离散余弦变换(DCT)是种图像压缩算法,它将图像从像素域变换到频率域。然后一般图像都存在很多冗余和相关性的,所以转换到频率域之后,只有很少的一部分频率分量的系数才不为0,大部分系数都为0(或者说接近于0)。经过DCT变换后的系数矩阵从左上角到右下角频率越来越高,因此图片的能量主要保留在左上角的低频系数上了。
具体步骤:
(1)缩小尺寸:pHash以小图片开始,但图片大于8x8,32x32是最好的。这样做的目的是简化了DCT的计算,而不是减小频率。
(2)简化色彩:将图片转化成灰度图像,进一步简化计算量。
(3)计算DCT:计算图片的DCT变换,得到32x32的DCT系数矩阵。
(4)缩小DCT:虽然DCT的结果是32x32大小的矩阵,但我们只要保留左上角的8x8的矩阵,这部分呈现了图片中的最低频率。
(5)计算平均值:如同均值哈希一样,计算DCT的均值。
(6)计算hash值:这是最主要的一步,根据8x8的DCT矩阵,设置0或1的64位的hash值,大于等于DCT均值的设为”1”,小于DCT均值的设为“0”。组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。
分析: 结果并不能告诉我们真实性的低频率,只能粗略地告诉我们相对于平均值频率的相对比例。只要图片的整体结构保持不变,hash结果值就不变。能够避免伽马校正或颜色直方图被调整带来的影响。对于变形程度在25%以内的图片也能精准识别。
代码实例:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import os
import glob
dir_data=os.path.dirname(os.path.dirname(__file__))
# Hash值对比


def cmpHash(hash1, hash2,shape=(10, 10)):
    n = 0
    # hash长度不同则返回-1代表传参出错
    if len(hash1)!=len(hash2):
        return -1
    # 遍历判断
    for i in range(len(hash1)):
        # 相等则n计数+1,n最终为相似度
        if hash1[i] == hash2[i]:
            n = n + 1
    return n/(shape[0]*shape[1])


 #  感知哈希算法(pHash)


def pHash(img,shape=(10,10)):
    # 缩放32*32
    img = cv2.resize(img, (115, 114))  # , interpolation=cv2.INTER_CUBIC

    # 转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 将灰度图转为浮点型,再进行dct变换
    dct = cv2.dct(np.float32(gray))
    # opencv实现的掩码操作
    dct_roi = dct[0:10, 0:10]

    hash = []
    avreage = np.mean(dct_roi)
    for i in range(dct_roi.shape[0]):
        for j in range(dct_roi.shape[1]):
            if dct_roi[i, j] > avreage:
                hash.append(1)
            else:
                hash.append(0)
    return hash


def match_result():
    for jpgfile in glob.glob(dir_data+'\POC\img/*.jpg'):
        file=os.path.basename(jpgfile)
        img1 = cv2.imread('images/template.jpg')
        img1 = cv2.resize(img1,(115,114))
        img2 = cv2.imread(jpgfile)

        hash1 = pHash(img1)
        hash2 = pHash(img2)
        n = cmpHash(hash1, hash2)
        print('{}的相似度是:{}'.format(file, n))
    

if __name__=="__main__":
    match_result()

以上代码运行结果如下:

 

posted @ 2022-11-05 10:07  麦哥编程  阅读(321)  评论(0编辑  收藏  举报