无参考图像质量评价实战:BRISQUE、RankIQA、NIMA算法原理与代码详解 📅 发布时间:2026/9/8 14:09:01 👁 浏览次数: 简介图像质量评价是图像处理的关键任务常用于压缩、传输、噪声等场景的画质监测与算法优化。这套代码合集围绕BRISQUE、RankIQA、NIMA三大代表性方法展开BRISQUE基于自然场景统计特征RankIQA利用失真局部排名与视觉显著性NIMA用CNN提取特征并经MLP映射为主观评分。包内共821个文件、约155MB以Python、MATLAB、C源码为主配有jpg/bmp示例图、prototxt配置、模型文件和说明文档便于对照不同语言版本理解原理、复现实验或二次开发不同文件类型各司其职代码负责训练与推理图像和模型用于测试验证md/txt补充使用说明。目前已有8674人学习下载热度较高。学习后可掌握无参考质量评价的经典实现思路适用于视频会议、医疗影像等质量保障也可用于压缩与增强算法的效果评估是研究与工程落地的实用资料。 做图像质量评价IQA这个方向也有几年了从最早在 ISP 调试阶段被人追着问“这张图到底比那张图好多少”到后来做算法评测时发现自己肉眼打分根本不够用中间踩过不少坑。这篇文章我把目前最容易上手、也最常被拿来当基线的三种经典算法——BRISQUE、RankIQA、NIMA——从原理到可运行代码完整梳理一遍分享一些没写在论文里的实操经验给准备入坑无参考图像质量评价NR-IQA的朋友一些参考。写之前先说明一点这里讲的三种算法都属于**无参考No-Reference**方法也就是不需要原始无损图像做对比直接给一张图就能算出质量分数。这在真实业务里几乎是刚需因为大多数场景下你根本拿不到“完美原图”去对比。1. 无参考质量评价先搞清楚你面对的是哪种问题很多刚接触这个方向的人会直接问“哪个算法效果最好”但这个问题本身就有问题。选错评估方案后面的所有调参都是在给错误的方向找补。我习惯先按场景把问题分成三类再决定用什么算法。1.1 全参考、半参考和无参考到底怎么选全参考FR-IQA像 PSNR、SSIM、LPIPS 这类需要有 undistorted 的参考图适合算法离线评测、压缩失真对比这类实验室场景。问题是业务线上绝大多数情况没有参考图。降参考RR-IQA只需要参考图的部分特征比如边缘统计、小波系数实际工程中很少见因为传特征也要带宽不如直接传图。无参考NR-IQA只有待测图模型直接输出分数。这就是 BRISQUE、RankIQA、NIMA 所在的赛道。我的经验如果你只是想在打磨算法时有个客观指标别一上来就上深度模型先用 BRISQUE 这类传统方法建立基线再用 NIMA 或 RankIQA 做精细化评价。因为深度学习无参考方法的训练数据、模型参数、推理速度差异非常大直接选最好的模型但环境不支持反而拖慢进度。1.2 业务对 IQA 的真实需求点我接触过的实际需求大致有以下几类ISP 参数调优同一场景拍多张不同参数的照片需要一个指标自动筛选出观感最好的一张替代人工目检。图像增强算法的回归验证去噪、去雾、超分之后输出图没有 ground truth现实中很难拿到同一场景的无损原图只能无参考评价。视频流质量监控实时抽帧评估压缩失真、花屏、模糊对速度要求高基本不能上太大模型。数据清洗从互联网抓海量图片做训练集需要批量筛掉模糊、过暗、噪声严重的图。明白自己属于哪类需求之后再看三种算法的选型思路就会清晰很多。BRISQUE 走的是传统特征提取路线RankIQA 解决的是标注数据获取难的问题NIMA 则直接把美学和质量统一成一个分数分布预测问题。三者理念完全不同实现难度也差别很大。2. BRISQUE用局部归一化统计量硬扛出来的经典基线全称是 Blind Referenceless Image Spatial Quality Evaluator2012 年发表在 IEEE TIP 上原作者是 Mittal 等人。它的思路非常与众不同的一点是不需要任何深度学习组件纯靠手工设计特征 回归器就能在多个失真类型上做到不错的单调性。2.1 核心技术拆解MSCN 系数与拟合特征BRISQUE 的第一步是计算MSCNMean Subtracted Contrast Normalized系数公式如下I_hat(i,j) (I(i,j) - mu(i,j)) / (sigma(i,j) C)其中mu(i,j)是局部高斯加权邻域的均值sigma(i,j)是局部标准差C是防止除零的常数。这一步的本质是去掉图像里的局部亮度均值和对比度影响让后续特征只关注“失真残留的结构信息”。用人话说就是一张清晰图经过局部归一化后MSCN 系数分布会近似高斯分布而失真图模糊、噪声、压缩的 MSCN 系数分布会出现不同程度的拖尾和中心峰值偏移。基于 MSCN 系数BRISQUE 还会继续提取四个方向上的邻域乘积水平I_hat(i,j) * I_hat(i,j1)垂直I_hat(i,j) * I_hat(i1,j)主对角线I_hat(i,j) * I_hat(i1,j1)次对角线I_hat(i,j) * I_hat(i1,j-1)对这些乘积结果用**非对称广义高斯分布AGGD**做拟合每个方向拟合出形状参数、均值、左右方差等最后组合成 18 维特征MSCN 本身 2 个参数 4 个方向各 4 个参数。此外还提取 2 个尺度原图和 1/2 下采样图的特征所以总特征是 (182)×2 36 维再做一个邻近像素乘积特征扩展常用实现里最终特征维度是 36 维也有很多版本直接扩到 18 维。最后用 SVR支持向量回归映射到质量分数。2.2 直接可跑的 Python 代码如果只是想在项目里快速用最好的方式是pip install brisque然后from brisque import BRISQUE brisque BRISQUE() score brisque.score(test_image.png) print(fBRISQUE score: {score})但注意这个 API 设计上会先加载模型文件如果离线环境没有模型会直接报错。我之前在一台无外网的开发机上就被这个坑过。解决办法是手动指定模型路径或者干脆用官方源码自己加载import numpy as np import cv2 from libsvm import svmutil # 加载官方预训练模型需要预先下载 brisque_svm_model model svmutil.svm_load_model(brisque_svm_model.txt) # 计算特征需要用到 quality.py 中的 compute_brisque_feature 函数 # 这里给出核心逻辑 def compute_mscn(img): # 高斯滤波权重 blk 7 window cv2.getGaussianKernel(blk, 7/6) window window * window.T mu cv2.filter2D(img, -1, window, borderTypecv2.BORDER_CONSTANT) sigma cv2.filter2D(img**2, -1, window, borderTypecv2.BORDER_CONSTANT) sigma np.sqrt(np.abs(sigma - mu**2)) mscn (img - mu) / (sigma 1) return mscn, sigma在实际工程中我更喜欢用这个方案因为可以离线部署、完全掌控特征提取过程以后想改造特征也方便。2.3 BRISQUE 的实际表现和边界这里说几个我实际测试中的结论BRISQUE 分数是越低越好不像 NIMA 是越高越好范围通常在 0~100。在合成失真高斯模糊、白噪声、JPEG 压缩评测集上BRISQUE 和主观分数的 Spearman 相关系数能到 0.8 以上作为传统方法相当不容易。但在真实场景失真比如暗光噪点、运动模糊加压缩混合失真上它的表现明显下滑特征空间覆盖不了复杂退化组合。另外必须注意 BRISQUE 对图像尺寸敏感论文作者建议输入大小不小于 512×512。我试过对 thumbnail 小图直接打分分数波动非常大同样的内容以 1024 宽和 512 宽计算BRISQUE 分数能差出十几分。建议统一缩放后再比较否则分数没有横向可比性。经验总结BRISQUE 适合作为线下快速筛选的硬性门槛比如“低于 40 分直接打回”但不适合做精细的美学评价。它是无参考领域最经典的 baseline任何深度学习方案都应该先在 BRISQUE 上对齐实验设置。3. RankIQA用“排序学习”绕开缺标注的困境深度学习做回归需要大量带质量标注的图但人工标注图像质量的行为主观性太强、成本高。RankIQA 的思路很巧妙不需要标绝对分数只需要知道两张图谁更好或者说通过已知的失真类型生成有排序关系的数据间接训练出网络对图像质量“高低”的判断能力。3.1 两阶段训练先学排序再学打分RankIQA 是 2017 年 ICCV 的工作作者来自澳大利亚国立大学。它分两步第一阶段排序网络用已知失真类型高斯模糊、高斯噪声、JPEG 压缩、JPEG2000 压缩等对原图进行多种强度的失真处理形成大量“同一内容、质量有优劣”的图片对。构造一个 Siamese 网络输入两张图输出置信度来判断哪张质量更好通过这种相对序关系来训练网络提取质量特征。第二阶段分数回归微调排序网络训练好后去掉 siamese 分支的头部保留特征提取部分再接一个回归头用少量带有绝对 MOSMean Opinion Score分数的标注数据例如 TID2013、LIVE 数据集里的主观分数微调让网络学会把“质量高低”映射到具体分数区间。关键设计是第一阶段的数据量可以无限生成成本近乎为零但能让模型学到比较稳定的相对排序能力第二阶段只需要少量精确标注即可达到不错的精度。3.2 一张图看懂排序损失的实现用 PyTorch 实现排序损失非常直接常用的是 Margin Ranking Lossimport torch import torch.nn as nn class RankLoss(nn.Module): def __init__(self, margin0.1): super().__init__() self.margin margin def forward(self, score_high, score_low): # score_high 预期质量高于 score_low # 损失为 max(0, -(score_high - score_low) margin) return torch.mean(torch.clamp(self.margin - (score_high - score_low), min0))训练时每次取同一原图的两个失真版本一个强失真、一个弱失真分别过网络得到两个标量计算排序损失。3.3 Siamese 网络的基础代码这里给一个简化可运行的训练代码骨架import torchvision.models as models class RankIQA_Siamese(nn.Module): def __init__(self, base_modelresnet18, use_pretrainedTrue): super().__init__() self.feature_extractor models.resnet18(pretraineduse_pretrained) # 去掉原分类层 self.feature_extractor.fc nn.Identity() self.quality_head nn.Sequential( nn.Linear(512, 256), nn.ReLU(), nn.Dropout(0.3), nn.Linear(256, 1) ) def forward_one(self, x): feat self.feature_extractor(x) return self.quality_head(feat).squeeze() def forward(self, x_high, x_low): s_high self.forward_one(x_high) s_low self.forward_one(x_low) return s_high, s_low训练时只需要构建好 (失真弱, 失真强) 的对criterion RankLoss(margin1.0) for batch in dataloader: x_high, x_low batch # 高质图、低质图 s_high, s_low model(x_high, x_low) loss criterion(s_high, s_low) optimizer.zero_grad() loss.backward() optimizer.step()3.4 实战中坑与建议第一阶段不要用真实数据这是很多复现失败的原因。RankIQA 的排序训练依赖的是可控制失真强度的合成数据真实采集数据很难排出一个可靠的质量序。排序网络的 backbone 预训练很重要。我尝试过随机初始化 ResNet第一阶段排序准确率怎么都上不了 80%换成 ImageNet 预训练后很快就收敛了。第二阶段的微调数据量不需要太多官方在 LIVE 数据集上只用了几十张图做微调就达到了当时 SOTA 的效果。特征提取器冻结与否需要试。我自己用的经验是先冻结前几层只微调后面几层和回归头不易过拟合。经验总结RankIQA 适合你手头有大量业务图、但缺少可靠人工质量分数的场景。它的价值在于先教会网络“什么是质量差异”再迁移到具体业务数据上比起直接拿几十张标注硬训回归模型稳定得多。4. NIMA把“好看”拆成分数分布而不是单一数字NIMANeural Image Assessment是 Google 2018 年发表的工作原论文题为 “NIMA: Neural Image Assessment”。跟之前算法一个最大的不同是它不直接回归一个均值分数而是预测每个分数1~10的概率分布再计算加权期望作为最终得分。这样不仅给出质量均值还能体现评分的“不确定性”。4.1 核心思想与模型结构NIMA 的整体架构其实不复杂预训练 CNN如 MobileNet、Inception-v3、ResNet 全连接层输出 10 个类别的概率用 Softmax 归一化。损失函数用的是 EMDLossEarth Movers Distance Loss对概率分布之间的 Wasserstein 距离做近似。EMD 损失公式EMD(p, q) (1/N) * sum_{k1}^{N} |CDF_p(k) - CDF_q(k)|其中CDF是累计分布函数。它衡量预测分布与真实标签分布之间的“运输距离”比直接 KL 散度更平滑也更贴合主观评分的分布特性。4.2 可运行的 PyTorch 实现首先定义 EMDLossimport torch import torch.nn as nn class EMDLoss(nn.Module): def __init__(self, num_bins10): super().__init__() self.num_bins num_bins def forward(self, pred, target): # pred, target: [batch, num_bins] 概率分布 cdf_pred torch.cumsum(pred, dim1) cdf_target torch.cumsum(target, dim1) # 近似 EMD对 CDF 差的绝对值的均值 return torch.mean(torch.abs(cdf_pred - cdf_target))然后搭建 NIMA 模型import torchvision.models as models class NIMA(nn.Module): def __init__(self, base_modelmobilenet_v2): super().__init__() if base_model mobilenet_v2: self.backbone models.mobilenet_v2(pretrainedTrue) in_features self.backbone.classifier[1].in_features self.backbone.classifier nn.Identity() elif base_model resnet50: self.backbone models.resnet50(pretrainedTrue) in_features self.backbone.fc.in_features self.backbone.fc nn.Identity() self.head nn.Sequential( nn.Dropout(0.5), nn.Linear(in_features, 10) ) def forward(self, x): feat self.backbone(x) return torch.softmax(self.head(feat), dim1)训练时标签处理成分布。比如 AVA 数据集的标签是 1~10 分的人次统计可以做归一化得到概率分布def label_to_distribution(score_counts, num_bins10): # score_counts 是长度为 10 的向量表示每个分数有多少人投票 total score_counts.sum() return score_counts / total推理时计算期望分数import numpy as np def nima_score(pred_dist): # pred_dist: [10] 概率分布 bins np.arange(1, 11) return np.dot(bins, pred_dist)我实际跑出来的结果在 AVA 数据集上算出的 NIMA 分数和人工评分的 Spearman 相关系数普遍在 0.6~0.7 之间这个数字看着不够惊艳但放在“同时拟合美学和畸变鲁棒性”这个问题下已经算不错了。4.3 训练细节这些不写进论文的经验很关键数据增强会扭转结果训练时加随机裁剪、翻转、颜色抖动后模型会更关注全局结构而不是局部伪影但也会削弱对压缩噪声的敏感度。我建议任务偏向“清晰度筛查”时减少颜色抖动偏向“美学评分”时加大增强强度。输入分辨率官方推荐 224×224但实际测试中如果画面里主体的局部纹理是核心质量信息比如皮肤质感、桌面木纹把输入放大到 384×384 会显著提升与主观感受的吻合度。EMA指数滑动平均在训练 NIMA 这种带有主观标签的任务时EMA 能明显稳定验证集分数。我给模型权重做 EMA 后模型收敛更稳分数波动降低了不少。Batch Size 尽量大主观标签噪声大小 batch 会导致梯度方向抖动。我最低可接受的 batch size 是 64。NIMA 分数范围通常在 4~7 之间不要把两个不同数据集上训出来的 NIMA 分数直接对比不同打分标定会导致整体偏移。经验总结NIMA 更适合做“画面好看程度”这类主观体验的打分拿来筛图、排序推荐前、评估增强算法是合理的如果目标是精确测量失真强度它的区分度不如失真定制化模型。5. 三种算法横向对比与选型建议讲了这么多最后一定要给一个清晰的选择路线图否则新手很容易在选型上纠结过度。下面这张表我根据近两年的使用体会整理出来的维度BRISQUERankIQANIMA方法类型传统手工特征 SVR深度学习 排序学习深度学习 分布预测输入要求单张图建议宽高≥512双分支输入训练复杂度高单张图224 或更高输出含义分数越低越好0~100相对排序或回归值分数越高越好1~10训练数据需求不需要训练直接用合成失真对 少量MOS大量 MOS/投票标注推理速度极快CPU 毫秒级较快依赖 backbone较快依赖 backbone抗混合失真能力弱中等中等偏上典型应用批量清晰度初筛、画质底线检测自定义场景质量排序标注美学评分、图像/视频质量回归5.1 按业务场景给结论如果你在做一个上线系统实时性要求高、只能 CPU 部署我的建议是用 BRISQUE 做粗筛先把低质量图筛掉再对通过粗筛的图用 NIMA 精评分。这种两级流水线我实际跑过比直接用 NIMA 处理全量图的精度更高——因为 BRISQUE 对“严重劣化”的检测非常稳NIMA 更适合对“差不多好”的图做精细化排序。如果你在做训练数据清洗且业务数据量不大、几百张到几千张为主我建议用 RankIQA 的思路自己构造少量失真对训练一个排序模型然后人工标注几十张图的绝对分数做迁移微调。这样得到的结果比直接用 ImageNet 预训练的 NIMA 更能贴合你业务里的缺陷形态。如果你在做算法评测报告又要面对“没有参考图”的死局我建议至少同时跑 BRISQUE 和 NIMA 两个指标分别代表传统特征方向和深度特征方向。两个指标若有冲突大概率说明评测图里存在某种特定失真比如对比度增强类失真BRISQUE 容易误判这时候再用主观抽检兜底。5.2 一个参考级选型流程从零开始接到一个“给图像打质量分”的需求时按这个顺序来不会被带偏先确认问题归属真的需要无参考吗有没有可能拿到参考图。用 BRISQUE 快速建立基线统计你的数据集分数分布找出明显异常区间。抽 500~1000 张图做人工粗标三分类好、中、差。对比 BRISQUE 分数段与人工类别的一致性如果一致性差说明失真形态不在 BRISQUE 范围内。这种情况下再上 RankIQA用合成失真构造排序对在少量业务数据上微调。如果需求是“评价美观程度”跳过 RankIQA 直接走 NIMA 路线。我自己经历过的项目大多数情况下走到第 4 步就能解决问题真正需要深度模型硬刚的是面部美化、摄影构图、多失真叠加这类更主观的场景。6. 常见坑复盘别人的论文复现和我自己的教训最后补几个我在复现和落地这些算法时踩过且觉得有共性的坑。6.1 数据集的分布偏移比模型结构更重要用 TID2013 或 LIVE 数据集评估模型性能时所有算法都能表现很好但把模型投到真实业务图像上性能普遍掉一截。这是因为这些传统数据集里的失真多为单一合成类型而现实中的画质劣化通常是多因叠加压缩、缩略、传感器噪声、抖动模糊一起出现。任何无参考模型都扛不住严重的域偏移所以上线前务必留一部分真实业务数据做人工评估。6.2 统一图像尺寸和色彩空间在同一个项目里对比 BRISQUE、RankIQA、NIMA 时要制定统一的预处理流程否则结论完全失真。我踩过一次BRISQUE 要求灰度或 RGB 输入但它在加载图片时默认是 RGBNIMA 训练时用的 ImageNet 归一化均值方差RankIQA 的 Siamese 网络如果不统一输入分辨率训练时 loss 直接震荡。后来我定了一个标准所有输入图统一 resize 短边为 512BRISQUE、256RankIQA 训练或 384NIMA 推理再用双线性插值保证三套算法面对的是同一构图信息。6.3 EARLY_STOPPING 要配验证集别信训练 lossRankIQA 第一阶段训练尤其容易出现过拟合合成失真对数量巨大模型可以轻松记住阶数关系导致训练 loss 很低但迁移到真实图像时极不靠谱。建议从合成数据中挖一部分留作验证监控验证集上对“没见过失真组合”的排序准确率用它决定早停而不是训练 loss。6.4 分数标定从模型分数到业务语义模型输出分数只是一个单调映射业务方通常想知道的是“这个分能不能过审”。我给每个算法都做了百分位归一化在你的数据集上跑一遍所有图记录分数分布的 10% 和 90% 分位然后标定出一个阈值。这样做的好处是不同日期、不同图像源的数据中心漂移可以被缓解。没有标定的绝对分没有任何运营意义这条是合作项目里被吐槽最多的一点。最后再说说个人体会。无参考图像质量评价没有一个银弹型算法现在大家更倾向于把质量评价拆成“技术质量”清晰、无噪声、无压缩伪影和“美学质量”构图、光线、色彩吸引力两个维度分开建模。BRISQUE 这种传统特征方法在技术质量维度上依然能打RankIQA 适合在标注匮乏时做一个相对可靠的排序模型NIMA 则是走到美学评分的必经之路。后续你可以根据自己的数据特点选一个方向继续挖——但无论选哪条先把这篇文章里的基线和代码跑通后面的事都会顺利很多。本文还有配套的精品资源点击获取