畅联云平台丨09-NIMA与视频质量指标

NIMA 与视频质量指标:35+65 打分如何落地
本文讲视频质量分如何设计与落地:画面技术与人物可用性如何加权、如何抽样取中位数、主角锁定相似度阈值,以及 A/B/C/D 等级含义。
一、总分结构
总分 = 画面35 + 人物65 (0~100)


图:A=画质15+曝光12+稳定8;B=锁定20+出镜18+连续15+大小7+路人5。
二、 抽样:设计上的 20 帧与实现上的 detect 帧
设计文档规定:对长度 N 的片段均匀抽 20 帧:
帧号按 k=0…19 均匀取:第 k 个抽样点 ≈ k×N/20

图:覆盖片头到片尾;各子项先逐帧算,再取中位数。
实现上,质量累加挂在 人物定位同一次解码的检测帧(在检测帧上累加质量指标),不另开全片解码。检测步长=3 时,样本间距约 3 帧,长视频上样本数可多于 20;评分前对各标量序列取 中位数,抗偶发脏帧。设计意图「约 20 点覆盖全片」与实现「复用检测帧」在工程上等价目标:稀疏、均匀、同一次 I/O。
子项聚合:
子项分 = 映射(各抽样帧指标的中位数)
三、NIMA technical:299 输入与 batch≤8
模型:NIMA 技术画质模型(inception_resnet_v2-koniq 技术美学头),路径可用环境变量指定的模型路径覆盖。
3.1 预处理
对 1920×1080:
短边=1080,缩放比=299/1080,
缩放后约 531×299,再中心裁成 299×299
每帧预处理后约 3×299×299 个浮点数。
3.2 批推理
pending 队列满 8 或 force flush 时 批量推理:
20 帧 → 至少 3 个 batch(8+8+4)。locate 结束时把 ORT 队列刷干净。
3.3 MOS → 画质分
本项目先把原始 MOS 统一到 [0,1],再 ×15 得到画质分:
static double nima_mos_to_unit(double raw) {
if (raw > 10.0) return std::min(1.0, raw / 100.0);
if (raw > 1.0) return std::min(1.0, (raw - 1.0) / 9.0);
return std::max(0.0, std::min(1.0, raw));
}
// median(nima_mos) → unit → image_quality_score(满分 15)
const double mos_med = median_of(accum.nima_mos);
const double mos_unit = nima_mos_to_unit(mos_med);
image_quality_score = clamp_score((int)std::lround(mos_unit * 15.0), 15);数值例子
中位 MOS=0.72(已是 0~1):
例如 NIMA 原始分 0.72,映射到 15 分制约为 11 分。
若原始头输出 6.4(1~10 标度):先 (6.4-1)/9 ≈ 0.60,再 ×15 ≈ 9 分。
四、曝光 12 分
对中心 ROI(约 70% 画幅)灰度:
- 亮度均值:亮度均值;
- 坏像素占比:像素 <30 或 >225 占比。
曝光分:由灰度均值映射,再按过暗/过曝比例扣分,结果限制在 0~12。
其中指标取各抽样帧的中位数。
数值例子
mean=120,bad=0.05:
例如均值 120、过曝比例很低时,曝光分大约 6 左右。
过暗 mean=40 → map 得 0;过曝坏像素 20% → 再扣约 2 分。
五、稳定性 8 分
相邻抽样(detect)帧缩略灰度差的均值进 motion,再取中位数。因 stride 拉大帧距,做等效:把 motion 除以检测步长后再映射。
稳定性:先看相邻抽样帧背景位移,再映射到 0~8 分。
数值例子
stride=3,motion=18:
例如归一化抖动指标折合后,稳定分约 5 分。
剧烈抖动 m_eq=12 → 得分趋 0。
六、B 类:人物可用性 65
6.1 主角锁定 20(sim≥0.32)
满分条件:ByteTrack 已锁主角且底图相似度 ≥ 0.32。
6.2 出镜率 18
出镜率映射到最高 18 分:出镜太低接近 0,足够高给满分。
0.85 满分;0.35 以下 0 分。
6.3 轨迹连续 15
用圆镜有效截止帧覆盖率:
连续性看有效轨迹覆盖了片段多大比例,再映射到最高 15 分。
轨迹点最大间隙 >12 帧时额外扣分:
s ← s − min(8, gmax/3)
6.4 主体大小 7
脸短边中位 / 画幅短边 r :
- 理想带 [0.08,0.28] → 满分 7;
- 太小:map (0.03,0.08);
- 太大:按 0.40−r 惩罚(脸填满画面也不利于跟拍构图)。
6.5 路人干扰 5
从满分 5 往下扣:峰值人数、多人帧占比、他人脸观测密度。
七、等级 A/B/C/D

