4. 数字前端与预处理:数字增益、黑电平校正、坏点校正、镜头阴影校正
各位同学,欢迎来到第四章。前面我们聊了模拟前端和ADC,传感器吐出来的原始数据终于变成了数字信号。但别高兴太早,这数据还“脏”得很。
我打个比方:这就像你从菜市场买回来的带泥土豆。数字前端要干的活,就是洗土豆、削皮、切块。说白了,就是一系列预处理操作。今天咱们就聊聊这四个最基础的模块:数字增益、黑电平校正、坏点校正和镜头阴影校正。
这四个模块,在ISP流水线里通常排在最前面。它们处理得好不好,直接影响后面所有模块的效果。我个人习惯,在设计硬件架构时,会先把这几个模块的吞吐量和位宽算清楚,不然后面很容易出问题。
4.1 黑电平校正(BLC)
先说说黑电平校正。你想想看,一个完美的图像传感器,在完全无光的环境下,输出应该是0。但现实不是这样的。由于暗电流、像素漏电、ADC偏移等原因,传感器在暗场下会输出一个非零的基底值。这个基底值,就是黑电平。
黑电平校正的目的很简单:把这个基底减掉。公式就是:
P_out = P_raw - BLC_offset
但这里有个坑。BLC_offset 不是固定不变的。它会随着温度、增益、曝光时间变化。我遇到过一款传感器,温度每升高10度,黑电平就往上跳2个LSB。如果不做动态校正,画面暗部就会偏色。
关键点:黑电平校正必须在数字增益之前做。为什么?因为如果你先放大信号,黑电平噪声也会被放大。先减掉基底,再放大,信噪比更好。
实际工程中,BLC 有两种实现方式:
- 静态BLC:从寄存器读一个固定值,直接减。适合低端方案,成本低。
- 动态BLC:从传感器周边的光学黑像素(OB像素)实时统计平均值,动态更新offset。我建议中高端方案都用这种,效果稳定很多。
| 对比项 | 静态 BLC | 动态 BLC |
|---|---|---|
| 硬件开销 | 低(一个减法器) | 中(加法器+统计模块) |
| 温度适应性 | 差 | 好 |
| 适用场景 | 监控、低端摄像头 | 手机、车载、医疗 |
⚠️ 注意:BLC 减完后,可能会出现负值。硬件上必须做钳位处理,把负值截断到0。否则后面模块会出问题。
4.2 数字增益
数字增益,说白了就是把像素值乘上一个系数。模拟增益不够用?数字增益来凑。但这里有个代价:数字增益会放大量化噪声。
公式很简单:
P_gain = P_blc * gain_coeff
gain_coeff 通常用定点数表示,比如 12 位精度。我习惯用 1.12 格式,也就是 1 位整数加 12 位小数。这样精度够用,硬件实现也不复杂。
数字增益的硬件实现,核心就是一个乘法器。但要注意位宽扩展。举个例子:
- 输入是 12 位数据
- 增益系数是 1.12 格式(13 位)
- 乘法结果就是 25 位
- 最终输出需要截断或舍入到 12 位
我曾经在一个项目里,因为截断方式没选好,导致画面出现明显的条带噪声。后来改用了带抖动的舍入,问题才解决。嗯,这里要注意,舍入方式对画质影响很大。
💡 工程建议:数字增益不要超过 4x(12dB)。超过这个范围,噪声会变得非常明显。如果确实需要更高增益,建议先提升模拟增益。
4.3 坏点校正(DPC)
传感器生产过程中,难免会有一些像素点坏了。坏点分两种:
- 亮点(Hot Pixel):一直输出高值,看起来像白点
- 暗点(Dead Pixel):一直输出低值,看起来像黑点
坏点校正的思路,就是用周围正常像素的值来“猜”坏点的值。常用的方法有:
- 均值滤波:取周围 3x3 或 5x5 邻域的平均值
- 中值滤波:取邻域的中值,抗噪能力更强
- 梯度方向插值:沿边缘方向插值,保留细节更好
我个人的经验是,中值滤波在硬件实现上性价比最高。它不需要乘法器,只需要比较器和排序网络。在 FPGA 上,一个 3x3 的中值滤波器,大概消耗 200 个 LUT 左右。
坏点检测 vs 校正:DPC 分为两步。第一步是检测,判断当前像素是不是坏点。第二步才是校正。检测算法可以用固定阈值,也可以用动态阈值。动态阈值更可靠,但硬件开销也更大。
坏点表(Defect Table)也是个好东西。在产线标定时,把坏点的坐标存到 OTP 里。运行时直接查表,不用实时检测。我建议量产方案都加上这个功能。
4.4 镜头阴影校正(LSC)
最后一个,镜头阴影校正。这个问题,你拿手机拍一张纯白墙壁的照片就能看到:画面中心亮,四周暗。这就是镜头阴影,也叫亮度渐晕。
原因有两个:
- 光学原因:镜头边缘的光线入射角大,到达传感器的光量少
- 像素原因:边缘像素的感光角度导致量子效率下降
LSC 的做法,就是对每个像素乘上一个增益系数。中心区域增益接近 1.0,边缘区域增益大于 1.0。这个增益分布,通常用一个二维网格来存储。
P_lsc(x, y) = P_raw(x, y) * gain_table[x][y]
增益网格的生成,需要在产线标定。用均匀光源拍一张灰卡,然后计算每个像素需要的增益。网格分辨率通常是 16x16 或 32x32,中间的点用双线性插值得到。
| 网格分辨率 | 存储开销(16bit) | 插值精度 | 适用场景 |
|---|---|---|---|
| 8x8 | 128 字节 | 低 | 低端摄像头 |
| 16x16 | 512 字节 | 中 | 主流手机 |
| 32x32 | 2 KB | 高 | 高端相机 |
⚠️ 注意:LSC 的增益系数可能很大,边缘区域可能达到 2x 甚至 3x。这会放大边缘区域的噪声。所以有些方案会在 LSC 之后加一个边缘降噪模块。
还有一个细节:LSC 的增益系数是浮点数,硬件实现时要用定点数。我习惯用 1.8 格式,也就是 1 位整数加 8 位小数。精度够用,乘法器面积也小。
4.5 硬件架构要点总结
好了,四个模块都讲完了。最后我总结一下硬件设计时要注意的几个点:
- 数据位宽:每个模块都会扩展位宽,要提前规划好。我一般从 12 位输入,内部保留 16 位,最后输出 12 位。
- 流水线深度:这四个模块可以串行处理,每级加 1-2 个时钟周期的流水线。总延迟大概 5-8 个时钟周期。
- 控制接口:每个模块都需要寄存器配置。建议用 APB 或 I2C 总线,统一管理。
- 统计信息:BLC 和 LSC 都需要统计信息。可以在模块内部加一个小型的统计引擎,避免占用主控 CPU。
这章的内容就到这里。记住,预处理做得好,后面的 ISP 模块才能发挥最大效果。别小看这几个基础模块,它们决定了整个图像质量的底线。