ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

【共创稿事节】HarmonyOS 7重建结果质量评估:SSIM/PSNR 端侧轻量实现

【共创稿事节】HarmonyOS 7重建结果质量评估:SSIM/PSNR 端侧轻量实现 重建结果质量评估SSIM/PSNR 端侧轻量实现3DGS 重建跑完了给用户看之前怎么知道这次重建好不好我们一开始全靠肉眼——重建工程师逐个看觉得糊就重拍。问题是肉眼判断主观、慢、且不可复现。同一组重建结果两个工程师一个说合格一个说不合格评审会开成吵架会。我们需要一个端侧能跑的量化指标重建完立刻给个分数分数低于阈值自动建议重拍。这篇文章记录我们把 SSIM/PSNR 做端侧轻量实现的过程以及在没有 ground truth 时怎么绕过没有参考图这个根本困难。能力面端侧轻量 SSIM/PSNRSSIM结构相似性和 PSNR峰值信噪比是图像质量评估的经典指标。常规用法是有原图I和失真图K按公式算出一个 0-1 的相似度分数。问题是3DGS 重建结果没有 ground truth——你拍了一段视频重建出 3D 场景没有原始 3D 场景可以对比。我们的解法是从采集视频里留出 holdout 帧当参考。采集 60 帧视频重建时用 50 帧训练留 10 帧不参与训练。重建完成后把这 10 帧对应的视角用 3DGS 渲染出来和真实采集的 10 帧对比算 SSIM/PSNR。这 10 帧重建结果没见过相当于考试题分数反映重建的泛化能力。// entry/src/main/ets/quality/QualityAssessor.etsimport{image}fromkit.ImageKit;import{spatialRender}fromkit.SpatialReconKit;exportinterfaceQualityResult{ssim:number;// 0-1越大越好0.85 我们认为可用psnr:number;// dB越大越好28 dB 我们认为可用assessTime:number;// 评估耗时 msholdoutCount:number;}exportclassQualityAssessor{/** * 端侧轻量 SSIM/PSNR 评估 * param gsNode 重建得到的 3DGS 节点 * param holdoutFrames 留出的参考帧视角 真实采集图 */staticasyncassess(gsNode:spatialRender.GSNode,holdoutFrames:HoldoutFrame[]):PromiseQualityResult{constt0:numberDate.now();letssimSum:number0;letpsnrSum:number0;letvalidCount:number0;for(constframeofholdoutFrames){// 1. 用 3DGS 在 holdout 视角下渲染出图constrendered:image.PixelMapawaitgsNode.renderToImage({camera:frame.camera,width:512,// 降采样到 512 加速评估原采集 1080pheight:512});// 2. 把真实采集帧也缩到同尺寸constreference:image.PixelMapawaitdownsample(frame.pixelMap,512,512);// 3. 算 SSIM 和 PSNRconstssim:numberthis.computeSSIM(rendered,reference);constpsnr:numberthis.computePSNR(rendered,reference);if(ssim0psnr0){ssimSumssim;psnrSumpsnr;validCount;}rendered.release();reference.release();}constassessTime:numberDate.now()-t0;return{ssim:validCount0?ssimSum/validCount:0,psnr:validCount0?psnrSum/validCount:0,assessTime,holdoutCount:holdoutFrames.length};}// SSIM 轻量实现分块计算11x11 高斯窗口简化为 8x8 均值窗口privatestaticcomputeSSIM(a:image.PixelMap,b:image.PixelMap):number{// 转灰度constgrayA:Uint8ArraytoGray(a);constgrayB:Uint8ArraytoGray(b);constw:number512;consth:number512;constblockSize:number8;letssimSum:number0;letblockCount:number0;for(lety:number0;yh-blockSize;yblockSize){for(letx:number0;xw-blockSize;xblockSize){conststatsAblockStats(grayA,w,x,y,blockSize);conststatsBblockStats(grayB,w,x,y,blockSize);constcovAB:numberblockCov(grayA,grayB,w,x,y,blockSize,statsA.mean,statsB.mean);// SSIM 常数按 8bit 图标准取值constc1:number(0.01*255)**2;constc2:number(0.03*255)**2;constssim:number((2*statsA.mean*statsB.meanc1)*(2*covABc2))/((statsA.mean**2statsB.mean**2c1)*(statsA.varstatsB.varc2));ssimSumssim;blockCount;}}returnblockCount0?ssimSum/blockCount:0;}// PSNRMSE 越小 PSNR 越大privatestaticcomputePSNR(a:image.PixelMap,b:image.PixelMap):number{constdataA:Uint8ArraytoGray(a);constdataB:Uint8ArraytoGray(b);letmse:number0;for(leti:number0;idataA.length;i){constdiff:numberdataA[i]-dataB[i];msediff*diff;}mse/dataA.length;if(mse0){return100;// 完全相同}return10*Math.log10((255*255)/mse);}}实现上有几处简化窗口从 11x11 高斯改成 8x8 均值标准 SSIM 用 11x11 高斯窗口滑窗计算端侧算力吃不消。8x8 块均值版本精度略低但和标准 SSIM 的相关系数在我们测的 10 组数据上达到 0.94够用。渲染分辨率降到 512x512原采集 1080p 直接算要 4 倍耗时512 下 SSIM 数值变化在 0.01 以内。下面这张图把端侧评估的判定链路串起来。从重建结果到最终入库还是重采每一步都有明确输入输出。达标不达标重建完成得到 3DGS 结果从采集视频留出 holdout 帧当参考在 holdout 视角渲染出图渲染图与真实帧统一降到 512 尺寸分块计算 SSIM 并算 PSNR多帧求均值得到质量分数SSIM 大于 0.75 且 PSNR 大于 26结果入库并展示按 SSIM 区间给具体重采建议触发重新采集或补拍图里从渲染到阈值比较是评估主链路。低于阈值的分支回到采集环节做一次质量兜底。约束面评估耗时与内存端侧评估不能比重建本身还慢否则没意义。我们在麒麟 9030 上测了不同 holdout 帧数下的耗时和内存。holdout 帧数评估耗时内存峰值SSIM 数值稳定性5380 ms42 MB±0.01810720 ms48 MB±0.011151080 ms56 MB±0.008201450 ms64 MB±0.006302310 ms78 MB±0.005我们选了10 帧。5 帧稳定性差30 帧太慢且内存逼近重建本身的占用。10 帧在 720 ms 内完成用户感知是重建完稍等一下分数就出来了。内存峰值 48 MB 看着不大但要叠加在重建过程的内存上。重建峰值已经 800 MB 左右再加 48 MB 不会触发 OOM但如果重建结果没释放就启动评估峰值会到 880 MB在 8 GB 设备上危险。我们的做法是重建完先释放中间张量再启动评估。场景落地10 组重建结果评估我们采集了 10 组不同场景的视频每组用 50 帧训练、10 帧 holdout重建后做端侧评估。同时请 3 位重建工程师盲打分1-5 分做人工对照。真机数据SSIM/PSNR 与人工评分场景SSIMPSNR (dB)人工评分均值评估耗时陶瓷茶壶0.9131.24.3680 ms毛绒玩具0.8829.84.0710 ms皮鞋0.8628.53.8695 ms玻璃杯0.6222.12.1720 ms镜面金属件0.5821.31.9730 ms木雕0.8930.14.1685 ms布艺沙发0.8427.93.6705 ms绿植盆栽0.7926.43.2700 ms强光下石雕0.8127.13.4690 ms弱光下手办0.7325.02.8715 msSSIM 与人工评分的 Pearson 相关系数 0.93PSNR 与人工评分 0.88。SSIM 比 PSNR 更贴合人感这和文献一致——PSNR 对像素误差敏感但人眼对结构误差更敏感SSIM 抓的就是结构。玻璃杯和镜面金属件两组数据是失败 case。SSIM 0.62、0.58人工评分 2.1、1.9都低。这两组是 3DGS 重建的已知弱项透明和反光物体采集时多视角不一致高斯点拟合不了反射光路。SSIM 准确地把这两组标了出来我们据此把阈值定在 0.75——低于 0.75 自动建议重拍。踩坑与取舍坑一SSIM 需要 reference 图但重建结果没有参考这是开头说的根本困难。holdout 帧方案能跑但有个隐含假设holdout 帧和训练帧视角分布接近。如果用户采集时只拍了正面holdout 留的也是正面SSIM 会偏高——正面重建容易侧面才是难点。我们试过强制 holdout 留侧面帧但用户采集路径不可控有时侧面帧本身就模糊。最后改成按视角均匀采样 holdout把 60 帧按相机方位角分到 6 个桶每桶留 1-2 帧做 holdout。这样 holdout 覆盖各视角SSIM 能反映整体重建质量。坑二PSNR 对结构误差不敏感PSNR 算的是像素级 MSE。重建结果如果整体偏了一像素几何漂移人眼看是错的但 PSNR 可能不算太低——因为偏移后像素值差异不大。我们有一组木雕数据PSNR 30.1 看着不错但人工评分只有 4.1原因是纹理对但轮廓偏了。结论是 PSNR 只能当辅助指标主判据用 SSIM。我们最终阈值是 SSIM 0.75 且 PSNR 26 dB双指标都过才算合格。单看 PSNR 会放过几何漂移的 case。坑三弱光场景 SSIM 失真弱光下手办那组 SSIM 0.73人工评分 2.8。看起来 SSIM 准确反映了质量不好。但深入看发现 SSIM 偏低部分原因是采集帧本身噪声大holdout 帧和渲染帧比渲染帧反而更干净3DGS 重建有降噪效果SSIM 把降噪后的干净和带噪的真实比分数被噪声拉低。这意味着弱光场景下SSIM 会低估重建质量。我们的处理是弱光场景采集平均亮度 50单独校准阈值从 0.75 降到 0.68。这是个 hack但比弱光场景全判不合格合理。坑四被放弃的方案——无参考质量评估NRQA我们试过完全不需要 holdout 的无参考质量评估方案用端侧小模型推理给个分数。模型用 BRISQUE 思路训练2 MB 大小。问题是模型在训练分布外场景表现崩塌——训练集是自然图像碰到 3DGS 渲染图高斯点叠加出的图分数完全不可信。陶瓷茶壶重建很好模型给 1.8 分玻璃杯重建很差模型给 4.2 分。这个方案被放弃了。无参考评估在没有 3DGS 渲染图训练集的前提下不可用而构建这样一个训练集成本太高。holdout 帧方案虽然要多留几帧但可靠。评估结果怎么用光算出分数不够要把分数接到产品流程里。// entry/src/main/ets/quality/QualityGate.etsexportclassQualityGate{privatestaticreadonlySSIM_THRESHOLD:number0.75;privatestaticreadonlyPSNR_THRESHOLD:number26;// 弱光场景阈值放宽privatestaticreadonlySSIM_THRESHOLD_LOWLIGHT:number0.68;staticevaluate(result:QualityResult,isLowLight:boolean):QualityVerdict{constssimThreshold:numberisLowLight?this.SSIM_THRESHOLD_LOWLIGHT:this.SSIM_THRESHOLD;if(result.ssimssimThresholdresult.psnrthis.PSNR_THRESHOLD){return{pass:true,score:result.ssim,suggestion:};}// 不通过时给具体建议而不是笼统说质量差letsuggestion:string;if(result.ssim0.6){suggestion重建质量较差建议重新采集注意覆盖多角度且避免反光;}elseif(result.ssimssimThreshold){suggestion部分视角重建模糊建议补拍侧面和背面;}else{suggestion几何精度不足建议采集时放慢移动速度;}return{pass:false,score:result.ssim,suggestion};}}suggestion不是笼统的质量差请重拍而是按 SSIM 区间给具体建议。SSIM 0.6 是整体崩了建议重采0.6-0.75 是部分视角糊建议补拍SSIM 过了但 PSNR 没过是几何漂移建议放慢移动速度。用户看到具体建议才知道怎么改质量差三个字对用户没操作指导意义。总结一下下holdout 帧按视角均匀采样不能只留正面帧否则 SSIM 偏高不反映整体质量SSIM 用 8x8 块均值窗口替代 11x11 高斯窗口精度损失 0.01 以内耗时减半评估分辨率降到 512x512原 1080p 算 SSIM 耗时 4 倍数值变化 0.01 以内主判据用 SSIMPSNR 仅辅助PSNR 对几何漂移不敏感单看会放过结构错误弱光场景 SSIM 阈值从 0.75 降到 0.68弱光下 SSIM 会因采集噪声低估重建质量评估前先释放重建中间张量避免内存峰值叠加触发 OOMholdout 帧数选 105 帧稳定性差30 帧耗时超过 2 秒用户感知等待无参考质量评估在 3DGS 场景不可用训练集分布外分数崩塌holdout 方案更可靠
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进