4. MFNR与HDR融合的协同设计

好,我们进入第四章。这一章我个人觉得是整个实战课程里最“工程”的一环。你算法再牛,模型再准,上了平台跑不动、发热、掉帧,那都是白搭。MFNR 和 HDR 融合,说白了就是两个吃带宽、吃算力的大户。怎么让它们在一个 Pipeline 里和睦共处,还能把高通平台的性能压榨到极致?这就是我们今天要聊的。

4.1 协同设计的核心矛盾:谁先谁后?

先问一个问题:MFNR 和 HDR 融合,到底谁先处理?

你可能会想,这还不简单?先做 MFNR 降噪,再做 HDR 合成呗。我在项目初期也是这么干的。结果呢?一跑起来,发现 HDR 合成后的鬼影问题特别严重。为什么?因为 MFNR 把多帧对齐后的残差给抹平了,HDR 模块拿到的帧之间差异太小,反而没法准确检测运动区域。

所以,Pipeline 的调度顺序,直接决定了最终画质。我个人习惯的做法是:

  1. 先做粗对齐:基于运动矢量的快速对齐,分出静态区和运动区。
  2. HDR 融合优先处理运动区:对运动区域做短曝光融合,避免鬼影。
  3. MFNR 处理静态区:对静态区域做多帧降噪,保留细节。
  4. 最后做边缘融合:把两个区域的结果平滑拼接。

核心原则:HDR 负责“动态范围”,MFNR 负责“信噪比”。两者在空间域上做分工,而不是在时间域上串行。

4.2 Pipeline 调度:从“串行”到“并行流水线”

高通平台的 ISP 是一个硬件 Pipeline,它不像 CPU 那样可以随便乱序执行。你得按照硬件模块的物理顺序来排任务。我画了一张典型的调度架构图,你看看就明白了。

MFNR与HDR融合Pipeline调度架构 MFNR 与 HDR 融合 Pipeline 调度架构 Sensor RAW 输入 Bayer 域预处理(BPC/LSC/ABF) 运动检测 & 粗对齐 运动区 → HDR 融合 短曝光合成 + 防鬼影 静态区 → MFNR 降噪 多帧对齐 + 空域降噪 边缘融合 & 后处理输出 关键:运动区走 HDR 路径,静态区走 MFNR 路径,最后合并

你看,这个架构里最关键的就是那个“分叉点”。运动检测模块在这里扮演了交通警察的角色。它告诉后面的模块:哪些像素是动的,哪些是静的。动的交给 HDR,静的交给 MFNR。

实战技巧:运动检测的阈值不要设死。我建议根据场景亮度动态调整——暗光下运动检测阈值要放宽,否则 MFNR 会把运动模糊当成噪声来降,结果就是鬼影+模糊双重暴击。

4.3 带宽优化:别让 DDR 成为瓶颈

高通平台的 ISP 通常有独立的带宽预算。比如某款 8 系列芯片,ISP 到 DDR 的总带宽是 12GB/s。你算算看:4K 60fps 的 RAW 数据流,一帧大约 24MB,60 帧就是 1.44GB/s。这还只是单路。MFNR 要读 3-5 帧,HDR 要读 2-3 帧,再加上写回,带宽很容易就爆了。

怎么优化?我总结了几条经验:

优化手段 原理 带宽节省 注意事项
Tile 处理 将图像切成 64x64 的块,逐块处理 30%-50% Tile 边界需要 overlap,否则有拼接痕迹
压缩传输 使用 DPCM 或 Huffman 压缩 RAW 数据 40%-60% 有损压缩会影响 SNR,建议用无损或近无损
帧缓存复用 MFNR 和 HDR 共享同一组帧缓存 20%-30% 需要仔细管理生命周期,防止踩内存
降采样预处理 对运动检测等模块使用 1/2 分辨率 75% 只适用于非关键路径,主路径仍用全分辨率

我曾经踩过的坑:在某个项目里,我为了省带宽,把 MFNR 的对齐模块也做了降采样。结果对齐精度下降,导致融合后的图像边缘有重影。后来我学乖了——对齐和降噪必须用全分辨率,运动检测和统计信息可以用降采样。

4.4 功耗优化:每一毫瓦都要花在刀刃上

功耗是手机影像的永恒痛点。你想想看,用户拍一张夜景,如果手机烫得能煎鸡蛋,谁还愿意用?

高通平台的 DVFS(动态电压频率调整)和 Clock Gating 是我们手里的两把刀。我的优化策略是:

  • 按需开启 ISP 管线:MFNR 不需要全部 ISP 模块都跑。比如 HDR 融合时不需要的模块,直接 Clock Gating 掉。
  • 动态调整帧率:暗光下 MFNR 需要 4-5 帧,但预览时其实 3 帧就够了。我建议在 capture 阶段才开满帧率,preview 阶段降帧运行。
  • DDR 频率自适应:带宽需求低的时候,把 DDR 频率降下来。这个在高通平台上有现成的 API,叫 devfreq。
// 伪代码:动态带宽管理示例
void mfnr_hdr_pipeline_optimize(int scene_lux) {
    if (scene_lux < 50) {
        // 暗光场景:MFNR 为主,HDR 为辅
        set_isp_clock(ISP_CLOCK_HIGH);   // 提高 ISP 频率
        set_ddr_freq(DDR_FREQ_MID);      // 中等带宽
        enable_module(MFNR_CORE, TRUE);
        enable_module(HDR_CORE, FALSE);  // HDR 降功耗
    } else if (scene_lux < 500) {
        // 室内场景:两者均衡
        set_isp_clock(ISP_CLOCK_MID);
        set_ddr_freq(DDR_FREQ_HIGH);     // 高带宽,因为要同时读写
        enable_module(MFNR_CORE, TRUE);
        enable_module(HDR_CORE, TRUE);
    } else {
        // 白天场景:HDR 为主,MFNR 降采样
        set_isp_clock(ISP_CLOCK_LOW);
        set_ddr_freq(DDR_FREQ_LOW);
        enable_module(MFNR_CORE, TRUE);  // 降采样模式
        enable_module(HDR_CORE, TRUE);
    }
}

4.5 QoS 策略:给关键任务插队

高通平台的系统总线是共享的。GPU、Display、Video、ISP 都在抢带宽。如果没有 QoS(服务质量)策略,ISP 的数据流可能会被其他模块堵住,导致掉帧。

QoS 说白了就是给 ISP 开“绿色通道”。我一般这样配置:

  1. ISP 读写请求优先级设为最高:在 msm_bus 驱动里设置 priority = 0(0 为最高)。
  2. 预留带宽:给 ISP 预留 30% 的 DDR 带宽,防止被 GPU 抢走。
  3. 设置超时机制:如果某个 Tile 处理超时,直接丢弃该 Tile,保证整帧的实时性。

关键指标:QoS 配置好后,用 perfetto 抓一次 trace,看看 ISP 的“等待时间”占比。如果超过 5%,说明 QoS 没配好,需要调整。