图:A≥80;B 65–79;C 50–64;D<50。

注意:B 档起点 65 = B 类满分,意味着画面技术全挂、人物全满分时刚好贴 B;要上 A 必须 A 类也贡献足够分。
八、整段数值演练
假设:
- NIMA 中位 unit=0.80 → 画质 12/15
- 曝光 10/12,稳定 6/8 → A=28
- 锁定 20,出镜 16,连续 12,大小 6,路人 3 → B=57
- Total=85 → 等级 A
若锁定失败(sim=0.25,仅有轨):锁定≈15,B 降到 52,Total=80,仍贴 A 边缘;再差一点出镜 → 掉进 B。
另一极端:A=10(糊且抖),B=40 → Total=50 → C。
九、与扫描流水线的衔接
日志:
NIMA 后端标签(TRT/CUDA/CPU)写入画质 basis 字符串,便于排查「分低是因为模型没加载」。
十、调参与误读
不要把 NIMA 原始 MOS 当百分制——先做 NIMA 分数归一化再 ×15。
sim=0.32 是锁定满分线,不是「有人脸」线。
稳定性已除以 stride:改 stride 后同分不代表同抖动物理量。
中位数对单帧闪光灯/转场更稳;看均值会误判。
十一、公式卡
主角锁定满分条件:已锁定跟踪号,且相似度≥0.32,且轨迹非空。
画质:image_quality = round(NIMA 分数归一化(median(MOS)) × 15)。
按此卡读日志,即可从 total/grade 反推是画质问题还是锁人问题。
十二、线性映射函数的精确形状
线性映射:指标落在区间 (低,高) 时,按比例映射到子项满分。
出镜率例子:r=0.60,区间 [0.35,0.85],满分 18:
例如出镜率指标落在区间中部时,出镜分约为满分的一半。
连续覆盖 c=0.70,区间 [0.45,0.92],满分 15:
连续性同理,可得到约 8 分。
再设最大间隙 18 帧:扣 min(8, 18/3)=6 → 连续得分约 2。这说明 中段丢轨对 B 类杀伤很大,即使出镜帧数看起来不少。
十三、 为何 A=35、B=65
产品上「能不能做成片」首先取决于有没有稳定主角;糊一点、暗一点仍可能可用,完全锁不住人则 lens/crop 无意义。故 B 权重大。A 仍保留 35,是为了挡住严重欠曝/剧烈抖动/画质崩坏的素材进入高分档。
合成启示:
- 想冲 A 档(≥80):大约需要 A≈15 且 B≈65,或 A≈28 且 B≈57 这类组合;
- 仅刷 NIMA 高分而锁人失败:B 可能只有 30~40,总分很难过 65。
十四、采样与 stride 的耦合再例
片长 N=750 帧(30 s@25),检测步长=3,检测帧约 250 次;若每次都累加 NIMA,成本过高。实现挂在 detect 帧,但 ORT batch≤8,长片仍可能积累很多 MOS。中位数对「偶发转场黑帧」稳健:即使 250 个样本里有 10 个接近 0,中位仍代表主体观感。
设计文档的 20 帧均匀抽样,可理解为 评分语义上的最小充分统计量;实现用更多 detect 样本取中位,统计上只会更稳,不会改变「先帧指标、再中位、再映射到分」的结构。
