4. 增益一致性补偿:多帧间模拟增益与数字增益的归一化处理
好,咱们接着聊。上一章我们把多帧之间的亮度跳变问题拆开了,发现根源之一就是增益不一致。这一章,我们就专门来解决这个「增益」的问题。
说白了,HDR合成时,不同曝光帧的增益设置往往不一样。暗帧为了提亮,增益拉得很高;亮帧为了不饱和,增益压得很低。这些增益差异如果不做归一化,合成出来的图像就会出现亮度断层,甚至闪烁。
我个人习惯把增益分成两类:模拟增益和数字增益。这两兄弟虽然都叫增益,但脾气完全不同。
4.1 模拟增益 vs 数字增益:谁更「干净」?
先看一个简单的对比表格,帮你快速建立印象:
| 特性 | 模拟增益(Analog Gain) | 数字增益(Digital Gain) |
|---|---|---|
| 作用位置 | ADC 转换之前(传感器端) | ADC 转换之后(ISP 端) |
| 噪声影响 | 放大信号的同时也放大噪声,但信噪比基本不变 | 放大信号和噪声,但会额外放大量化噪声 |
| 动态范围 | 会压缩传感器动态范围 | 不影响传感器动态范围 |
| 线性度 | 高(模拟电路线性度好) | 极高(数字计算线性度完美) |
| 典型值范围 | 1x ~ 16x(受硬件限制) | 0.25x ~ 256x(理论上限更高) |
你想想看,模拟增益是在信号还没被数字化之前就放大了。它放大的「原始信号」里虽然也有噪声,但那个噪声是传感器本身的物理噪声,比较「自然」。数字增益就不一样了,它是在 ADC 已经量化完之后再乘一个系数。量化误差、截断误差,都会被一起放大。
核心原则:能用模拟增益解决的,尽量不用数字增益。模拟增益带来的噪声更「干净」,数字增益容易把量化噪声放大到肉眼可见的程度。
我在项目中遇到过一件事:某款 sensor 的模拟增益最高只能到 8x,但暗帧需要 16x 的增益才能提亮到目标亮度。没办法,只能用 8x 模拟 + 2x 数字的组合。结果暗帧的噪声明显比纯模拟 16x 的 sensor 要差一截。嗯,这就是硬件的天花板。
4.2 增益归一化的数学基础
归一化听起来高大上,其实公式很简单。我们定义每一帧的总增益为:
G_total = G_analog × G_digital
归一化的目标,就是把所有帧的增益统一到一个参考帧上。通常我会选中曝光帧作为参考,因为它的增益最接近 1x,噪声水平也最均衡。
假设参考帧的总增益是 G_ref,当前帧的总增益是 G_cur,那么归一化系数就是:
K_norm = G_ref / G_cur
然后,把当前帧的像素值乘以 K_norm,就完成了增益归一化。就这么简单?嗯,理论上是,但实际工程里有两个坑。
4.2.1 坑一:增益不是线性叠加的
模拟增益和数字增益的噪声特性不同,不能简单地把它们合并成一个系数来处理。我曾经踩过这个坑:直接把 G_total 算出来,然后对整帧做乘法。结果暗帧的噪声被放大了,亮帧的细节被压没了。
正确的做法是:分别处理模拟增益和数字增益的归一化。
// 伪代码:分通道增益归一化
float analog_norm = ref_analog_gain / cur_analog_gain;
float digital_norm = ref_digital_gain / cur_digital_gain;
// 先做模拟增益归一化(在 RAW 域做)
for each pixel in raw_image:
pixel = pixel * analog_norm;
// 再做数字增益归一化(在 ISP 处理后的线性域做)
for each pixel in linear_image:
pixel = pixel * digital_norm;
为什么要分开?因为模拟增益归一化应该在 RAW 域做,这时候噪声模型还是 sensor 的物理模型。数字增益归一化可以在更后面的线性域做,不影响噪声分布。
4.2.2 坑二:增益值不是整数
很多 sensor 的增益寄存器值不是直接的倍数,而是用 dB 表示的。比如 6dB 对应 2x,12dB 对应 4x。你需要先转成线性倍数:
G_linear = 10^(G_dB / 20)
或者有些 sensor 用 0.3dB 步进,那就更麻烦了。我建议在驱动层就把增益统一转成 float 类型的线性倍数,上层算法直接拿这个值算归一化系数,省心。
注意:不同 sensor 的增益映射表可能不同。有些 sensor 的模拟增益和数字增益是耦合的,调整模拟增益时数字增益会自动跟着变。这种情况下,你需要从 sensor 的驱动里读出「实际生效的增益值」,而不是你设置的目标值。
4.3 实战:多帧增益归一化流程
下面是我在实际项目中用的一套流程,你可以直接参考:
- 采集增益元数据:每一帧曝光时,从 sensor 驱动读出当前的模拟增益和数字增益(线性倍数)。
- 选择参考帧:通常选中曝光帧,或者选增益最接近 1x 的那一帧。
- 计算归一化系数:分别计算模拟增益和数字增益的归一化系数。
- RAW 域补偿:在 RAW 图像上应用模拟增益归一化系数。
- 线性域补偿:在去马赛克后的线性 RGB 图像上应用数字增益归一化系数。
- 亮度对齐验证:用直方图或平均亮度检查各帧是否对齐。
这个流程看起来简单,但每一步都有细节。比如第 4 步,在 RAW 域做乘法时要注意位宽。如果 RAW 数据是 12bit,乘以一个大于 1 的系数可能会溢出。我一般会先左移几位,留出余量,等做完归一化再右移回来。
小技巧:如果 sensor 不支持独立读取模拟增益和数字增益,你可以通过改变曝光时间来间接控制增益。曝光时间每翻一倍,等效于增加 1x 的增益。但要注意,曝光时间太长会导致运动模糊,这是个 trade-off。
4.4 增益归一化的知识体系
为了让你更直观地理解整个增益归一化的脉络,我画了一张流程图:
4.5 避坑指南
最后,分享几个我亲身踩过的坑,希望能帮你省点时间:
- 增益值不是线性映射的:有些 sensor 的增益寄存器值 0x10 对应 1x,0x20 对应 2x,但 0x30 可能对应 4x 而不是 3x。一定要查 datasheet 确认映射关系。
- 数字增益不要超过 4x:超过 4x 的数字增益,量化噪声会被放大到肉眼可见的条带。如果必须用,建议配合降噪算法一起使用。
- 注意帧间增益跳变:如果两帧之间的增益差异超过 4x,归一化后暗帧的噪声会非常明显。这时候可以考虑用多帧降噪来压制噪声。
- 别忘了黑电平:做增益归一化之前,一定要先减去黑电平。否则黑电平也会被放大,导致暗部偏色。
一句话总结:增益归一化的本质,就是把不同曝光帧的「放大倍数」统一到同一个基准上。模拟增益在 RAW 域做,数字增益在线性域做,分开处理,噪声更干净。