图像质量评估方法及代码

ZhuYuanxiang 2023-02-14 11:48:04
Categories: Tags:

图像质量评估方法及代码

均方根误差(RMSE)

均方误差(Mean Square Error)反映的是变量间的差异程度,是一种基于像素误差的图像质量客观评价指标,用于衡量融合图像和理想参考图像之间的差异,MSE越小,表示融合图像质量越好。

给定一个大小为 $m\times n$ 的干净图像 $I$ 和噪声图像 $K$,均方误差(MSE, Mean Squared Error)定义为:
$$
\text{MSE}=\frac1{mn}\sum_{i=0}^{m-1}\sum_{j=0}^{n-1}[I(i,j)-K(i,j)]^2
$$

均方根误差(Root Mean Square Error)是一个翻译空间细节信息的评价指标
$$
RMSE(I,K)=\sqrt{MSE(I,K)}
$$

归一化均方根误差 NRMSE

归一化均方根误差(normalized root mean square error)就是将RMSE的值变成(0,1)之间。

峰值信噪比(PSNR)

PSNR(Peak Signal to Noise Ratio),峰值信噪比,即峰值信号的能量与噪声的平均能量之比,通常表示的时候取 $\log$ 变成分贝(dB),由于 MSE 为真实图像与含噪图像之差的能量均值,而两者的差即为噪声,因此 PSNR 即峰值信号能量与 MSE 之比。

PSNR的计算公式

PSNR(dB) 的定义为:
$$
\begin{align}
\text{PSNR}
&=10\cdot\log_{10}(\frac{(MAX_I)^2}{MSE})\
&=20\cdot\log_{10}(\frac{MAX_I}{\sqrt{MSE}})\
&=20\cdot\log_{10}(MAX_I)-10\cdot\log_{10}(MSE)
\end{align}
$$
其中,$MAX_I$ 为图片可能的最大像素值。如果每个像素都由8位二进制来表示,那么就为255。一般情况,如果像素值由$B$位二进制来表示,那么$MAX_I=2^B-1$。

通常情况下,面对 uint8 数据,最大像素值为255;面对浮点型数据,最大像素值为1。

上面是灰度图像的计算方法,下面是彩色图像的三种计算方法:

PSNR的数值意义

图像与影像压缩中典型的峰值信噪比值在30dB~50dB,愈高愈好。

PSNR的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
import cv2
max_pixel = 255

# im1 和 im2 都为灰度图像,uint8 类型
im1=cv2.imread(im1_file)
im2=cv2.imread(im2_file)

# method 1
diff = im1 - im2
mse = np.mean(np.square(diff))
psnr = 10 * np.log10(max_pixel * max_pixel / mse)

# method 2
psnr = skimage.measure.compare_psnr(im1, im2, max_pixel)

PSNR的补充

针对超光谱图像,我们需要针对不同波段分别计算 PSNR,然后取平均值,这个指标称为 MPSNR。

结构相似性(SSIM)

结构相似性(SSIM,Structural Similarity Index Measure),假设自然图像是高度结构化的,即在自然图像中相邻像素之间有很强的关联性,并且这样的关联性承载了场景中物体的结构信息。人类视觉系统在观看图像时已经习惯抽取这样的结构性信息。因此,结构性失真就成为图像评价的重要指标。

作为结构相似性理论的实现,结构相似度指数从图像组成的角度将结构信息定义为独立于亮度、对比度的,反映场景中物体结构的属性,并将失真建模为**亮度(luminance)、对比度(contrast)和结构(structure)**三个不同因素的组合。用均值作为亮度的估计,标准差作为对比度的估计,协方差作为结构相似程度的度量。

Original image, Image with noise, Image plus constant

SSIM的计算公式

给定两个信号$\mathbf{x}$和$\mathbf{y}$,两者的结构相似性定义为:
$$
\begin{align}
SSIM(\mathbf{x,y})&=
[l(\mathbf{x,y})]^\alpha
[c(\mathbf{x,y})]^\beta]
[s(\mathbf{x,y})]^\gamma\
l(\mathbf{x,y})&=\frac{2\mu_x\mu_y+C_1}{\mu_x^2+\mu_y^2+C_1}\
c(\mathbf{x,y})&=\frac{2\sigma_x\sigma_y+C_2}{\sigma_x^2+\sigma_y^2+C_2}\
s(\mathbf{x,y})&=\frac{\sigma_{xy}+C_3}{\sigma_x\sigma_y+C_3}
\end{align}
$$

其中,

结构相似性指标的值越大,代表两个信号的相似性越高。

SSIM的使用

实际使用时,为了简化起见,一般将$\alpha=1,\beta=1,\gamma=1,C_1=(k_1,L)^2,C_2=(k_2,L),C_3=C_2/2$得
$$
SSIM(x,y)=\frac{(2\mu_x\mu_y+C_1)(2\sigma_{xy}+C_2)}
{(\mu_x^2+\mu_y^2+C_1)(\sigma_x^2+\sigma_y^2+C_2)}
$$
每次计算的时候都从图片中取一个$N\times N$的窗口,然后不断滑动窗口进行计算,最后取平均值作为全局的SSIM。

SSIM的代码

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np
import cv2
from skimage.metrics import structural_similarity as ssim_func
from skimage.metrics import mean_squared_error as mse_func
max_pixel = 255

