写在前面

psnr作为图像质量评价指标,在很多图像领域如图像超分辨率、图像压缩、图像去噪等都有广泛的应用。

PSNR(峰值信噪比)

简介

Peak signal-to-noise ratio(简称PSNR)是一个工程术语,表示信号的最大可能功率与影响信号表示精度的干扰噪声功率之间的比值。由于许多信号都有非常宽的动态范围,峰值讯噪比常用对数分贝单位来表示。

定义

它常简单地通过均方误差(MSE)进行定义。两个 pytorch的psnr与ssim python psnr_pytorch的psnr与ssim 单色图像 pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_02pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_03pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_02 为一无噪声的原始图像,pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_03pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_02 的噪声近似(例: pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_02 为未压缩的原始图像,pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_03pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_02 经过压缩后的图像),那么它们的的均方误差定义为:
pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_10
峰值信噪比定义为:
pytorch的psnr与ssim python psnr_psnr_11
其中,pytorch的psnr与ssim python psnr_MSE_12 是表示图像点颜色的最大数值,如果每个采样点用 8 位表示(例:影像处理),那么就是 255。更为通用的表示是,如果每个采样点用 B 位线性脉冲编码调制表示,那么 pytorch的psnr与ssim python psnr_MSE_12 就是:
pytorch的psnr与ssim python psnr_MSE_14
对于每点有RGB三个值的彩色图像来说,峰值信噪比的定义类似。除了横轴、纵轴 pytorch的psnr与ssim python psnr_信噪比_15pytorch的psnr与ssim python psnr_MSE_16

彩色图像的峰值讯噪比定义为:
pytorch的psnr与ssim python psnr_信噪比_17

实现

这是我一开始写的代码,两个地方有点问题,也是大家常会犯的错误。

from PIL import Image
import numpy as np

img1 = np.array(Image.open('original.jpg'))
img2 = np.array(Image.open('compress.jpg'))


def psnr(img1, img2):
    mse = np.mean((img1-img2)**2)
    if mse == 0:
        return 100
    else:
        return 20*np.log10(255/np.sqrt(mse))


if __name__ == "__main__":
    print(psnr(img1, img2))

1、如果mse == 0不应该返回100,而是正无穷,正无穷在python中用float('inf')表示。(参考维基英文百科:In the absence of noise, the two images pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_02 and pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_03

2、数据类型的问题。img1img2原本是np.int8类型,应该转换为np.float64再参与计算,否则会导致精度丢失,计算的psnr值偏大。(这里参考了psnr百科词条中的matlab代码实现,代码中对图片进行了double操作,学过matlab的同学应该清楚,这就是将无符号int8类型转换为双精度浮点型

修改后的代码:

from PIL import Image
import numpy as np

img1 = np.array(Image.open('original.jpg')).astype(np.float64)
img2 = np.array(Image.open('compress.jpg')).astype(np.float64)


def psnr(img1, img2):
    mse = np.mean((img1-img2)**2)
    if mse == 0:
        return float('inf')
    else:
        return 20*np.log10(255/np.sqrt(mse))


if __name__ == "__main__":
    print(psnr(img1, img2))

如果你不想自己写,也可以调用第三方库skimage实现,里面有封装好的计算psnr的代码,和我修改后的代码计算结果是一模一样的,具体调用方式如下:

from skimage.metrics import peak_signal_noise_ratio as psnr
from PIL import Image
import numpy as np


img1 = np.array(Image.open('original.jpg'))
img2 = np.array(Image.open('compress.jpg'))


if __name__ == "__main__":
    print(psnr(img1, img2))

备注:skimage的大名叫scikit-image,安装请用pip install scikit-image

意义

  • PSNR接近 50dB ,代表压缩后的图像仅有些许非常小的误差。
  • PSNR大于 30dB ,人眼很难查觉压缩后和原始影像的差异。
  • PSNR介于 20dB 到 30dB 之间,人眼就可以察觉出图像的差异。
  • PSNR介于 10dB 到 20dB 之间,人眼还是可以用肉眼看出这个图像原始的结构,且直观上会判断两张图像不存在很大的差异。
  • PSNR低于 10dB,人类很难用肉眼去判断两个图像是否为相同,一个图像是否为另一个图像的压缩结果。

同压缩比例的PSNR比较(点击图片可放大)图片为台湾桃园国际机场停机坪

pytorch的psnr与ssim python psnr_信噪比_20

pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_21

pytorch的psnr与ssim python psnr_信噪比_22

pytorch的psnr与ssim python psnr_pytorch的psnr与ssim_23

未压缩的原图

PSNR 47.61dB

PSNR 34.02dB

PSNR 24.46dB

拓展阅读

psnr的matlab实现:

function PSNR = psnr(f1, f2)
%计算两幅图像的峰值信噪比
k = 8;
%k为图像是表示地个像素点所用的二进制位数,即位深。
fmax = 2.^k - 1;
a = fmax.^2;
MSE =(double(im2uint8(f1)) -double( im2uint8(f2))).^2;
b = mean(mean(MSE));
PSNR = 10*log10(a/b);

引用参考

https://zh.wikipedia.org/wiki/峰值信噪比https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratiohttps://baike.baidu.com/item/psnr/2925132