【Python】图像相似度对比

【声明】度量两张图片的相似度有许多算法,本文将对常用的图片相似度算法进行汇总。部分数据、资料来源于各技术网站,如有侵权烦请联系删除。
常用的算法有几类:

一、Hash算法

  • Hash算法常用的有三种,分别为平均哈希算法(aHash)、感知哈希算法你(pHash)和差异哈哈希算法(dHash);还有一种是小波哈希算法(whash)。
  • Hash算法都是通过获取图片的hash值,再比较两张图片hash值的汉明距离来度量两张图片是否相似。两张图片越相似,那么两张图片的hash数的汉明距离越小。

1、aHash-平均哈希

算法步骤

平均哈希算法是三种Hash算法中最简单的一种,它通过下面几个步骤来获得图片的Hash值:

(1) 缩放图片;

(2) 转灰度图;

(3) 算像素均值;

(4) 根据相似均值计算指纹.

【Python】图像相似度对比
得到图片的ahash值后,比较两张图片ahash值的汉明距离,通常认为汉明距离小于10的一组图片为相似图片。

举栗

我们以一张动物的图片为例,详解ahash算法过程:
原图:
【Python】图像相似度对比

缩放图片
先将图片缩放为8*8的图片,得到下图:
【Python】图像相似度对比

图片灰度
得到灰度图:
【Python】图像相似度对比
得到单通道灰度图的各个像素值
【Python】图像相似度对比

计算平均值
求得的平均值为152.4375

每个像素点与平均值比较
【Python】图像相似度对比
那么该图片的ahash值即为:1111100011110000111111001111011011100111111011101111000000001000

ahash代码

python">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);

举栗

原图:
【Python】图像相似度对比

缩放图片
先将图片缩放为9*8的图片,得到下图:
【Python】图像相似度对比
图片灰度
得到灰度图:
【Python】图像相似度对比

得到单通道灰度图的各个像素值
【Python】图像相似度对比

每个像素点与后面一个像素点比较值
【Python】图像相似度对比

那么该图片的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值。

举栗

原图:
【Python】图像相似度对比

缩放图片
先将图片缩放为32*32的图片,得到下图:
【Python】图像相似度对比

图片灰度
得到灰度图:
【Python】图像相似度对比

计算图片DCT
得到DCT图:
【Python】图像相似度对比

得到图片低频DCT
得到低频DCT图:
【Python】图像相似度对比
低频DCT值:
【Python】图像相似度对比
平均值为: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()

4、wHash-小波哈希

wavelet hash是频表示的另一种形式。whash相当于将phash中的DCT变换改为DWT。
离散小波变换(DWT)是频表示的另一种形式。流行的DCT和傅立叶变换使用余弦函数作为sin\cos的基础:sin(x),sin(2x),sin(3x)等等。与此相反,DWT使用一个单一的功能作为基础,但在不同的形式:缩放和移动。

小波hash在平时用的不多,在此不展开。

以上是所有hash算法的总结

5、彩蛋

那我们在平时使用过程中,是不需要自己手写hash算法过程的。为什么写在最后,其实是想让大家能够耐心看完前面的内容,对算法底层有一定的了解,求不挨打!
有现有的包(imagehash)供大家使用:

pip install imagehash

from imagehash import phash

def image_similar_compare(img1, img2):

# 以phash为栗子,其余hash方法也可以直接引用的

hash1 = phash(Image.open(img1))

hash2 = phash(Image.open(img2))

# 计算汉明距离

return 1 - (hash1 - hash2) / len(hash1.hash) ** 2

二、SSIM算法

SSIM(结构相似性度量),这是一种全参考的图像质量评价指标,分别从亮度、对比度、结构三个方面度量图像相似性。 均值作为亮度的估计,标准差作为对比度的估计,协方差作为结构相似程度的度量。 SSIM取值范围[0,1],值越大,表示图像失真越小,越相似。

计算步骤

在实际应用中,可以利用滑动窗将图像分块,令分块总数为N,考虑到窗口形状对分块的影响,采用高斯加权计算每一窗口的均值、方差以及协方差;然后计算对应块的结构相似度SSIM,最后将平均值作为两图像的结构相似性度量,即平均结构相似性MSSIM。

优点

结构相似度指数从图像组成的角度将结构信息定义为独立于亮度、对比度的反映场景中物体结构的属性,并将失真建模为亮度、对比度和结构三个不同因素的组合。

应用

更多的是应用于同一张照片,在传输过程前后的对比。

【Python】图像相似度对比

【Python】图像相似度对比

参考文章:

https://cloud.tencent.com/dev...
https://www.cnblogs.com/Kalaf...
https://blog.csdn.net/u010977...

以上是 【Python】图像相似度对比 的全部内容, 来源链接: utcz.com/a/74248.html

回到顶部