展厅暗光区采集 3DGS,重建质量会崩。我们在一个文物展柜前拍,环境光 80 lux,重建出来全是噪点,高斯点数从正常的 40 万暴涨到 180 万,SSIM 跌到 0.58。弱光采集是 3DGS 落地展厅场景的硬门禁,过不去这道坎,展厅这类高价值场景就用不了。这篇把我们在不同照度下的实测、门禁划定和降噪方案摊出来。
能力面:弱光采集的三个手段
弱光下要拍到足够信息,手段就三个:拉长曝光时间、提 ISO、补光。每个都有代价。
曝光补偿
曝光时间拉长,进光量增加,但手抖模糊的风险随曝光时间线性涨。手持采集时曝光时间超过 1/30 秒就开始有模糊,超过 1/10 秒基本废了。三脚架能放宽到 1 秒,但展厅采集要求用户手持环绕走动,三脚架不现实。
我们的做法是曝光时间卡在 1/60 秒,配合防抖。1/60 秒在 200 lux 以上够用,100 lux 以下就欠曝了。曝光补偿在手持采集下天花板很低,弱光不能只靠它。
ISO 上限
提 ISO 是弱光下最直觉的手段,也是最容易翻车的。ISO 从 100 拉到 800,画面亮度提了 3 档,噪声也涨了。3DGS 重建对噪声特别敏感——噪声点会被当成真实细节重建出来,高斯点数暴涨,SSIM 暴跌。
我们测下来 ISO 800 是安全线,ISO 1600 开始有可见噪点,ISO 3200 重建直接崩。ISO 上限卡 800 是我们这台机器上的门禁,再高就要配强力降噪,而强力降噪本身会丢细节,两头不讨好。
降噪策略
降噪有两个时机:采集时实时降噪(相机 ISP 内置)和重建前预处理。相机 ISP 降噪是黑盒,我们能调的是强度。强度拉高噪声降了,但细节也糊了——陶瓷摆件的釉面纹理在强降噪下变光滑,重建出来失真。
重建前预处理是我们自己做的:对采集的每一帧跑一遍非局部均值(NLM)降噪,再送进重建管线。NLM 在保边去噪上比双边滤波好,但慢——1080×1440 一帧 NLM 约 80 ms,80 帧采集视频要 6.4 秒预处理。能接受,因为重建本身要几分钟,多 6 秒不显眼。
NLM 的强度要按噪声水平调,不是固定值。我们按采集时的 ISO 估噪声 σ,ISO 100 时 σ≈2 用弱档 NLM,ISO 800 时 σ≈10 用中档,ISO 1600 以上用强档但已经不推荐了。强度档位是我们调出来的,弱档保细节、强档保去噪,中档是商品展示的默认。NLM 强度按 ISO 联动比固定值好,固定值会在低噪声时过度平滑丢细节。
补光
补光灯是物理手段,最有效但限制最多。手持一个 LED 补光灯环绕采集,能把局部照度从 80 lux 拉到 300 lux。问题是补光灯的方向跟着手走,环绕到不同角度时补光方向变,物体上的高光阴影分布不一致,重建时这块是噪声源。
补光要稳定方向,得用固定灯架,但展厅里不一定能架灯。补光方案在能架灯的展柜有效,在自由走动的展厅无效。
被放弃的方案:图像超分提亮
我们试过用端侧图像超分(Super Resolution)把弱光采集的低分辨率帧超分提亮再重建。想法是超分能"猜"出高频细节,等效补光。API 26 的超分能力能把 1080×1440 超分到 2160×2880,理论上细节更丰富。
跑下来不work。超分"猜"出来的细节是 hallucination——青铜器表面纹理被超分脑补成不存在的花纹,重建出来这些假花纹变成真实几何,SSIM 反而比不超分低。超分在弱光下的 hallucination 比噪声更伤,因为噪声至少是随机的、重建优化能平均掉,hallucination 是结构性的、重建会把它当真实结构保留。超分提亮在 3DGS 重建上是反效果,hallucination 比噪声更难处理。这个方案放弃了。
超分在 API 26 仍带 Beta 标记,接口可能调整,即使有效也不敢上生产。
约束面:照度门禁与各手段上限
| 约束 | 阈值 | 来源 |
|---|---|---|
| 环境光门禁 | < 100 lux 重建质量不可接受 | 实测 SSIM < 0.7 |
| 曝光时间上限 | 1/60 秒(手持) | 手抖模糊 |
| ISO 上限 | 800 | 噪声致重建崩 |
| 降噪强度上限 | NLM 中等档 | 强档丢细节 |
| 补光一致性 | 灯方向变化 < 15° | 重建阴影一致 |
照度门禁 100 lux 是我们划的。低于 100 lux 时,即使 ISO 拉到 800、曝光拉到 1/60、NLM 降噪全开,SSIM 也只有 0.65~0.7,重建出来的高斯点数是正常值的 3~4 倍,渲染时同屏点数失控。这个门禁只在我们测过的 3 台机器和 5 类物体上成立,换设备换物体可能要重测。
展厅里常见照度分布:入口区 500~800 lux、主展区 200~400 lux、文物暗光区 50~150 lux。文物暗光区普遍过不了 100 lux 门禁,这是展厅 3DGS 落地的主要障碍。
还有一道约束是采集引导。用户不知道什么是 lux,看到环境暗就开拍,拍完重建崩了怪应用。门禁要在采集前主动挡,用环境光传感器读 lux,低于门禁灰掉按钮并提示"光照不足,建议移到亮处或补光"。这个引导比事后报"重建失败"友好得多,是我们踩了"用户白拍 5 分钟"的坑后加的。
门禁判断的整体流程如下图,先挡人再调参数。
图里三档照度的处理后面都有实测数据撑着。
场景落地:同一物体四档照度实测
拿一个青铜小摆件做测试对象。固定在三脚架上(排除手抖),用可调光源把环境光分别设到 500/200/100/50 lux,每档用同一套环绕采集路径(80 帧、ISO 800、曝光 1/60),重建后测耗时、高斯点数、SSIM、噪声水平。SSIM 用 500 lux 的重建结果做参考。
| 照度 | 重建耗时 | 高斯点数 | SSIM | 噪声水平 (σ) | 可用性 |
|---|---|---|---|---|---|
| 500 lux | 3 分 48 秒 | 38 万 | 1.000 | 2.1 | 优 |
| 200 lux | 4 分 12 秒 | 42 万 | 0.94 | 4.8 | 良 |
| 100 lux | 5 分 36 秒 | 68 万 | 0.78 | 11.2 | 边缘 |
| 50 lux | 7 分 24 秒 | 142 万 | 0.58 | 28.5 | 不可用 |
测试机型 Pura 80 Pro(麒麟 9030)。数据有几个值得注意的:
- 重建耗时随照度降而涨。50 lux 时 7 分 24 秒,是 500 lux 的近 2 倍。原因是噪声点多,优化迭代次数增加。
- 高斯点数在 100 lux 以下暴涨。50 lux 时 142 万点,是 500 lux 的 3.7 倍。这些多出来的点大部分是噪声点,渲染时同屏点数失控。
- SSIM 在 100 lux 处跌破 0.8,50 lux 跌到 0.58。0.7 是我们定义的"可用下限",100 lux 在边缘,50 lux 明显不可用。
- 噪声水平 σ 在 50 lux 时 28.5,是 500 lux 的 13 倍。这个噪声量肉眼可见,重建出来物体表面全是颗粒。
- 50 lux 档重建耗时 7 分 24 秒里有约 2 分钟是优化器在跟噪声点搏斗,最后还是没搏过——这 2 分钟是纯浪费,门禁挡掉比让它跑完更友好。
加 NLM 预处理后的对比
同样四档照度,重建前对采集帧跑 NLM 降噪预处理:
| 照度 | 高斯点数 (NLM) | SSIM (NLM) | 噪声 σ (NLM) | vs 无降噪 |
|---|---|---|---|---|
| 500 lux | 37 万 | 0.99 | 1.8 | 几乎无差 |
| 200 lux | 40 万 | 0.95 | 3.2 | 略改善 |
| 100 lux | 52 万 | 0.83 | 6.5 | 明显改善 |
| 50 lux | 98 万 | 0.68 | 15.1 | 改善但仍不可用 |
NLM 在 100 lux 档把 SSIM 从 0.78 拉到 0.83,高斯点数从 68 万压到 52 万,效果明显。但 50 lux 档即使加了 NLM,SSIM 仍只有 0.68,过不了 0.7 可用下限。NLM 能把门禁从 100 lux 下推到 80 lux 左右,但推不到 50 lux。弱光下 NLM 也救不回来,因为信号本身就欠曝,降噪找不回不存在的细节。
跨设备弱光表现
把同一青铜摆件在 100 lux 下放到两台机器上重建:
| 机型 | 重建耗时 | 高斯点数 | SSIM | 噪声 σ |
|---|---|---|---|---|
| Pura 80 Pro (9030) | 5 分 36 秒 | 68 万 | 0.78 | 11.2 |
| Mate 70 Pro (9020) | 7 分 48 秒 | 75 万 | 0.74 | 13.6 |
Mate 70 Pro 慢 40%,SSIM 低 0.04,噪声 σ 高 2.4。差距来自 ISP 降噪能力——9030 的 ISP 在弱光下降噪比 9020 强一档。弱光门禁要按机型分档,9030 上 100 lux 可用,9020 上门禁要拉到 130 lux 才能保证 SSIM 0.75 以上。我们目前门禁统一 100 lux,9020 用户在 100~130 lux 区间会拿到边缘质量,未来要按机型调。
这个机型差异在弱光下被放大了。500 lux 时两台机器 SSIM 差距只有 0.02,100 lux 时拉到 0.04。照度越低,设备差异越明显,和 fillrate 那篇的"同屏点数越高设备差异越大"是同一个规律——瓶颈越紧,硬件差距越暴露。
踩坑:三个弱光采集的坑
坑一:ISO 拉到 3200 重建全是噪点
第一版弱光方案我们直接把 ISO 拉到 3200,想着"先拍亮再说"。拍出来画面确实亮了,肉眼看也还行。重建出来崩了——142 万点里大部分是噪声点,物体表面全是颗粒,SSIM 0.52。
原因是相机 ISP 在高 ISO 下的降噪是把噪声糊成色块,肉眼看着"还行",但 3DGS 重建要的是高频细节,色块糊掉之后重建算法把色块边界当成细节,产出大量虚假高斯点。高 ISO + ISP 降噪的组合对 3DGS 是毒药,肉眼能接受的画面重建出来未必能用。
改方案是 ISO 卡 800,欠曝的部分靠 NLM 预处理提信噪比,不靠 ISO 硬拉。代价是 100 lux 以下采集到的原始画面偏暗,但重建质量比 ISO 3200 好得多。
坑二:补光灯方案有效但采集姿势受限
第二版我们上补光灯,手持一个 200 流明的 LED 环绕采集。100 lux 环境加补光局部到 300 lux,SSIM 从 0.78 拉到 0.89,效果显著。但环绕到物体背面时,补光灯方向从正面变到背面,物体上的高光阴影分布完全变了,重建时背面区域出现色差。
要解决色差,补光方向得稳定。我们试过把补光灯绑在相机上(跟相机一起转),这样补光相对物体方向还是变。试过固定灯架双灯(不跟相机转),效果好但要求展厅能架灯,且采集范围被灯覆盖范围限死。补光方案在能架固定灯的小展柜有效,在自由走动的大展厅不实用。
最后我们的策略是分场景:文物展柜(小范围、能架灯)用固定补光,自由展厅(大范围、不能架灯)用 ISO 800 + NLM,过不了门禁的区域标"不建议采集"。
坑三:长曝光手抖模糊
第三版我们试过长曝光提光。三脚架固定相机,曝光拉到 1/4 秒,500 lux 下进光量翻几倍。画面亮了,重建出来 SSIM 0.91,看起来不错。但用户不可能都带三脚架。
手持 1/4 秒曝光,画面全糊。我们测了 5 个用户手持 1/15 秒曝光采集,3 个有可见模糊,重建 SSIM 都低于 0.7。手抖的模糊是运动模糊,NLM 降噪救不了——NLM 去的是高斯噪声,运动模糊是信号失真,不是噪声。手持采集曝光时间不能超过 1/30 秒,1/60 秒更安全。长曝光只在三脚架场景下可用,而三脚架场景在展厅里很少。
坑四:环境光传感器读数和实际采集照度不一致
第四个坑比较隐蔽。我们用环境光传感器读 lux 做门禁,读数 120 lux,判定可采。实际重建出来 SSIM 只有 0.72,比预期低。排查发现环境光传感器装在手机顶部,读的是手机所在位置的照度;采集时手机对着物体,物体所在位置的照度可能不同——物体在展柜里、手机在展柜外,展柜玻璃衰减了光。
这个差异在开放空间小,在展柜、橱窗这类有遮挡的场景大。我们的解法是门禁阈值留余量——开放空间门禁 100 lux,展柜场景门禁拉到 130 lux,多 30 lux 余量补偿传感器和物体的照度差。环境光传感器读数是手机位置的,不是物体位置的,有遮挡场景要留余量。理想方案是采集前让用户把手机贴近物体测一次,但操作太繁琐,余量方案够用。
照度检测与门禁判断:ArkTS 实现
采集前先测当前环境光,低于门禁直接提示用户,不要白拍一遍重建出来废。
// entry/src/main/ets/capture/LightGateChecker.etsimport{sensor}from'@kit.SensorKit';// 照度门禁检查:采集前判断环境光是否达标exportclassLightGateChecker{// 门禁阈值,低于此值不建议采集privatereadonlyluxGate:number=100;// 警告阈值,低于此值提示用户补光privatereadonlyluxWarn:number=200;// 读环境光传感器,返回当前照度asyncreadLux():Promise<number>{returnnewPromise((resolve:(v:number)=>void,reject:(e:Error)=>void):void=>{sensor.getSingleSensor(sensor.SensorId.AMBIENT_LIGHT).then((s:sensor.SingleSensor)=>{s.on('data',(data:sensor.AmbientLightResponse)=>{s.off('data');resolve(data.intensity);// 单位 lux});// 200 ms 超时,传感器可能没数据setTimeout(()=>{reject(newError('sensor timeout'));},200);}).catch((e:Error)=>{reject(e);});});}// 检查门禁,返回建议动作asynccheck():Promise<{pass:boolean;action:string;lux:number}>{letlux:number;try{lux=awaitthis.readLux();}catch(e){// 传感器不可用,放行但提示用户人工判断return{pass:true,action:'传感器不可用,请人工判断光照是否充足',lux:-1};}if(lux>=this.luxWarn){return{pass:true,action:'光照充足,可以采集',lux};}if(lux>=this.luxGate){return{pass:true,action:'光照偏暗,建议补光或移到亮处',lux};}return{pass:false,action:'光照不足,重建质量会崩,请补光或换位置',lux};}}调用侧在采集引导页调check(),门禁不过时灰掉"开始采集"按钮,显示当前 lux 和建议动作。这个门禁挡住了用户白拍 5 分钟重建出来废的体验,比事后告诉"重建失败"友好得多。
采集参数联动
照度确定后,ISO、曝光、降噪强度要联动调,不是固定值。
// entry/src/main/ets/capture/CaptureParamsTuner.ets// 按当前照度调采集参数exportfunctiontuneCaptureParams(lux:number):CaptureParams{// ISO 卡 800 上限,照度够时压低提画质constiso:number=lux>=500?100:lux>=200?400:800;// 曝光卡 1/60 上限,照度够时压短提锐度constexposureSec:number=lux>=500?1/125:lux>=200?1/80:1/60;// NLM 降噪强度,照度低时拉高constnlmStrength:number=lux>=500?0.3:lux>=200?0.6:0.9;return{iso,exposureSec,nlmStrength};}interfaceCaptureParams{iso:number;exposureSec:number;nlmStrength:number;}这套联动参数在我们测过的 500/200/100 lux 三档上验证过,50 lux 档没配因为门禁已挡。联动的好处是用户不用手动调三个参数,读一个 lux 就全定了。
注意一下下
- 环境光门禁 100 lux,低于此值重建 SSIM < 0.7 不可用,采集前用传感器挡
- 弱光门禁按机型分档,9030 上 100 lux 可用,9020 上要拉到 130 lux
- ISO 上限 800,再高配降噪也救不回,高 ISO + ISP 降噪对 3DGS 是毒药
- 曝光时间上限 1/60 秒(手持),1/30 秒开始有手抖模糊,长曝光仅三脚架可用
- NLM 预处理把门禁从 100 lux 下推到 80 lux,推不到 50 lux,信号欠曝找不回
- 图像超分提亮在 3DGS 上反效果,hallucination 比噪声更难处理,已放弃
- 补光灯在能架固定灯的小展柜有效,自由走动的大展厅不实用
- 采集参数按照度联动调,ISO/曝光/NLM 三者一起变,不是固定值
- 弱光下重建耗时翻倍,高斯点数暴涨 3~4 倍,渲染时同屏点数要重新预算
- 门禁挡在采集前,用环境光传感器读 lux,比事后报"重建失败"7 分 24 秒友好
- 环境光传感器读数是手机位置不是物体位置,展柜场景门禁留 30 lux 余量
- 门禁阈值只在我们测过的 3 台机器和 5 类物体上成立,换设备换物体要重测
- 照度越低设备差异越明显,弱光门禁按机型分档比统一门禁更准
- NLM 降噪强度按 ISO 联动调,固定值会在低噪声时过度平滑丢细节
- Spatial Recon Kit 体验保证仅覆盖麒麟 9020/9030S/9030/9030 Pro 及后续旗舰
下一步哦
我们正在把照度门禁做成动态的:不同物体类型门禁不同——高反光青铜器门禁要拉高到 200 lux(反光在弱光下更难重建),毛绒玩具门禁可以降到 80 lux(纹理高频,弱光下还能保留特征)。目前门禁是固定 100 lux,未来按物体类型分档。物体类型识别可以复用端侧 AI 检测,但要评估模型加载和采集管线的资源争用。
第二个想验证的是多帧降噪——同一角度连拍 3 帧做平均,等效降一档 ISO 的噪声,代价是采集时间翻 3 倍。多帧降噪在静态展品上可行(展品不动),自由走动场景不行(人走动时多帧对不齐)。如果后续 API 不变的话,先在静态展品场景试多帧降噪,自由走动场景还是单帧+NLM。
第三个想做的是把弱光门禁和展厅导览联动——展厅地图上标出各区域照度,用户走到暗区时应用主动提示"此区域光照不足,3DGS 采集质量受限"。这个要做展厅照度地图的预采集,一次测完各区域 lux,后续用户采集时按位置查地图提示。展厅方那边对这个功能有兴趣,他们也想用这张地图优化展品布光,算是顺带帮他们做了一张照度热力图。