063、超分评价指标详解:PSNR、SSIM、LPIPS 与 NIQE 的计算与对比
上个月调一个视频超分模型,在公开测试集上PSNR刷到了38.2dB,心里美滋滋准备发论文。结果审稿人一句话把我打回原形:“请补充感知质量指标,PSNR高不代表视觉好。” 当时真想顺着网线过去理论——后来自己盯着输出帧看了半小时,确实,高频细节是多了,但纹理全是假的,像油画笔刷抹上去的。从那以后,我养成了一个习惯:跑完模型先算四个指标,PSNR、SSIM、LPIPS、NIQE,一个都不能少。
PSNR:最古老也最坑的指标
PSNR的全称是Peak Signal-to-Noise Ratio,峰值信噪比。公式很简单:
PSNR = 10 * log10(MAX^2 / MSE)MAX是像素最大值,8位图就是255。MSE是均方误差,逐像素算差然后平均。
这里踩过坑:很多人直接用skimage.metrics.peak_signal_noise_ratio,但默认参数是data_range=255。如果你处理的是归一化到[0,1]的tensor,别这样写——算出来PSNR会虚高。正确做法是:
# 别这样写:psnr = peak_signal_noise_ratio(hr, sr)# 应该指定data_rangepsnr=peak_signal_noise_ratio(hr,sr,data_range=255)PSNR最大的问题是什么?它完全不在乎图像结构。你把一张清晰人脸整体向右平移一个像素,PSNR可能掉到20dB以下,但人眼看不出区别。反过来,你给图像加一层高斯噪声,PSNR可能只掉0.5dB,但视觉上已经糊成一片了。
实战经验:PSNR适合作为模型训练的loss监督信号,但不适合作为最终评价标准。我见过太多论文靠PSNR刷榜,实际效果一塌糊涂。如果你发现两个模型PSNR差0.1dB以内,基本可以认为它们在这个指标上没有显著差异——别为了这0.1dB折腾三天调参。
SSIM:结构相似性,比PSNR靠谱一点
SSIM(Structural Similarity Index)从亮度、对比度、结构三个维度比较图像。公式长这样:
SSIM(x,y) = (2μxμy + C1)(2σxy + C2) / (μx^2 + μy^2 + C1)(σx^2 + σy^2 + C2)μ是均值,σ是方差,C1、C2是防止除零的小常数。
别这样写:直接用skimage.metrics.structural_similarity不指定win_size,默认是7x7窗口。对于超分任务,尤其是4倍、8倍超分,7x7窗口太小了,算出来的SSIM对纹理细节不敏感。我习惯用win_size=11或者15。
# 推荐写法ssim_val=structural_similarity(hr,sr,win_size=11,data_range=255,channel_axis=-1)SSIM比PSNR好的地方在于,它对图像结构变化更敏感。比如超分结果出现了振铃效应(边缘附近的伪影),SSIM会明显下降,而PSNR可能只掉零点几分贝。
但SSIM也有坑:它对模糊不敏感。你把一张高清图稍微模糊一下,SSIM可能还有0.95以上,但人眼已经能看出区别了。这就是为什么后来有了MS-SSIM(多尺度SSIM),对模糊更敏感。
LPIPS:终于开始像人了
LPIPS(Learned Perceptual Image Patch Similarity)是2018年提出的,核心思想是用预训练好的CNN(比如AlexNet、VGG)提取特征,在特征空间里算距离。
原理一句话:人眼看图像不是逐像素看的,而是看纹理、边缘、语义内容。LPIPS让网络替我们做这件事。
# 使用lpips库,注意输入要归一化到[-1,1]importlpips loss_fn=lpips.LPIPS(net='alex')# 推荐用alex,vgg太慢# 别这样写:loss_fn = lpips.LPIPS(net='vgg', verbose=True) # verbose=True会打印一堆信息dist=loss_fn(hr_tensor,sr_tensor)# 输出是0-1之间的距离,越小越好踩坑记录:LPIPS的输入必须是归一化到[-1,1]的tensor,而且要有batch和channel维度。如果你直接传numpy数组,会报错。另外,LPIPS对图像尺寸有要求,至少224x224,太小了特征提取不准。
LPIPS最大的价值在于:它能捕捉到PSNR和SSIM完全看不出的差异。比如超分结果出现了纹理粘连(两个不同物体的纹理混在一起),LPIPS会给出很高的距离,而PSNR可能还很高。这也是为什么现在顶会论文几乎必报LPIPS。
实战建议:LPIPS的数值范围是0到1,但实际中0.1以下就算很好了。如果你的模型LPIPS能到0.05以下,视觉上基本看不出和原图的区别。
NIQE:无参考指标,救急用的
前面三个指标都需要高清参考图(HR),但实际应用中,你拿到的低清图可能根本没有对应的HR。这时候NIQE(Natural Image Quality Evaluator)就派上用场了。
NIQE的原理:从大量自然图像中提取统计特征(主要是空间域和频域的统计量),建立一个“自然图像”的分布模型。然后计算待测图像的特征与这个模型的偏离程度。
# 使用piq库计算NIQEfrompiqimportniqe# 别这样写:score = niqe(sr) # 默认参数可能不适合超分score=niqe(sr,data_range=255,reduction='none')# 返回每个图像的分数注意:NIQE没有参考图,所以它只能告诉你图像“像不像自然图像”,不能告诉你超分结果是否忠实于原图。比如你把一张人脸超分成了猫脸,如果猫脸纹理自然,NIQE可能还很高——这就尴尬了。
个人经验:NIQE适合做模型筛选的辅助指标。比如你有10个候选模型,PSNR和SSIM都差不多,这时候看NIQE,选最低的那个。但别把NIQE当唯一标准,它和主观评分的相关性只有0.6左右,远不如LPIPS(0.8以上)。
四个指标怎么用?我的血泪经验
训练阶段:用PSNR做loss监督,同时每100个iteration算一次LPIPS,如果LPIPS不降反升,说明模型开始过拟合了——赶紧加正则化或者早停。
模型对比:先看PSNR和SSIM,如果两个模型差距在0.1dB/0.01以内,再算LPIPS。LPIPS差距超过0.02,基本可以判断哪个模型更好。
论文投稿:四个指标全报,但要在正文里说明每个指标的意义。审稿人看到你报了LPIPS和NIQE,会觉得你懂行。
实际应用:如果用户反馈“超分结果太假”,先看LPIPS,如果LPIPS很高,说明模型产生了伪影。这时候别调PSNR了,调LPIPS相关的loss(比如Perceptual Loss)更有效。
最后说一句:指标只是工具,别被指标绑架。我见过最离谱的事,有人为了刷PSNR,把超分结果直接往HR上靠,结果纹理全没了——这叫降噪,不叫超分。真正好的超分,是在保持纹理自然的前提下提升分辨率,这需要你同时盯着四个指标,更要盯着自己的眼睛。