PSNR(峰值信噪比,Peak Signal-to-Noise Ratio),用于衡量两张图像之间差异,例如压缩图像与原始图像,评估压缩图像质量;复原图像与ground truth,评估复原算法性能等。
公式: P S N R = 10 × l g ( M a x V a l u e 2 M S E ) \mathrm{PSNR}=10 \times lg \left( \frac{\mathrm{MaxValue}^2}{\mathrm{MSE}}\right) PSNR=10×lg(MSEMaxValue2)
其中, M S E \mathrm{MSE} MSE 为两张图像的均方误差; M a x V a l u e \mathrm{MaxValue} MaxValue 为图像像素可取到的最大值,例如 8 位图像为 2 8 − 1 = 255 2^8-1=255 28−1=255 。
代码:
# 直接调库
from skimage.measure import compare_psnr
compare_psnr(img1, img2, 255)
'''
2022-7-28: 更新
skimage.measure.compare_psnr has been moved to skimage.metrics.peak_signal_noise_ratio
'''
from skimage.metrics import peak_signal_noise_ratio as compare_psnr
compare_psnr(img1, img2, data_range=255)
# 自己实现
import numpy as np
def compare_psnr(img1, img2, maxvalue):
'''
一般 opencv 读图是 uint8, 漏掉转数据格式会导致计算出错;
有些代码会在 mse==0 的时候直接返回 100, 但很明显 psnr 并没有最大值为 100 的说法,
通常也不会算两张相同图像的 psnr, 干脆和 skimage 一样不写 mse==0 的情况
'''
img1, img2 = img1.astype(np.float64), img2.astype(np.float64)
mse = np.mean((img1 - img2) ** 2)
return 10 * np.log10((maxvalue ** 2) / mse)
意义:
PSNR 最小值为 0,PSNR 越大,两张图像差异越小;
PSNR 计算简单,物理意义清晰,但是,这种基于 MSE 的评价指标并不能很好的按人眼的感受来衡量两张图像的相似度,例如 SSIM 论文中的图:
意思就是5种不同变换后的图像与原图 MSE 相同,即 PSNR 也相同,但是 SSIM 不同,可以类似人的感受评估图像相似性。
验证一下,保存了论文中的6幅图像计算 PSNR,毕竟不是完全在原图上计算的,不过 PSNR 的差异也确实不大:
psnr(a,b) = 22.8197
psnr(a,c) = 24.6104
psnr(a,d) = 23.6994
psnr(a,e) = 22.9966
psnr(a,f) = 24.6628
SSIM(结构相似性,Structural Similarity)基于人眼会提取图像中结构化信息的假设,比传统方式更符合人眼视觉感知。
公式: SSIM ( x , y ) = [ l ( x , y ) ] α ⋅ [ c ( x , y ) ] β ⋅ [ s ( x , y ) ] γ \operatorname{SSIM}(\mathbf{x}, \mathbf{y})=[l(\mathbf{x}, \mathbf{y})]^{\alpha} \cdot[c(\mathbf{x}, \mathbf{y})]^{\beta} \cdot[s(\mathbf{x}, \mathbf{y})]^{\gamma} SSIM(x,y)=[l(x,y)]α⋅[c(x,y)]β⋅[s(x,y)]γ
SSIM由三个部分组成, α , β , γ > 0 \alpha, \beta, \gamma>0 α,β,γ>0,用于调整三个部分的比重
l ( x , y ) = 2 μ x μ y + C 1 μ x 2 + μ y 2 + C 1 ⟶ 亮度 l(\mathbf{x}, \mathbf{y})=\frac{2 \mu_{x} \mu_{y}+C_{1}}{\mu_{x}^{2}+\mu_{y}^{2}+C_{1}} \longrightarrow 亮度 l(x,y)=μx2+μy2+C12μxμy+C1⟶亮度
c ( x , y ) = 2 σ x σ y + C 2 σ x 2 + σ y 2 + C 2 ⟶ 对比度 c(\mathbf{x}, \mathbf{y})=\frac{2 \sigma_{x} \sigma_{y}+C_{2}}{\sigma_{x}^{2}+\sigma_{y}^{2}+C_{2}} \longrightarrow 对比度 c(x,y)=σx2+σy2+C22σxσy+C2⟶对比度
s ( x , y ) = σ x y + C 3 σ x σ y + C 3 ⟶ 结构 s(\mathbf{x}, \mathbf{y})=\frac{\sigma_{x y}+C_{3}}{\sigma_{x} \sigma_{y}+C_{3}} \longrightarrow 结构 s(x,y)=σxσy+C3σxy+C3⟶结构
其中, C 1 = ( K 1 L ) 2 C_{1} = (K_1L)^2 C1=(K1L)2, C 2 = ( K 2 L ) 2 C_{2} = (K_2L)^2 C2=(K2L)2,用于规避分母为0的情况,
L L L 等价于 PSNR 中的 M a x V a l u e \mathrm{MaxValue} MaxValue, K 1 , K 2 ≪ 1 K_1,K_2 \ll 1 K1,K2≪1 是很小的常数,默认 K 1 = 0.01 K_1=0.01 K1=0.01, K 2 = 0.03 K_2=0.03 K2=0.03。
论文中设置 α = β = γ = 1 \alpha = \beta = \gamma = 1 α=β=γ=1 和 C 3 = C 2 / 2 C_{3}=C_{2}/2 C3=C2/2 来简化公式:
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}(\mathbf{x}, \mathbf{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)=(μx2+μy2+C1)(σx2+σy2+C2)(2μxμy+C1)(2σxy+C2)
均值: μ x = 1 N ∑ i = 1 N x i \mu_{x}=\frac{1}{N} \sum \limits_{i=1}^{N} x_{i} μx=N1i=1∑Nxi
标准差: σ x = ( 1 N − 1 ∑ i = 1 N ( x i − μ x ) 2 ) 1 / 2 \sigma_{x}=\left(\frac{1}{N-1} \sum \limits_{i=1}^{N}\left(x_{i}-\mu_{x}\right)^{2}\right)^{1 / 2} σx=(N−11i=1∑N(xi−μx)2)1/2
协方差: σ x y = 1 N − 1 ∑ i = 1 N ( x i − μ x ) ( y i − μ y ) \sigma_{x y}=\frac{1}{N-1} \sum \limits_{i=1}^{N}\left(x_{i}-\mu_{x}\right)\left(y_{i}-\mu_{y}\right) σxy=N−11i=1∑N(xi−μx)(yi−μy)
代码:
from skimage.measure import compare_ssim
'''
compare_ssim(X, Y, win_size=None, gradient=False,
data_range=None, multichannel=False,
gaussian_weights=False, full=False, **kwargs)
-------- Parameters --------
X, Y : ndarray
任意维度图像
win_size : int or None
gradient : bool, optional
是否返回关于Y的梯度
data_range : float, optional
输入图像数据范围(MaxValue), 默认情况根据图像数据类型估计
multichannel : bool, optional
if True, 则将数组的最后一个维度视为通道,
对每个通道独立进行相似度计算, 然后取平均值。
gaussian_weights : bool, optional
if True, 则每个patch的均值和方差由宽度为 sigma=1.5 的归一化高斯核在空间上加权。
full : bool, optional
if True, 返回原图大小的ssim而不是均值
-------- Other Parameters --------
use_sample_covariance : bool, default=True
if True, 则通过 N-1 而不是 N 对协方差进行归一化,
其中 N 是滑动窗口内的像素数。
K1 : float, default=0.01
K2 : float, default=0.03
sigma : float, default=1.5
gaussian_weights=True 时的 sigma
-------- Returns --------
mssim : float
grad : ndarray
X 和 Y 之间结构相似指数的梯度。
仅在 gradient=True 时返回
S : ndarray
完整的 ssim 图像
仅在 full=True 时返回
'''
ssim = compare_ssim(img1, img2, win_size=11, data_range=255, multichannel=True)
意义:
SSIM ≤ 1 \operatorname{SSIM}\le 1 SSIM≤1,SSIM 越大,两张图像越相似。
但是 PSNR 和 SSIM 都只适合画面复杂度低或完全对齐的图像,例如下图是同一地点的不同时期卫星图像及其重叠显示,对人眼来说相似度高,但由于没对齐导致 SSIM 很低。