4. BPS(拜耳处理段)详解:HDR合成、多帧降噪的硬件流水线设计与带宽优化
好,咱们进入BPS。BPS全称是Bayer Processing Segment,说白了就是专门处理RAW图的那一段硬件。在高通ISP流水线里,BPS夹在IFE和IPE之间,位置很关键——它负责把多帧RAW数据揉成一帧高质量的图像,再送给后面的IPE去做色彩和细节处理。
我个人习惯把BPS看作ISP的“预处理车间”。这个车间里最重的活,就是HDR合成和多帧降噪。这两个功能都是多帧输入、单帧输出,对带宽和算力的要求极高。今天咱们就把它拆开来看。
4.1 BPS硬件流水线架构概览
先看整体结构。BPS内部不是一条直线走到底的,它分了好几个阶段,每个阶段都有专门的硬件加速器。
核心要点:BPS的流水线是“多入单出”的架构。它需要同时处理2~3帧RAW数据,然后在内部完成对齐、合成、降噪,最后输出一帧干净的Bayer图。
你看这个图,BPS的流水线是三级串联的:LDC(镜头畸变校正)→ HDR合成 → MNR(多帧降噪)。每一级都有独立的硬件加速器,可以并行处理多个像素块。
我记得第一次调BPS的时候,发现一个坑:如果LDC的查找表配置不对,后面的HDR合成会出现鬼影。后来我养成了一个习惯——先单独验证LDC的对齐精度,再开HDR。
4.2 HDR合成:硬件流水线设计
HDR合成,说白了就是把不同曝光时间的帧融合到一起。短曝光帧保留高光细节,长曝光帧保留暗部细节,中曝光帧做过渡。
高通的BPS支持两种HDR模式:
| 模式 | 输入帧数 | 曝光比 | 适用场景 | 带宽消耗 |
|---|---|---|---|---|
| 2帧HDR | 2 (短+长) | 1:16 ~ 1:64 | 白天逆光、室内外过渡 | 低 |
| 3帧HDR | 3 (短+中+长) | 1:4:16 ~ 1:8:64 | 夜景、大光比场景 | 高 |
硬件流水线里,HDR合成主要分三步:
- 运动检测:比较对齐后的帧之间是否有运动物体。如果有,要降低该区域的融合权重,否则会出现鬼影。
- 权重计算:根据像素亮度和运动检测结果,给每帧的每个像素算一个权重。亮的地方多采短帧,暗的地方多采长帧。
- 像素级融合:按权重把多帧数据加权平均,输出一帧HDR结果。
实战技巧:运动检测的阈值不要设得太死。我遇到过一个问题:阈值设低了,运动区域权重被过度压低,导致运动物体周围出现亮度跳变。后来我把阈值放宽了20%,鬼影没增加,画质反而更自然了。
4.3 多帧降噪(MNR):时域与空域协同
MNR是多帧降噪的缩写。它和HDR合成是前后脚的关系——HDR输出一帧融合后的图像,MNR再对这帧做降噪。
MNR的硬件流水线包含两个核心滤波器:
- 时域滤波器(Temporal Filter):利用当前帧和历史帧的差异来做降噪。静止区域可以大幅降噪,运动区域要保留细节。
- 空域滤波器(Spatial Filter):在单帧内做双边滤波或导向滤波,去除残留噪声。
这两个滤波器是串联的。先做时域,再做空域。为什么?因为时域滤波会引入运动模糊,空域滤波可以修复一部分边缘细节。
注意:MNR的时域滤波需要维护一个“历史帧缓冲区”。这个缓冲区的大小直接影响带宽。如果缓冲区太小,时域滤波的效果会大打折扣。我建议至少保留3帧历史数据。
4.4 带宽优化:从数据流角度切入
好,到了最核心的部分——带宽优化。BPS是ISP里最吃带宽的模块之一,原因很简单:它要同时处理多帧数据。
咱们算一笔账:
| 分辨率 | 帧率 | 单帧大小 (RAW10) | 3帧HDR带宽 | MNR额外带宽 | 总带宽 |
|---|---|---|---|---|---|
| 4K (3840x2160) | 30fps | ~24 MB | ~2.16 GB/s | ~0.72 GB/s | ~2.88 GB/s |
| 8K (7680x4320) | 30fps | ~96 MB | ~8.64 GB/s | ~2.88 GB/s | ~11.52 GB/s |
你看,8K分辨率下,BPS的带宽需求轻松超过10 GB/s。如果不做优化,DDR带宽很快就会被吃光。
我个人常用的优化手段有这几条:
- Tile-based处理:把图像切成小块(比如64x64),每个块独立处理。这样LDC的查找表可以复用,HDR的权重计算也可以局部化。
- 压缩传输:在IFE和BPS之间使用RAW压缩。高通支持一种叫“无损RAW压缩”的格式,压缩比大约1.5:1,几乎不损失画质。
- 帧率降采样:如果场景变化不大,可以降低MNR的输入帧率。比如从30fps降到15fps,带宽直接减半。
- DDR QoS配置:给BPS分配高优先级的DDR端口,避免被其他模块抢占带宽。
避坑指南:我曾经在一个项目里,BPS的带宽优化做得不够,结果导致HDR合成时出现“帧撕裂”——因为DDR带宽不足,BPS读帧的速度跟不上流水线。后来我加了一级内部FIFO缓冲,才把问题解决。所以,永远不要低估BPS的带宽需求。
4.5 实战:BPS流水线配置示例
最后,给一个实际的BPS配置示例。这是我在一个4K 60fps项目里用过的参数:
// BPS流水线配置
bps_config_t bps_cfg = {
.input_format = RAW10,
.output_format = RAW10,
.resolution = {3840, 2160},
.frame_rate = 60,
// HDR配置
.hdr_mode = HDR_3FRAME,
.exposure_ratio = {1, 4, 16},
.motion_threshold = 32, // 运动检测阈值
.fusion_weights = {0.25, 0.5, 0.25}, // 短/中/长权重
// MNR配置
.mnr_enable = true,
.temporal_strength = 0.7, // 时域滤波强度
.spatial_strength = 0.3, // 空域滤波强度
.history_frames = 3, // 历史帧数
// 带宽优化
.tile_size = {64, 64},
.raw_compression = true,
.ddr_priority = DDR_PRIO_HIGH
};
这个配置跑下来,BPS的带宽消耗大约在4.5 GB/s左右。如果不开压缩,这个数字会飙到6.8 GB/s。你看,压缩的收益非常明显。
嗯,BPS这块内容不少,但核心就三点:HDR怎么合、MNR怎么降噪、带宽怎么省。把这三点吃透了,BPS这块你就拿下了。