图像相似度比较之哈希算法

哈希算法是一个函数,能把几乎所有的数字文件转换为一串由字符和数字组成的看似乱码的字符串。因此哈希函数也是加密函数,它具备两个特点:

  • 不可逆性。输入信息得到输出的哈希值往往比较容易,但是由输出的字符串反推输入信息非常难。
  • 输出值唯一性和不可预测性。即便两个输入信息只有一点点区别,得到的哈希值也会相差甚远。

均值哈希算法aHash

步骤:

  1. 将图片缩放为88,保留结构,除去细节(为什么是88?为了后续生成64位的值)
  2. 转换为灰度图(如果要考虑色彩的相似性,就不用转)
  3. 计算灰度图所有像素的平均值
  4. 像素值大于平均值记作1,相反为0,总共64位
  5. 将上述得到的1和0组合起来就是图片的指纹(哈希值)
  6. 对比两幅图的指纹,计算汉明距离(也就是两个64位的hash值有多少位是不一样的),不同位数越小,图片越相似。

差值哈希算法dHash

步骤基本与aHash类似:

  1. 将图片缩放为8*9,保留结构,除去细节
  2. 转换为灰度图(如果要考虑色彩的相似性,就不用转)
  3. 像素值大于后一个像素值就记作1,相反为0,每行有9个像素,会有8个差值,有8行,总共也是64位
  4. 将上述得到的1和0组合起来就是图片的指纹(哈希值)
  5. 对比两幅图的指纹,计算汉明距离(也就是两个64位的hash值有多少位是不一样的),不同位数越小,图片越相似。

感知哈希函数pHash(了解即可,不展开)

三种算法对比:
均值哈希速度比较快,但是常常不太精确。比如均值为100,那么像素为99和1都会被记作0,显然比较粗糙。
感知哈希精确度较高,但是速度方面较差一些。
差值哈希精确度较高,且速度也非常快。因此这是用的最多的。

代码也比较简单:

import cv2
import numpy as np
 
#均值哈希算法
def aHash(img):
    #缩放为8*8
    img=cv2.resize(img,(8,8),interpolation=cv2.INTER_CUBIC)
    #转换为灰度图
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    #s为像素和初值为0,hash_str为hash值初值为''
    s=0
    hash_str=''
    #遍历累加求像素和
    for i in range(8):
        for j in range(8):
            s=s+gray[i,j]
    #求平均灰度
    avg=s/64
    #灰度大于平均值为1相反为0生成图片的hash值
    for i in range(8):
        for j in range(8):
            if  gray[i,j]>avg:
                hash_str=hash_str+'1'
            else:
                hash_str=hash_str+'0'            
    return hash_str
 
#差值感知算法
def dHash(img):
    #缩放8*9
    img=cv2.resize(img,(9,8),interpolation=cv2.INTER_CUBIC)
    #转换灰度图
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    hash_str=''
    #每行前一个像素大于后一个像素为1,相反为0,生成哈希
    for i in range(8):
        for j in range(8):
            if   gray[i,j]>gray[i,j+1]:
                hash_str=hash_str+'1'
            else:
                hash_str=hash_str+'0'
    return hash_str
 
#Hash值对比
def cmpHash(hash1,hash2):
    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
 
img1=cv2.imread('lenna.png')
img2=cv2.imread('lenna_noise.png')
hash1= aHash(img1)
hash2= aHash(img2)
print(hash1)
print(hash2)
n=cmpHash(hash1,hash2)
print('均值哈希算法相似度:',n)
 
hash1= dHash(img1)
hash2= dHash(img2)
print(hash1)
print(hash2)
n=cmpHash(hash1,hash2)
print('差值哈希算法相似度:',n)

输出:

1011111010011110100111011010100110101011101000110000111000101100
1011011010011110100111011010100110101011101000111010111000101100
均值哈希算法相似度: 3
1000100110001101101000101010010001000110111011001010010110000011
1001100110001101100000101110010011000110011011000010010111000011
差值哈希算法相似度: 7

你可能感兴趣的:(哈希算法)