感知哈希算法是一类算法的总称,包括aHash、pHash、dHash。顾名思义,感知哈希不是以严格的方式计算Hash值,而是以更加相对的方式计算哈希值,因为“相似”与否,就是一种相对的判定。
- aHash:平均值哈希。速度比较快,但是常常不太精确。
- pHash:感知哈希。精确度比较高,但是速度方面较差一些。
- dHash:差异值哈希。精确度较高,且速度也非常快
注意: 但是在下面我用了ahash和dhash得到的哈希值都是一样的,我就有点懵逼了!!!
计算图片的hanming距离步骤(代码里面有介绍):
- 先将图片压缩成8*8的小图
- 将图片转化为灰度图
- 计算图片的Hash值,这里的hash值是64位,或者是32位01字符串
- 将上面的hash值转换为16位的
- 通过hash值来计算汉明距离
给出图片:
img1: img2:
# -*- coding: utf-8 -*-
# !/usr/bin/env python
# @Time : 2018/11/16 15:40
# @Author : xhh
# @Desc : 图片的hash算法
# @File : image_3hash.py
# @Software: PyCharm
import cv2
# 均值哈希算法
def ahash(image):
# 将图片缩放为8*8的
image = cv2.resize(image, (8,8), interpolation=cv2.INTER_CUBIC)
# 将图片转化为灰度图
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# s为像素和初始灰度值,hash_str为哈希值初始值
s = 0
ahash_str = ''
# 遍历像素累加和
for i in range(8):
for j in range(8):
s = s+gray[i, j]
# 计算像素平均值
avg = s/64
# 灰度大于平均值为1相反为0,得到图片的平均哈希值,此时得到的hash值为64位的01字符串
ahash_str = ''
for i in range(8):
for j in range(8):
if gray[i,j]>avg:
ahash_str = ahash_str + '1'
else:
ahash_str = ahash_str + '0'
result = ''
for i in range(0, 64, 4):
result += ''.join('%x' % int(ahash_str[i: i + 4], 2))
# print("ahash值:",result)
return result
# 差异值哈希算法
def dhash(image):
# 将图片转化为8*8
image = cv2.resize(image,(9,8),interpolation=cv2.INTER_CUBIC )
# 将图片转化为灰度图
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
dhash_str = ''
for i in range(8):
for j in range(8):
if gray[i,j]>gray[i, j+1]:
dhash_str = dhash_str + '1'
else:
dhash_str = dhash_str + '0'
result = ''
for i in range(0, 64, 4):
result += ''.join('%x'%int(dhash_str[i: i+4],2))
# print("dhash值",result)
return result
# 计算两个哈希值之间的差异
def campHash(hash1, hash2):
n = 0
# hash长度不同返回-1,此时不能比较
if len(hash1) != len(hash2):
return -1
# 如果hash长度相同遍历长度
for i in range(len(hash1)):
if hash1[i] != hash2[i]:
n = n+1
return n
img1 = "../doraemon/image-003.png"
img2 = "../doraemon/image-019.jpg"
img1 = cv2.imread(img1)
img2 = cv2.imread(img2)
hash1 = ahash(img1)
print('img1的ahash值',hash1)
hash2= dhash(img1)
print('img1的dhash值',hash2)
hash3= ahash(img2)
print('img2的ahash值',hash3)
hash4= dhash(img2)
print('img2的dhash值',hash4)
camphash1 = campHash(hash1, hash3)
camphash2= campHash(hash2, hash4)
print("ahash均值哈希相似度:",camphash1)
print("dhash差异哈希相似度:",camphash2)
运行结果:
还有一种计算汉明距离的方法,对两者方法都试了一次,一样的:
# -*- coding: utf-8 -*-
# !/usr/bin/env python
# @Time : 2018/11/17 9:57
# @Author : xhh
# @Desc : 图片hash值,与汉明距离的计算
# @File : image_phash1.py
# @Software: PyCharm
import numpy as py
import cv2
# 计算hash值
def p_pash(path):
# 读取图片
src = cv2.imread(path, 0)
# 将图片压缩为8*8的,并转化为灰度图
img = cv2.resize(src, (8,8), cv2.COLOR_RGB2GRAY)
# 计算图片的平均灰度值
avg = sum([sum(img[i]) for i in range(8)])/64
# 计算哈希值,与平均值比较生成01字符串
str = ''
for i in range(8):
str += ''.join(map(lambda i: '0' if i< avg else '1', img[i]))
# 计算hash值, 将64位的hash值,每4位合成以为,转化为16 位的hash值
result = ''
for i in range(0, 64, 4):
result += ''.join('%x'%int(str[i: i+4], 2))
print(result)
return result
# 计算汉明距离
def hamming_distance(str1, str2):
if len(str1) != len(str2):
return
count = 0
for i in range(len(str1)):
if str1[i] != str2[i]:
count += 1
return count
h1 = p_pash('../cat1/cat.1.jpg')
h2 = p_pash('../doraemon/image-003.png')
h3 = p_pash('../doraemon/image-019.jpg')
print(hamming_distance(h1, h2))
print(hamming_distance(h1, h3))
print(hamming_distance(h2, h3))
运行结果: