输入质量门禁:分辨率/帧数/覆盖率的拒绝策略

用户随手拍两张就点重建,输入烂得没法看,重建出来的 3DGS 场景一堆浮点、墙面破洞、家具边缘飘出半空。这种垃圾结果用户不会怪自己拍得差,只会怪应用"重建效果不行"。我们在入口加了一道质量门禁,在重建开始前就把明显不行的输入挡回去。门禁的难点不是写检测代码,是把阈值定在"既不烦人也不放过垃圾"的那个窄区间里。

能力面:输入质量检测的五个维度

Spatial Recon Kit 提供 spatialRecon.inspectInput(frames, options),返回质量报告。检测维度五个:分辨率(每帧宽高)、帧数(总帧数,少于 60 直接拒绝)、覆盖率(相机轨迹对物体的环绕覆盖比例,0-1)、模糊度(每帧清晰度,基于拉普拉斯方差)、光照(平均亮度和动态范围)。

报告里每个维度给一个数值和 pass/warn/fail 三态判定。inspectInput 是同步快速检测(80-150ms),不阻塞太久。覆盖率检测会跑一遍特征点匹配,是五个维度里最贵的,约占总检测时间 60%。

把这五个维度串起来就是一道质量门禁,任一硬指标不通过就挡回并引导补采:

不足 80 帧

通过

低于 0.45

通过

超出 30 到 250lux

通过

低于 0.5 且置信度低于 0.6

低于 0.5 且置信度高

通过

采集帧输入

inspectInput 五维快速检测

帧数检测

拒绝并引导补采

模糊度检测

光照检测

覆盖率检测

降级为 warn
提示多拍几个角度

放行进入重建

分辨率不在拒绝链上,它只出 warn,把选择权交回用户。

约束面:门禁阈值与拒绝后的引导

阈值定在哪是核心问题。定太严,用户按引导拍一圈还是被拒,体验崩;定太松,垃圾输入放进去重建出垃圾结果,用户骂重建效果。我们测了三档阈值:

阈值档分辨率帧数覆盖率模糊度光照通过率重建合格率
严格≥1080p≥120≥0.7≥0.650-200lux38%92%
中等≥720p≥80≥0.5≥0.4530-250lux71%78%
宽松≥540p≥60≥0.35≥0.3520-300lux89%61%

我们最后选了中等档。严格档通过率太低,内测时 10 个用户有 6 个拍第一次就被拒,第二次也没过,直接放弃。宽松档放过去太多垃圾输入,重建合格率 61% 意味着 4 成用户看到破模型。中等档妥协——71% 用户一次能过,剩下 29% 给引导重拍,重拍后 80% 能过。

阈值不是写死的,按场景调。商品展示用中等档;户型重建用严格档,因为大空间重建失败成本更高。门禁要跟着场景走,不能一套阈值打天下。

场景落地:5 种输入的门禁实测

Mate 90(9030)上跑了 5 种典型输入,看门禁判定和实际重建质量:

输入类型分辨率帧数覆盖率模糊度光照门禁判定重建 PSNR用户评分
高质量1080p1800.780.72120luxpass28.4dB4.6/5
低分辨率540p1800.720.68120luxwarn(分辨率)24.1dB3.2/5
少帧1080p450.320.71120luxfail(帧数+覆盖)——
模糊1080p1800.650.28120luxfail(模糊度)——
暗光1080p1800.700.558luxfail(光照)——

几个观察:低分辨率被 warn 而不是 fail,540p 重建出来虽然不锐利但能用,让用户自己决定,实测 70% 用户看到 warn 会重拍。少帧同时触发帧数和覆盖率两个 fail,门禁只报第一个命中的,避免一次给一堆问题。暗光 8lux 相当于昏暗走廊,重建特征点提取失败率 90%+,必须 fail。模糊输入是用户边走边大幅晃动拍的,整段没一帧清楚,门禁直接 fail 引导"请放慢移动速度"。

踩坑:覆盖率检测误判

覆盖率检测是五个维度里最容易误判的。算法逻辑:从输入帧里抽几帧做特征点匹配,看相机轨迹覆盖了物体多少角度。问题出在两个 case:

Case 1:重复纹理物体。用户拍对称花纹抱枕,环绕一圈,算法把对称的两段轨迹识别成同一段,覆盖率报 0.35,实际是 0.7。门禁 fail,用户重拍还是 fail,骂应用"我明明拍了一圈"。

Case 2:平面物体。用户拍海报贴墙,环绕拍,但物体是平的没有深度变化,特征点匹配在纯平面上不稳定,覆盖率报 0.4,实际重建质量没问题。

修复方式是给覆盖率检测加置信度字段。置信度低(<0.6)时,覆盖率 fail 降级为 warn,让用户选择继续。同时 UI 提示"覆盖检测不确定,建议多拍几个角度",把判断权交回用户。

// entry/src/main/ets/recon/InputGate.ets
import { spatialRecon, InputReport } from '@kit.SpatialReconKit';

export class InputGate {
  // 门禁主入口:返回 'pass' | 'warn' | 'fail' + 原因 + 引导建议
  static async check(frames: string[]): Promise<{
    decision: 'pass' | 'warn' | 'fail';
    reasons: string[];
    guide: string;
  }> {
    const report: InputReport = await spatialRecon.inspectInput(frames, {
      checkResolution: true, checkFrameCount: true, checkCoverage: true,
      checkBlur: true, checkLighting: true,
    });

    const reasons: string[] = [];
    let worst: 'pass' | 'warn' | 'fail' = 'pass';

    // 帧数、模糊度、光照是硬指标,fail 就 fail
    if (report.frameCount.level === 'fail') { reasons.push('帧数不足,至少拍 80 帧'); worst = 'fail'; }
    if (report.blur.level === 'fail') { reasons.push('画面模糊,请放慢移动速度'); worst = 'fail'; }
    if (report.lighting.level === 'fail') { reasons.push('光线太暗,请到明亮处重拍'); worst = 'fail'; }

    // 覆盖率看置信度:置信度低时 fail 降级为 warn
    if (report.coverage.level === 'fail') {
      if (report.coverage.confidence < 0.6) {
        reasons.push('覆盖检测不确定,建议多拍几个角度');
        worst = worst === 'fail' ? 'fail' : 'warn';
      } else {
        reasons.push('环绕覆盖不足,请绕物体完整一圈');
        worst = 'fail';
      }
    }

    // 分辨率 warn 不升级到 fail
    if (report.resolution.level === 'warn') {
      reasons.push('分辨率偏低,重拍更清晰');
      worst = worst === 'pass' ? 'warn' : worst;
    }

    return { decision: worst, reasons, guide: reasons.length > 0 ? reasons[0] : '可以开始重建' };
  }
}

这段代码的关键是覆盖率 fail 要看置信度,不能盲信算法。我们一开始没加置信度判断,对称物体场景投诉率突然上来一批。加了降级后,对称物体的 fail 率从 100% 降到 30%(真覆盖不足的 case 该 fail 还是 fail)。

被放弃的方案:试过把覆盖率检测整个关掉,靠帧数和模糊度兜底。结果户型重建场景翻车——用户只拍正面和两个侧面,背面没拍,重建出来背面是大洞。覆盖率检测必须开,但要带置信度。

门禁规则表(中等档,商品展示场景)

维度检测方法warn 阈值fail 阈值检测耗时误判率
分辨率取首帧宽高<720p<540p<5ms0%
帧数计数<100<80<5ms0%
覆盖率特征点匹配+轨迹拟合<0.6<0.560-90ms12%(对称物体)
模糊度拉普拉斯方差<0.5<0.4515-25ms3%
光照平均亮度+动态范围<50lux 或 >200lux<30lux 或 >250lux10-15ms5%

总检测耗时约 90-140ms,用户感知不到延迟。覆盖率检测是大头,其他几个维度都是逐帧轻量计算。

真机数据:门禁前后的重建合格率对比

商品展示场景跑了 200 次真实用户采集,统计门禁开启前后:

指标无门禁中等档门禁
进入重建的比例100%71%(29% 被引导重拍)
重建完成率82%96%
重建结果合格率(PSNR ≥24dB)61%87%
用户平均重拍次数1.01.3
用户放弃率18%(看到垃圾结果放弃)9%(被门禁拒后放弃)

门禁把"看到垃圾结果放弃"的 18% 转化成了"重拍后成功"的多数。总放弃率从 18% 降到 9%,这是门禁最大的价值——不是挡用户,是把"必然失败的重建"提前变成"重拍一次能成"。

几个细节

  • inspectInput 在低端机上耗时翻倍,覆盖率检测能到 200ms。我们给低端机关掉覆盖率检测,只留帧数和模糊度,门禁宽松一档。
  • 模糊度检测对暗光场景会误报——画面本来就暗,拉普拉斯方差天然偏低。模糊度和光照联合判:光照 fail 时模糊度不单独 fail。
  • 覆盖率检测采样帧数影响精度和耗时。默认采 12 帧,对称物体场景调到 20 帧,误判率从 12% 降到 7%。
  • 门禁 UI 提示要具体。"输入质量不佳"是废话,"光线太暗,请到明亮处重拍"才是引导。

注意哦

  • 门禁阈值要按场景定,商品展示和户型重建不能共用一套

  • 覆盖率检测必须带置信度,低置信度时 fail 降级为 warn

  • 模糊度和光照要联合判,暗光场景模糊度不单独 fail

  • 门禁只报第一个命中的 fail,避免一次给一堆问题

  • 低端机可以关掉覆盖率检测,门禁降档

  • 门禁的目的是引导重拍,不是挡用户,通过率别低于 60%

门禁跑通后,下一步收集真实用户的 fail 原因分布。我们内测一周数据是覆盖率 fail 占 47%、模糊度 fail 占 28%、光照 fail 占 15%、帧数 fail 占 10%。覆盖率是大头,说明引导里"绕物体完整一圈"没讲清楚,下一步改引导 UI 加动画示意。下一篇会拆重建失败降级,那是门禁没挡住、重建过程中出问题的 6 种 case。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