Python计算两张图片的相似度

  • Post author:
  • Post category:python




一、场景需求解读

在现实场景中,我们经常会遇到一个问题,

即如何评价不同图片的好坏,或者如何比较两张图片的相似性

。它在学术研究领域中具有的广泛的研究前景,例如当你提出来一种新的图像增强算法,算法最终会输出增强之后的结果,为了比较不同算法的性能,我们通常需要使用一个指标来解决这个问题,常用的思路是使用MSE或者SSIM来比较标签和不同算法预测的结果,然后根据指标的大小来判断不同算法的好坏。



二、Mean Squared Error (MSE)简介


MSE,即均方误差,它是一个用来计算两张图片相似度的一个指标值,该值越小表示两张图像越相似

,它在学术领域中得到了广泛的应用,它的计算公式为:



M

S

E

=

1

m

n

i

=

0

m

1

j

=

0

n

1

[

I

(

i

,

j

)

K

(

i

,

j

)

]

2

M S E=\frac{1}{m n} \sum_{i=0}^{m-1} \sum_{j=0}^{n-1}[I(i, j)-K(i, j)]^{2}






MSE




=




















mn
















1




































i


=


0










m





1


































j


=


0










n





1



















[


I


(


i


,




j


)













K


(


i


,




j


)



]











2













,其中m和n分别表示图像的宽和高,I和K分别表示两张测试图片对应的像素值,

即将两张测试图片对应的位置的像素值相减然后将结果累积起来即可

。具体的代码实现如下所示:

def mse(imageA, imageB):
	# 计算两张图片的MSE相似度
	# 注意:两张图片必须具有相同的维度,因为是基于图像中的对应像素操作的
    # 对应像素相减并将结果累加起来
	err = np.sum((imageA.astype("float") - imageB.astype("float")) ** 2)
	# 进行误差归一化
	err /= float(imageA.shape[0] * imageA.shape[1])
	
	# 返回结果,该值越小越好,越小说明两张图像越相似
	return err


MSE的实现起来非常简单,但是当使用它进行相似性判断时,我们可能会遇到一些问题。主要问题是,像素强度之间的差距比较大并不一定意味着图像的内容有很大的差异

。需要注意的是,MSE值为0时表示两张图像完全相似,大于1时意味着两张图片相似度较低,并将随着像素强度之间的平均差异的增加而继续增长。



三、The Structural Similarity Index (SSIM)简介

尽管MSE实现起来十分简单,但是该评价指标中存在着较大的问题。为了更好的判断两份图片的相似度,学者们提出了SSMI指标,

该指标能够更好的反应出两张图片的相似度,该指标的范围是[-1,1],当SSIM=-1时表示两张图片完全不相似,当SSIM=1时表示两张图片非常相似。即该值越接近1说明两张图片越相似

。该指标的计算公式如下所示:



SSIM

(

x

,

y

)

=

(

2

μ

x

μ

y

+

c

1

)

(

2

σ

x

y

+

c

2

)

(

μ

x

2

+

μ

y

2

+

c

1

)

(

σ

x

2

+

σ

y

2

+

c

2

)

\operatorname{SSIM}(x, y)=\frac{\left(2 \mu_{x} \mu_{y}+c_{1}\right)\left(2 \sigma_{x y}+c_{2}\right)}{\left(\mu_{x}^{2}+\mu_{y}^{2}+c_{1}\right)\left(\sigma_{x}^{2}+\sigma_{y}^{2}+c_{2}\right)}







SSIM



(


x


,




y


)




=






















(




μ











x










2



















+



μ











y










2



















+



c











1




















)






(




σ











x










2



















+



σ











y










2



















+



c











2




















)




















(



2



μ











x




















μ











y



















+



c











1




















)






(



2



σ











x


y



















+



c











2




















)


























,其中



μ

x

\mu_{x}







μ











x






















表示图像中NxN区域中x方向的均值,



σ

x

\sigma_{x}







σ











x






















表示NxN区域中x方向的方差,c1和c2分别表示两张测试图片的像素强度平均值 ,



σ

x

y

\sigma_{x y}







σ











x


y






















表示x和y方向的协方差值。

SSIM方法显然比MSE方法更为复杂,SSIM试图模拟图像结构信息中感知到的变化,而MSE实际上是估计感知到的误差。两者之间有着细微的差别,但结果上的差异还是比较大的。此外,

上式中的公式用于比较两个窗口(即小的子样本),而不是像MSE那样比较整个图像。这种方法能够解释图像结构的变化,而不仅仅是感知到的变化



Scikit-image中已经实现了该指标,本文将使用实现好的SSIM指标。



四、算法代码实现

# coding=utf-8
# 导入python包
from skimage.measure import compare_ssim as ssim
import matplotlib.pyplot as plt
import numpy as np
import cv2

