【声明】度量两张图片的相似度有许多算法,本文将对常用的图片相似度算法进行汇总。部分数据、资料来源于各技术网站,如有侵权烦请联系删除。
常用的算法有几类:
一、Hash算法
- Hash算法常用的有三种,分别为平均哈希算法(aHash)、感知哈希算法你(pHash)和差异哈哈希算法(dHash);还有一种是小波哈希算法(whash)。
- Hash算法都是通过获取图片的hash值,再比较两张图片hash值的汉明距离来度量两张图片是否相似。两张图片越相似,那么两张图片的hash数的汉明距离越小。
1、aHash-平均哈希
算法步骤
平均哈希算法是三种Hash算法中最简单的一种,它通过下面几个步骤来获得图片的Hash值:
(1) 缩放图片;
(2) 转灰度图;
(3) 算像素均值;
(4) 根据相似均值计算指纹.
得到图片的ahash值后,比较两张图片ahash值的汉明距离,通常认为汉明距离小于10的一组图片为相似图片。
举栗
计算平均值
求得的平均值为152.4375
每个像素点与平均值比较
那么该图片的ahash值即为:1111100011110000111111001111011011100111111011101111000000001000
ahash代码
import cv2
import numpy as np
import copy
def ahash_process(pic_path):
'''
ahash算法过程
:param pic_path: 图片路径
:return:
'''
img = cv2.imread(pic_path, cv2.IMREAD_UNCHANGED)
img_resize = cv2.resize(img, (8, 8), cv2.INTER_AREA)
gray_img = cv2.cvtColor(img_resize, cv2.COLOR_BGR2GRAY)
print('单通道灰度图:', gray_img)
avg = np.mean(gray_img)
print('平均值:', avg)
dis = copy.deepcopy(gray_img)
dis_hash_str = ''
for x_index, x in enumerate(gray_img):
for y_index, y in enumerate(x):
if y >= avg:
dis[x_index, y_index] = 1
else:
dis[x_index, y_index] = 0
dis_hash_str += str(dis[x_index, y_index])
print('与平均值比较:', dis)
print('该图片的ahash值:', dis_hash_str)
cv2.namedWindow('resize', 0)
cv2.resizeWindow('resize', 600, 600)
cv2.imshow('resize', img_resize)
cv2.namedWindow('gray', 0)
cv2.resizeWindow('gray', 600, 600)
cv2.imshow('gray', gray_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
两张图片对比自然需要另外一张图片,同理通过上述方法,计算出hash值后,计算汉明距离即可。
2、dHash-差异哈希
算法步骤
dhash和ahash算法的差别在于,ahash使用每个像素点与平均像素做对比得出布尔值,dhash是使用当前像素与后一个像素点做对比得到布尔值,正是这个原因,所以dhash算法需要将图片缩放为9*8个像素点。
(1)图片缩放为9*8,保留结构,出去细节;
(2)灰度化:转换为256阶灰度图;
(3)求平均值:计算灰度图所有像素的平均值;
(4)比较:像素值大于后一个像素值记作1,相反记作0。本行不与下一行对比,每行9个像素,八个差值,有8行,总共64位 ;
(5)生成hash:将上述步骤生成的1和0按顺序组合起来既是图片的指纹(hash);
举栗
那么该图片的dhash值即为:0011011010111011010110101111001011010011101110011110101111001101
dHash代码
import cv2
def dhash_process(pic_path):
img = cv2.imread(pic_path, cv2.IMREAD_UNCHANGED)
img_resize = cv2.resize(img, (9, 8), cv2.INTER_AREA)
gray_img = cv2.cvtColor(img_resize, cv2.COLOR_BGR2GRAY)
print('单通道灰度图:', gray_img)
dis = [[] for x in range(8)]
dis_hash_str = ''
for row in range(8):
for col in range(8):
if gray_img[row, col] >= gray_img[row, col + 1]:
dis[row].append(1)
dis_hash_str += str(1)
else:
dis[row].append(0)
dis_hash_str += str(0)
print('比较值:', dis)
print('该图片的dhash值:', dis_hash_str)
cv2.namedWindow('resize', 0)
cv2.resizeWindow('resize', 600, 600)
cv2.imshow('resize', img_resize)
cv2.namedWindow('gray', 0)
cv2.resizeWindow('gray', 600, 600)
cv2.imshow('gray', gray_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
3、pHash-感知哈希
算法步骤
dhash是三种Hash算法中较为复杂的一种,它是基于DCT(离散余弦变换)来得到图片的hash值:
(1)缩小图片:32*32是一个较好的大小,这样方便DCT计算;
(2)灰度化:转换为256阶灰度图;
(3)计算DCT:DCT把图片分离成分率的集合,DCT(离散余弦变换);
(4)缩小DCT:DCT计算后的矩阵是32 * 32,保留左上角的8 * 8,这些代表的图片的最低频率;
(5)计算平均值:计算缩小DCT后的所有像素点的平均值;
(6)比较平均值:大于平均值记录为1,反之记录为0,得到phash值。
举栗
得到图片低频DCT
得到低频DCT图:
平均值为:97.10013
低频DCT值与平均值比较
得到phash值为:1110011010100100000010001101001100010000110000001001000000010000
pHash代码
import cv2
import numpy as np
def phash_process(pic_path):
img = cv2.imread(pic_path, cv2.IMREAD_UNCHANGED)
img_resize = cv2.resize(img, (32, 32), cv2.INTER_AREA)
gray_img = cv2.cvtColor(img_resize, cv2.COLOR_BGR2GRAY)
print('单通道灰度图:', gray_img)
gray_img_dct = cv2.dct(np.float32(gray_img))
gray_img_low_dct = gray_img_dct[0:8, 0:8]
print('低频DCT图值:', gray_img_low_dct)
avg = np.mean(gray_img_low_dct)
print('低频DCT图平均值:', avg)
dis = [[] for x in range(8)]
dis_hash_str = ''
for row_index, row in enumerate(gray_img_low_dct):
for col_index, col in enumerate(row):
print(row_index, col_index)
if col >= avg:
dis[row_index].append(1)
dis_hash_str += '1'
else:
dis[row_index].append(0)
dis_hash_str += '0'
print('phash值:', dis_hash_str)
cv2.namedWindow('resize', 0)
cv2.resizeWindow('resize', 600, 600)
cv2.imshow('resize', img_resize)
cv2.namedWindow('gray', 0)
cv2.resizeWindow('gray', 600, 600)
cv2.imshow('gray', gray_img)
cv2.namedWindow('DCT', 0)
cv2.resizeWindow('DCT', 600, 600)
cv2.imshow('DCT', gray_img_dct)
cv2.namedWindow('low_DCT', 0)
cv2.resizeWindow('low_DCT', 600, 600)
cv2.imshow('low_DCT', gray_img_low_dct)
cv2.waitKey(0)
cv2.destroyAllWindows()
二、SSIM算法
SSIM(结构相似性度量),这是一种全参考的图像质量评价指标,分别从亮度、对比度、结构三个方面度量图像相似性。
参考文章:
https://cloud.tencent.com/dev...
https://www.cnblogs.com/Kalaf...
https://blog.csdn.net/u010977...