# im1 和 im2 都为灰度图像,uint8 类型
im1=cv2.cvtColor(cv2.imread(im1_file),cv2.COLOR_BGR2GRAY)
im2=cv2.cvtColor(cv2.imread(im2_file),cv2.COLOR_BGR2GRAY)

mse = mse_func(im1, im2)
ssim = ssim_func(im1, im2, data_range=max_pixel)

SSIM的补充

针对超光谱图像,我们需要针对不同波段分别计算 SSIM,然后取平均值,这个指标称为 MSSIM。

信息熵(entropy)

信息熵主要是度量图像包含信息量多少的一个客观评价指标,$a$表示灰度值,$P(a)$表示灰度概率分布,信息熵为:
$$
H(A)=-\sum_a P_A(a)\log p_A(a)
$$
信息熵越高表示整合图像的信息量越丰富,质量越好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import numpy as np
import math
import cv2
import os
from skimage.measure import compare_ssim
import skimage.measure
# 峰值信噪比
def psnr(target, ref):
#将图像格式转为float64
target_data = np.array(target, dtype=np.float64)
ref_data = np.array(ref,dtype=np.float64)
# 直接相减,求差值
diff = ref_data - target_data
# 按第三个通道顺序把三维矩阵拉平
diff = diff.flatten('C')
# 计算MSE值
rmse = math.sqrt(np.mean(diff ** 2.))
# 精度
eps = np.finfo(np.float64).eps
if(rmse == 0):
rmse = eps
psnr=20*math.log10(255.0/rmse)
return psnr
# 结构相似性
def ssim(imageA, imageB):
# 为确保图像能被转为灰度图
imageA = np.array(imageA, dtype=np.uint8)
imageB = np.array(imageB, dtype=np.uint8)

# 通道分离,注意顺序BGR不是RGB
(B1, G1, R1) = cv2.split(imageA)
(B2, G2, R2) = cv2.split(imageB)

# convert the images to grayscale BGR2GRAY
grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)

# 方法一
#直接转换为灰度图,计算ssim
(grayScore, diff) = compare_ssim(grayA, grayB, full=True)
diff = (diff * 255).astype("uint8")
# print("gray SSIM: {}".format(grayScore))

# 方法二
#分离每个通道,计算ssim,再求平均值
(score0, diffB) = compare_ssim(B1, B2, full=True)
(score1, diffG) = compare_ssim(G1, G2, full=True)
(score2, diffR) = compare_ssim(R1, R2, full=True)
aveScore = (score0 + score1 + score2) / 3
# print("BGR average SSIM: {}".format(aveScore))

return aveScore
#
##数据集评估####
original_path=r"C:\study_he\exp_result\LOL15\high"
contrast_path=r"C:\study_he\RetinexNet-master\Retinex_n"
psnr_all=0
ssim_all=0
rmse_all=0
nrmse_all=0
entropy_all=0
length=len(os.listdir(original_path))
for file in os.listdir(original_path):
original_img=os.path.join(original_path,file)
contrast_img=os.path.join(contrast_path,file)
original=cv2.imread(original_img)
contrast = cv2.imread(contrast_img, 1)
# 峰值信噪比
psnrValue = psnr(original, contrast)
# 结构相似性
ssimValue = ssim(original, contrast)
# 均方误差
mse = skimage.measure.compare_mse(original, contrast)
# 均方根误差
rmse = math.sqrt(mse)
# 归一化均方根误差
nrmse = skimage.measure.compare_nrmse(original, contrast, norm_type='Euclidean')
# 信息熵
entropy = skimage.measure.shannon_entropy(contrast, base=2)
psnr_all+=psnrValue
ssim_all+=ssimValue
rmse_all+=rmse
nrmse_all+=nrmse
entropy_all+=entropy

psnr_avg=psnr_all/length
ssim_avg=ssim_all/length
rmse_avg=rmse_all/length
nrmse_avg=nrmse_all/length
entropy_avg=entropy_all/length
print(rmse_avg)
print(nrmse_avg)
print(ssim_avg)
print(psnr_avg)
print(entropy_avg)

# #单张图像预测
# original = cv2.imread(r"C:\study_he\exp_result\LOL15\high\780.png") # numpy.adarray
# contrast = cv2.imread(r"C:\study_he\RetinexNet-master\Retinex_n\780.png",1)
# #峰值信噪比
# psnrValue = psnr(original,contrast)
# #结构相似性
# ssimValue = ssim(original,contrast)
# # 均方误差
# mse = skimage.measure.compare_mse(original, contrast)
# # 均方根误差
# rmse = math.sqrt(mse)
# # 归一化均方根误差
# nrmse = skimage.measure.compare_nrmse(original, contrast, norm_type='Euclidean')
# # 信息熵
# entropy = skimage.measure.shannon_entropy(contrast, base=2)
# print(rmse)
# print(nrmse)
# print(ssimValue)
# print(psnrValue)
# print(entropy)

参考文献

(10条消息) 【图像处理】——图像质量评价指标信噪比(PSNR)和结构相似性(SSIM)(含原理和Python代码)_python_AI_fans的博客-CSDN博客_tf.image.psnr

Structural similarity index — skimage v0.19.0.dev0 docs (scikit-image.org)

结构相似性 - 维基百科,自由的百科全书 (wikipedia.org)