def mse(imageA, imageB):
	# 计算两张图片的MSE指标
	err = np.sum((imageA.astype("float") - imageB.astype("float")) ** 2)
	err /= float(imageA.shape[0] * imageA.shape[1])
	
	# 返回结果,该值越小越好
	return err

def compare_images(imageA, imageB, title):
	# 分别计算输入图片的MSE和SSIM指标值的大小
	m = mse(imageA, imageB)
	s = ssim(imageA, imageB)

	# 创建figure
	fig = plt.figure(title)
	plt.suptitle("MSE: %.2f, SSIM: %.2f" % (m, s))

	# 显示第一张图片
	ax = fig.add_subplot(1, 2, 1)
	plt.imshow(imageA, cmap = plt.cm.gray)
	plt.axis("off")

	# 显示第二张图片
	ax = fig.add_subplot(1, 2, 2)
	plt.imshow(imageB, cmap = plt.cm.gray)
	plt.axis("off")
	plt.tight_layout()
	plt.show()



# 读取图片
original1 = cv2.imread("test3.jpg")
contrast1 = cv2.imread("test3_adjust1.jpg")
shopped1 = cv2.imread("test2.jpg")

# 将彩色图转换为灰度图
original = cv2.cvtColor(original1, cv2.COLOR_BGR2GRAY)
contrast = cv2.cvtColor(contrast1, cv2.COLOR_BGR2GRAY)
shopped = cv2.cvtColor(shopped1, cv2.COLOR_BGR2GRAY)

# 初始化figure对象
fig = plt.figure("Images")
images = ("Original", original), ("Enhance", contrast), ("Others", shopped)

# 遍历每张图片
for (i, (name, image)) in enumerate(images):
	# 显示图片
	ax = fig.add_subplot(1, 3, i + 1)
	ax.set_title(name)
	plt.imshow(image, cmap = plt.cm.gray)
	plt.axis("off")
plt.tight_layout()
plt.show()

# 比较图片
compare_images(original, original, "Original vs Original")
compare_images(original, contrast, "Original vs Enhance")
compare_images(original, shopped, "Original vs Others")



五、效果展示与分析

在这里插入图片描述

上图展示了不同指标在不同测试图片上面的测试效果。每一行表示不同的测试样本,第1列表示的是第一个测试样例的三种情况,第1行第1列表示输入的两张图片都是同一张图片的情况;第2行第1列表示输入一张原图和一张经过变换的图片的情况;第3行第1列表示输入两张不同的测试图片的情况。每张图片的上方都展示了不同情况下两种不同指标的计算结果,即MSE:xxx,SSIM:xxx。通过观察上图,我们可以获得一些信息,即当输入两张相同的照片时,对应到图中的第一行,我们可以观察到不同指标的输出结果为MSE=0,SSIM=1,即两种评价指标都认为这两张图片很相似;当输入一张原图和一张变换后的图像后,对应到图中的第二行,我们可以观察到不同指标的输出结果为MSE对于不同的图片会有较大的差异,SSIM基本上都在0.9以上,即SSIM指标认为这两张图片仍然很相似;当输入两张不同的图片时,对应到图中的第三行,我们可以观察到不同指标输出的结果为MSE=6277.42,SSIM=0.50,即两种指标都认为这两张图片不相似。



六、思维扩展

尽管MSE和SSIM在很多情况下可以很好的判断出两张图片的相似度,但是在某些情况下这两个指标都不能很好的去判断两张图片的相似性,主要的原因是因为这两个指标都是人为设计的,都是根据人的理解来定义两张图片的相似度的。随着深度学习技术的快速发展,

诞生了一种判断两张图片相似度的网络,即孪生网络(Siamese Network),该网络的主要思路是分别在两个分支中获取不同测试图片的特征,然后使用欧氏距离等指标来比较这两个特征的相似性

,该网络当前已经可以获得较高的精度,聪明的你不妨去仔细的了解一下它。



参考资料

[1]

参考资料



注意事项

[1] 如果您对AI、自动驾驶、AR、ChatGPT等技术感兴趣,欢迎关注我的微信公众号“

AI产品汇

”,有问题可以在公众号中私聊我!

[2] 该博客是本人原创博客,如果您对该博客感兴趣,想要转载该博客,请与我联系(qq邮箱:1575262785@qq.com),我会在第一时间回复大家,谢谢大家的关注.

[3] 由于个人能力有限,该博客可能存在很多的问题,希望大家能够提出改进意见。

[4] 如果您在阅读本博客时遇到不理解的地方,希望您可以联系我,我会及时的回复您,和您交流想法和意见,谢谢。

[5] 本文测试的图片可以通过关注微信公众号

AI产品汇

之后找我索取!

[6]

本人业余时间承接各种本科毕设设计和各种小项目,包括图像处理(数据挖掘、机器学习、深度学习等)、matlab仿真、python算法及仿真等,有需要的请加QQ:1575262785详聊!!!



版权声明:本文为WZZ18191171661原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。