有时候我们想要计算两张图片是否相似,而用来衡量两张图片相似度的算法也有很多,例如:RMSE
、PSNR
、SSIM
、UQI
、SIFT
以及深度学习
等。这篇文章主要介绍,RMSE
、PSNR
、SSIM
、UQI
这些指标的计算和应用,关于SIFT
算法来计算图像的相似度在后面的文章中再进行介绍
影响这些算法的结果也有很多因素,图片的噪声
、平移
、缩放
、旋转
、裁剪
、透视变换
等,都会影响到算法的最终结果,所以我们需要根据不同的应用场景来选择使用不同的算法
MSE
(mean squared error):图像像素值的平方误差
RMSE
(root mean squared error):图像像素值的平方根误差
def mean_squared_error(img1,img2):
#判断两张图片的shape是否一致
assert img1.shape == img2.shape,"images have different shape " \
"{} and {}".format(img1.shape,img2.shape)
#计算两张图像的MSE
img_mse = np.mean((img1.astype(np.float64) - img2.astype(np.float64))**2)
#将图像的MSE量化为相似度
img_sim = img_mse / (255**2)
return img_mse,1 - img_sim
def root_mean_squared_error(img1,img2):
#判断两张图片的shape是否一致
assert img1.shape == img2.shape,"images have different shape " \
"{} and {}".format(img1.shape,img2.shape)
#计算两张图像的MSE
img_rmse = np.sqrt(np.mean((img1.astype(np.float64) - img2.astype(np.float64))**2))
#将图像的MSE量化为相似度
img_sim = img_rmse / 255
return img_rmse,1 - img_sim
print(mean_squared_error(img1,img2))
#(10826.879833697936, 0.8334966576901509)
print(root_mean_squared_error(img1,img2))
#(104.05229374549096, 0.5919517892333688)
PSNR
(Peak Signal Noise Ratio)也叫峰值信噪比
:为了衡量处理后图像的品质,我们经常会使用到PSNR来衡量程序的处理结果是否令人满意。它是原图像与被处理图像之间的均方误差相对于 ( 2 n − 1 ) 2 (2^n-1)^2 (2n−1)2的对数值(信号最大值的平方,n是每个采样值的比特数),计算公式如下:
P S N R = 10 ∗ l o g 10 ( 2 n − 1 ) 2 M S E PSNR = 10 * log_{10}\frac{(2^n-1)^2}{MSE} PSNR=10∗log10MSE(2n−1)2
缺点
PSNR的分数无法和人眼看到的品质完全一致
优点
算法简单,应用广泛
适用场景
用来评价画质客观量的测法,也可以用于图像相似的计算
代码实现
def peak_signal_noise_ratio(img1,img2):
#判断两张图片的size是否一致
assert img1.shape == img2.shape,"images hava different shape " \
"{} and {}".format(img1.shape,img2.shape)
#获取数据类型所表示的最大值
MAX = np.iinfo(img1.dtype).max
#计算两张图片的MSE
mse,_ = mean_squared_error(img1,img2)
#计算两张图片的PSNR
psnr = 10 * np.log10(MAX**2 / mse)
return psnr
print(peak_signal_noise_ratio(img1,img2))
#49.24985796979349
注
:由于PSNR
的取值范围在(0,inf),PSNR的值越大表示图像越相似
。如果想要将PSNR指标量化为相似度,可以基于测试图片上设置一个最大的PSNR值,进行取最大操作来换算成相似度
SSIM
(structural similarity index)结构相似性:是一种用来衡量两张图像相似程度的指标。当两张图像其中有一张为无失真图像,另一张为失真后的图像,两张图像的结构相似性
可以看做是失真图像的品质质量指标。结构相似性相对于峰值信噪比而言,结构相似性指标在图像品质的衡量上更能符合人眼对图像品质的判断。
以 x x x和 y y y两个信号为例,结构相似性的计算公式如下:
S S I M ( x , y ) = ( l ( x , y ) ) α ( c ( x , y ) ) β ( s ( x , y ) ) γ l ( x , y ) = 2 μ x μ y + C 1 μ x 2 + μ y 2 + C 1 c ( x , y ) = 2 δ x δ y + C 2 δ x 2 + δ y 2 + C 2 s ( x , y ) = δ x y + C 3 δ x δ y + C 3 \begin{aligned} SSIM(x,y) &= (l(x,y))^\alpha(c(x,y))^\beta(s(x,y))^\gamma \\ l(x,y) &= \frac{2\mu_x\mu_y + C_1}{\mu_x^2+\mu_y^2+C_1} \\ c(x,y) &= \frac{2\delta_x\delta_y + C_2}{\delta_x^2+\delta_y^2+C_2}\\ s(x,y) &= \frac{\delta_{xy}+C_3}{\delta_x\delta_y+C_3} \end{aligned} SSIM(x,y)l(x,y)c(x,y)s(x,y)=(l(x,y))α(c(x,y))β(s(x,y))γ=μx2+μy2+C12μxμy+C1=δx2+δy2+C22δxδy+C2=δxδy+C3δxy+C3
上式中的 l ( x , y ) l(x,y) l(x,y)比较的是两个信号之间的亮度, c ( x , y ) c(x,y) c(x,y)比较的是两个信号的对比度, s ( x , y ) s(x,y) s(x,y)比较的是两个信号的结构,其中 α > 0 , β > 0 , γ > 0 \alpha > 0,\beta > 0,\gamma > 0 α>0,β>0,γ>0主要是用来调整 l ( x , y ) 、 c ( x , y ) 、 s ( x , y ) l(x,y)、c(x,y)、s(x,y) l(x,y)、c(x,y)、s(x,y)的重要性, μ x 和 μ y \mu_x和\mu_y μx和μy表示的是信号的平均值, δ x 和 δ y \delta_x和\delta_y δx和δy表示的是信号的标准差,而 δ x y \delta_{xy} δxy为信号的协方差, C 1 、 C 2 、 C 3 C_1、C_2、C_3 C1、C2、C3皆为常数,用来维持 l ( x , y ) 、 c ( x , y ) 、 s ( x , y ) l(x,y)、c(x,y)、s(x,y) l(x,y)、c(x,y)、s(x,y)的稳定,SSIM的值越大,表示两个信号之间的相似度越高
在计算图像结构相似性的时候,我们一般会将参数设为 α = β = γ = 1 以 及 C 3 = C 2 / 2 \alpha=\beta=\gamma=1以及C_3=C_2/2 α=β=γ=1以及C3=C2/2所以 S S I M SSIM SSIM最终的公式就变成了下式
S S I M ( x , y ) = ( 2 μ x μ y + C 1 ) ( 2 δ x y + C 2 ) ) ( μ x 2 + μ y 2 + C 1 ) ( δ x 2 + δ y 2 + C 2 ) SSIM(x,y) = \frac{(2\mu_x\mu_y+C_1)(2\delta_{xy}+C_2))}{(\mu_x^2+\mu_y^2+C_1)(\delta_x^2+\delta_y^2+C_2)} SSIM(x,y)=(μx2+μy2+C1)(δx2+δy2+C2)(2μxμy+C1)(2δxy+C2))
通常在计算图像的 S S I M SSIM SSIM的时候,我们都会采用移动的filter
来进行计算
from scipy import signal
from enum import Enum
def filter2(img,fltr,mode='same'):
return signal.convolve2d(img, np.rot90(fltr,2), mode=mode)
def _get_sums(GT,P,win,mode='same'):
mu1,mu2 = (filter2(GT,win,mode),filter2(P,win,mode))
return mu1*mu1, mu2*mu2, mu1*mu2
def _get_sigmas(GT,P,win,mode='same',**kwargs):
if 'sums' in kwargs:
GT_sum_sq,P_sum_sq,GT_P_sum_mul = kwargs['sums']
else:
GT_sum_sq,P_sum_sq,GT_P_sum_mul = _get_sums(GT,P,win,mode)
return filter2(GT*GT,win,mode) - GT_sum_sq,\
filter2(P*P,win,mode) - P_sum_sq, \
filter2(GT*P,win,mode) - GT_P_sum_mul
class Filter(Enum):
UNIFORM = 0
GAUSSIAN = 1
def fspecial(fltr,ws,**kwargs):
if fltr == Filter.UNIFORM:
return np.ones((ws,ws))/ ws**2
elif fltr == Filter.GAUSSIAN:
x, y = np.mgrid[-ws//2 + 1:ws//2 + 1, -ws//2 + 1:ws//2 + 1]
g = np.exp(-((x**2 + y**2)/(2.0*kwargs['sigma']**2)))
g[ g < np.finfo(g.dtype).eps*g.max() ] = 0
assert g.shape == (ws,ws)
den = g.sum()
if den !=0:
g/=den
return g
return None
def _ssim_single(GT, P, ws, C1, C2, fltr_specs, mode):
win = fspecial(**fltr_specs)
GT_sum_sq, P_sum_sq, GT_P_sum_mul = _get_sums(GT, P, win, mode)
sigmaGT_sq, sigmaP_sq, sigmaGT_P = _get_sigmas(GT, P, win, mode, sums=(GT_sum_sq, P_sum_sq, GT_P_sum_mul))
assert C1 > 0
assert C2 > 0
ssim_map = ((2 * GT_P_sum_mul + C1) * (2 * sigmaGT_P + C2)) / (
(GT_sum_sq + P_sum_sq + C1) * (sigmaGT_sq + sigmaP_sq + C2))
cs_map = (2 * sigmaGT_P + C2) / (sigmaGT_sq + sigmaP_sq + C2)
return np.mean(ssim_map), np.mean(cs_map)
def ssim(GT,P,ws=11,K1=0.01,K2=0.03,MAX=None,fltr_specs=None,mode='valid'):
if MAX is None:
MAX = np.iinfo(GT.dtype).max
assert GT.shape == P.shape, "Supplied images have different sizes " + \
str(GT.shape) + " and " + str(P.shape)
if fltr_specs is None:
fltr_specs=dict(fltr=Filter.UNIFORM,ws=ws)
C1 = (K1*MAX)**2
C2 = (K2*MAX)**2
ssims = []
css = []
for i in range(GT.shape[2]):
ssim,cs = _ssim_single(GT[:,:,i],P[:,:,i],ws,C1,C2,fltr_specs,mode)
ssims.append(ssim)
css.append(cs)
return np.mean(ssims),np.mean(css)
img_sim,_ = ssim(img1,img2)
#0.9459787655432684
UQI
(Universal Quality Image Index)也叫图像通用质量指标
:它能够很容易的计算并且应用到各种图像处理的应用中,主要结合三个因素来计算,相关性的损失
、亮度失真
、对比度失真
。尽管UQI
指标是从数学的角度来定义的不是利用人类的视觉系统,但是通过各种各样的图像失真表明UQI与主观质量测量有着惊人的一致性
。
UQI
指标的计算公式如下:
Q = 4 δ x y x ^ y ^ ( δ x 2 + δ y 2 ) [ ( x ^ ) 2 + ( y ^ ) 2 ] x ^ = 1 N ∑ i = 1 N x i y ^ = 1 N ∑ i = 1 N y i δ x 2 = 1 N − 1 ∑ i = 1 N ( x i − x ^ ) 2 δ y 2 = 1 N − 1 ∑ i = 1 N ( y i − y ^ ) 2 \begin{aligned} Q &= \frac{4\delta_{xy}\hat{x}\hat{y}}{(\delta^2_x+\delta^2_y)[(\hat{x})^2+(\hat{y})^2]} \\ \hat{x} &= \frac{1}{N}\sum_{i=1}^{N}x_i \\ \hat{y} &= \frac{1}{N}\sum_{i=1}^{N}y_i \\ \delta_{x}^2 &= \frac{1}{N - 1}\sum_{i=1}^{N}(x_i-\hat{x}) ^2\\ \delta_{y}^2 &= \frac{1}{N - 1}\sum_{i=1}^{N}(y_i - \hat{y})^2 \end{aligned} Qx^y^δx2δy2=(δx2+δy2)[(x^)2+(y^)2]4δxyx^y^=N1i=1∑Nxi=N1i=1∑Nyi=N−11i=1∑N(xi−x^)2=N−11i=1∑N(yi−y^)2
Q
的取值范围在[-1,1]之间
import numpy as np
from scipy.ndimage import uniform_filter
def _uqi_single(GT,P,ws):
N = ws**2
window = np.ones((ws,ws))
GT_sq = GT*GT
P_sq = P*P
GT_P = GT*P
GT_sum = uniform_filter(GT, ws)
P_sum = uniform_filter(P, ws)
GT_sq_sum = uniform_filter(GT_sq, ws)
P_sq_sum = uniform_filter(P_sq, ws)
GT_P_sum = uniform_filter(GT_P, ws)
GT_P_sum_mul = GT_sum*P_sum
GT_P_sum_sq_sum_mul = GT_sum*GT_sum + P_sum*P_sum
numerator = 4*(N*GT_P_sum - GT_P_sum_mul)*GT_P_sum_mul
denominator1 = N*(GT_sq_sum + P_sq_sum) - GT_P_sum_sq_sum_mul
denominator = denominator1*GT_P_sum_sq_sum_mul
q_map = np.ones(denominator.shape)
index = np.logical_and((denominator1 == 0) , (GT_P_sum_sq_sum_mul != 0))
q_map[index] = 2*GT_P_sum_mul[index]/GT_P_sum_sq_sum_mul[index]
index = (denominator != 0)
q_map[index] = numerator[index]/denominator[index]
s = int(np.round(ws/2))
return np.mean(q_map[s:-s,s:-s])
def uqi (GT,P,ws=8):
if len(GT.shape) == 2:
GT = GT[:, :, np.newaxis]
P = P[:, :, np.newaxis]
GT = GT.astype(np.float64)
P = P.astype(np.float64)
return np.mean([_uqi_single(GT[:,:,i],P[:,:,i],ws) for i in range(GT.shape[2])])
除了上面的图像相似度评估指标之外,Sewar还提供了很多其他的图像质量评估指标算法,例如:MS-SSIM
、ERGAS
、SCC
、RASE
、SAM
、D_lambda
、D_S
、QNR
、VIF
以及PSNR-B
。
下面我们来对比一下一些常用指标在添加不同噪声的情况下,计算出来的相似度结果之间的差异
给图片添加噪声可以参考我的这篇文章对图像添加(高斯/椒盐/泊松/斑点)噪声
评估算法 | 原图像 | 高斯噪声 | 高斯模糊 | 泊松噪声 | 椒盐噪声 | 散斑噪声 |
---|---|---|---|---|---|---|
MSE | 0.00 | 548.66 | 79.78 | 0.77 | 885.12 | 10826.88 |
RMSE | 0.00 | 23.42 | 8.93 | 0.88 | 29.75 | 104.05 |
PSNR | inf | 20.74 | 29.11 | 49.25 | 18.66 | 7.79 |
SSIM | 1.00 | 0.25 | 0.94 | 0.99 | 0.45 | 0.06 |
UQI | 1.00 | 0.98 | 0.99 | 1.00 | 0.98 | 0.80 |
MS-SSIM | 1.00+0.00j | 0.76+0.00j | 0.98+0.00j | 1.00+0.00j | 0.86+0.00j | 0.32+0.00j |
ERGAS | 0.00 | 8031.33 | 2322.77 | 225.79 | 11187.33 | 26741.73 |
SCC | 0.89 | 0.08 | 0.17 | 0.48 | 0.35 | 0.02 |
RASE | 0.00 | 1158.13 | 333.25 | 32.21 | 1600.90 | 3814.14 |
SAM | 0.00 | 0.13 | 0.05 | 0.00 | 0.13 | 0.58 |
D_lambda | 0.00 | 0.02 | 0.00 | 0.00 | 0.03 | 0.20 |
VIFP | 1.00 | 0.23 | 0.49 | 0.93 | 0.44 | 0.06 |
PSNR-B | inf | 20.70 | 28.93 | 49.59 | inf | 8.10 |