PSNR简介
PSNR的全称为“Peak Signal-to-Noise Ratio”,直译为中文就是峰值信噪比。是一种衡量图像质量的指标。在很多领域都会需要这个指标,比如在超分辨率重建图像的时候,PSNR就是很重要的指标了。
WIKI解释
峰值信噪比(英语:Peak signal-to-noise ratio,常缩写为PSNR)是一个表示信号最大可能功率和影响它的表示精度的破坏性噪声功率的比值的工程术语。由于许多信号都有非常宽的动态范围,峰值信噪比常用对数分贝单位来表示。
计算PSNR要先知道MSE(均方误差)的计算。两个m×n单色图像I和K,如果一个为另外一个的噪声近似,那么它们的的均方误差定义为:
MSE的概念应该是比较熟悉的,这也是常见的损失函数。而PSNR就是通过MSE得出来的,公式如下:
其中,MAXI是表示图像点颜色的最大数值,如果每个采样点用 8 位表示,那么就是 255。
所以MSE越小,则PSNR越大;所以PSNR越大,代表着图像质量越好。一般来说,
PSNR高于40dB说明图像质量极好(即非常接近原始图像),
在30—40dB通常表示图像质量是好的(即失真可以察觉但可以接受),
在20—30dB说明图像质量差;
最后,PSNR低于20dB图像不可接受
python代码实现PSNR计算
# PSNR.py
import numpy as np
import math
def psnr(target, ref, scale):
# target:目标图像 ref:参考图像 scale:尺寸大小
# assume RGB image
target_data = np.array(target)
target_data = target_data[scale:-scale,scale:-scale]
ref_data = np.array(ref)
ref_data = ref_data[scale:-scale,scale:-scale]
diff = ref_data - target_data
diff = diff.flatten('C')
rmse = math.sqrt( np.mean(diff ** 2.) )
return 20*math.log10(1.0/rmse)
以上代码仅作参考之用,tensorflow框架里有直接关于psnr计算的函数,直接调用就行了:(更推荐)
注意:计算PSNR的时候必须满足两张图像的size要完全一样!
import tensorflow as tf
def read_img(path):
return tf.image.decode_image(tf.read_file(path))
def psnr(tf_img1, tf_img2):
return tf.image.psnr(tf_img1, tf_img2, max_val=255)
def _main():
t1 = read_img('t1.jpg')
t2 = read_img('t2.jpg')
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
y = sess.run(psnr(t1, t2))
print(y)
if __name__ == '__main__':
_main()
SSIM简介
SSIM是一种衡量两幅图片相似度的指标。
出处来自于2004年的一篇TIP,标题为:Image Quality Assessment: From Error Visibility to Structural Similarity 论文地址,与PSNR一样,SSIM也经常用作图像质量的评价。
先了解SSIM的输入
SSIM的输入就是两张图像,我们要得到其相似性的两张图像。其中一张是未经压缩的无失真图像(即ground truth),另一张就是你恢复出的图像。所以,SSIM可以作为super-resolution质量的指标。假设我们输入的两张图像分别是x和y,那么
α>0, β>0β>0,and γ>0γ>0. 式1是SSIM的数学定义,其中:
其中l(x, y)是亮度比较,c(x,y)是对比度比较,s(x,y)是结构比较。μ**xμx和μ**yμy分别代表x,y的平均值,σ**xσx和σ**yσy分别代表x,y的标准差。σxyσxy代表x和y的协方差。而c1c1,c2c2,c3c3分别为常数,避免分母为0带来的系统错误。
在实际工程计算中,我们一般设定α=β=γ=1α=β=γ=1,以及c3=c2/2c3=c2/2,可以将SSIM简化为下:
总结:
- SSIM具有对称性,即SSIM(x,y)=SSIM(y,x)
- SSIM是一个0到1之间的数,越大表示输出图像和无失真图像的差距越小,即图像质量越好。当两幅图像一模一样时,SSIM=1;
如PSNR一样,SSIM这种常用计算函数也被tensorflow收编了,我们只需在tf中调用ssim就可以了tf.image.ssim(x, y, 255)
源代码如下:
def ssim(img1, img2, max_val):
"""Computes SSIM index between img1 and img2.
This function is based on the standard SSIM implementation from:
Wang, Z., Bovik, A. C., Sheikh, H. R., & Simoncelli, E. P. (2004). Image
quality assessment: from error visibility to structural similarity. IEEE
transactions on image processing.
Note: The true SSIM is only defined on grayscale. This function does not
perform any colorspace transform. (If input is already YUV, then it will
compute YUV SSIM average.)
Details:
- 11x11 Gaussian filter of width 1.5 is used.
- k1 = 0.01, k2 = 0.03 as in the original paper.
The image sizes must be at least 11x11 because of the filter size.
Example:
# Read images from file.
im1 = tf.decode_png('path/to/im1.png')
im2 = tf.decode_png('path/to/im2.png')
# Compute SSIM over tf.uint8 Tensors.
ssim1 = tf.image.ssim(im1, im2, max_val=255)
# Compute SSIM over tf.float32 Tensors.
im1 = tf.image.convert_image_dtype(im1, tf.float32)
im2 = tf.image.convert_image_dtype(im2, tf.float32)
ssim2 = tf.image.ssim(im1, im2, max_val=1.0)
# ssim1 and ssim2 both have type tf.float32 and are almost equal.
img1: First image batch.
img2: Second image batch.
max_val: The dynamic range of the images (i.e., the difference between the
maximum the and minimum allowed values).
Returns:
A tensor containing an SSIM value for each image in batch. Returned SSIM
values are in range (-1, 1], when pixel values are non-negative. Returns
a tensor with shape: broadcast(img1.shape[:-3], img2.shape[:-3]).
"""
_, _, checks = _verify_compatible_image_shapes(img1, img2)
with ops.control_dependencies(checks):
img1 = array_ops.identity(img1)
# Need to convert the images to float32. Scale max_val accordingly so that
# SSIM is computed correctly.
max_val = math_ops.cast(max_val, img1.dtype)
max_val = convert_image_dtype(max_val, dtypes.float32)
img1 = convert_image_dtype(img1, dtypes.float32)
img2 = convert_image_dtype(img2, dtypes.float32)
ssim_per_channel, _ = _ssim_per_channel(img1, img2, max_val)
# Compute average over color channels.
return math_ops.reduce_mean(ssim_per_channel, [-1])