2. Bayer RAW数据格式与预处理:从传感器到可处理图像的第一步
各位同学,欢迎来到第二章。上一章我们聊了ISP的整体架构,今天咱们把镜头拉近,看看ISP流水线的第一站——Bayer RAW数据。说白了,这就是图像传感器最原始的“底片”。
我刚开始接触ISP时,觉得Bayer Pattern不就是个马赛克嘛,有啥好研究的?后来在项目中吃过亏才明白,这一块要是没吃透,后面所有算法都是在沙子上盖楼。好,咱们正式开始。
2.1 Bayer Pattern详解——传感器的“单色”世界
图像传感器本身是色盲的。它只能感知光的强度,分不清颜色。那彩色照片怎么来的?答案就是Bayer Pattern——在传感器每个像素上覆盖一层滤色片,只让特定颜色的光通过。
最常见的Bayer Pattern是RGGB,也就是一个像素点阵里,红色、绿色、绿色、蓝色按2x2排列。为什么绿色有两个?因为人眼对绿色最敏感,传感器也模仿这个特性。
| Pattern名称 | 排列方式(2x2) | 常见应用场景 |
|---|---|---|
| RGGB | R G / G B | 索尼、三星主流传感器 |
| GRBG | G R / B G | 安森美、部分OV传感器 |
| GBRG | G B / R G | 部分老款CCD |
| BGGR | B G / G R | 柯达、部分工业相机 |
关键点:硬件实现时,Bayer Pattern的起始位置(即第一个像素是R还是G)必须与ISP配置一致。我见过一个项目,因为Sensor驱动里Pattern配置写反了,整张图偏色到离谱,排查了两天才找到原因。
硬件上怎么处理?很简单——每个像素只存一个颜色值,12bit或10bit。后续的Demosaic模块才会把缺失的颜色插值出来。但在此之前,我们得先做几件“脏活累活”。
2.2 黑电平校正(BLC)——把“零”找回来
理想情况下,没有光输入时,像素输出应该是0。但现实是,传感器有暗电流,即使全黑环境也会读出一个小信号,比如64(12bit下)。这个值就是黑电平。
BLC的目的就是把这个偏移减掉。公式很简单:
P_out = P_raw - BLC_offset
但硬件实现时要注意几点:
- BLC_offset怎么来? 传感器通常有光屏蔽像素(OB像素),硬件会实时统计这些像素的平均值作为BLC_offset。我建议不要用固定值,因为温度变化会影响暗电流。
- 减法后可能变负数。 硬件必须做饱和处理,把负值钳位到0。
- 分通道校正。 R、G、B通道的暗电流可能不同,最好每个通道独立统计。
我的经验: 在FPGA上实现BLC时,用流水线结构,每个时钟周期处理一个像素。统计OB像素时,用滑动平均滤波器,避免单帧噪声影响。
2.3 镜头阴影校正(LSC)——把“暗角”抹平
你有没有拍过一张四角发暗的照片?那就是镜头阴影(Lens Shading)。原因是镜头中心进光量多,边缘进光量少。LSC就是给边缘像素“补光”。
硬件实现思路:
- 增益矩阵。 预先标定一张均匀光照下的图像,计算每个像素位置需要的补偿增益。通常存成一张查找表(LUT)。
- 插值计算。 因为增益矩阵不可能每个像素都存(太费内存),一般存网格点,比如16x16或32x32。运行时用双线性插值算出当前像素的增益。
- 乘法与饱和。 像素值乘以增益后,要检查是否溢出12bit范围。
| 网格密度 | 内存占用(12bit增益) | 精度 |
|---|---|---|
| 16x16 | 256 x 2字节 = 512字节 | 中等 |
| 32x32 | 1024 x 2字节 = 2KB | 较高 |
| 64x64 | 4096 x 2字节 = 8KB | 高 |
注意: LSC增益不能太大,一般不超过4倍。我曾经遇到一个项目,边缘增益设到6倍,结果噪声被放大得惨不忍睹。LSC之后通常要接降噪模块,就是这个原因。
硬件流水线设计上,LSC模块需要知道当前像素的坐标(x, y),然后查表、插值、乘加。这个模块的延迟通常控制在几个时钟周期内。
2.4 坏点校正(DPC)——把“死像素”修掉
传感器生产过程中,难免有几个像素是坏的——要么一直亮(亮点),要么一直暗(暗点),要么随机跳动(闪点)。DPC就是把这些坏点替换成周围正常像素的值。
硬件实现分两步:
- 坏点检测。 比较当前像素与周围8邻域像素的差值。如果差值超过阈值,就判定为坏点。阈值可以固定,也可以自适应(根据局部亮度)。
- 坏点替换。 用中值滤波或均值滤波的结果替换坏点。我个人习惯用中值,因为对边缘保护更好。
// 伪代码:坏点检测与替换
if (abs(P_center - median(neighbors)) > threshold) {
P_out = median(neighbors);
} else {
P_out = P_center;
}
硬件加速技巧: DPC需要3x3窗口,在FPGA上可以用Line Buffer实现行缓存。3行数据同时送入窗口,每个时钟周期输出一个像素的处理结果。注意,坏点检测只在Bayer域做,不要等Demosaic之后再做,那样会引入颜色串扰。
嗯,这里还要提一个坑。坏点列表(Defect Pixel List)通常由传感器厂商提供,但运行过程中还会出现新的坏点。我建议硬件保留一个“动态坏点检测”模式,每隔一段时间重新扫描全图,更新坏点表。
2.5 预处理流水线的硬件架构
把BLC、LSC、DPC串起来,就是ISP预处理的核心流水线。下面这张图展示了数据流:
这张图里,数据从左到右流经BLC、DPC、LSC。每个模块都是独立的流水级,用Valid/Ready信号握手。为什么是这个顺序?
- BLC先做:因为后面的DPC和LSC都依赖正确的黑电平。如果黑电平没减干净,坏点检测的阈值会偏。
- DPC在LSC之前:坏点替换应该在增益补偿之前做,否则坏点被放大后更难检测。
- LSC最后:增益补偿会放大噪声,但这是必要的代价。后续的降噪模块会处理。
硬件资源估算: 以1080p@60fps为例,像素时钟约148.5MHz。BLC只需要一个减法器,DPC需要3行Line Buffer(约6KB)和比较器,LSC需要增益LUT(2KB)和插值器。整个预处理模块在FPGA上大约消耗500-800个LUT,非常轻量。