4、RAW图预处理与Bayer格式优化
RAW图预处理,说白了就是图像质量的第一道防线。我做了这么多年嵌入式相机,发现很多后期调不好的问题,根子都在RAW阶段没处理好。今天咱们就聊聊Bayer格式、坏点校正和黑电平校正这几个硬骨头。
4.1 Bayer Pattern格式:RGGB与GRBG
先说说Bayer格式。CMOS传感器每个像素只能感知亮度,要得到彩色图像就得靠滤色片阵列。最常见的Bayer Pattern有RGGB和GRBG两种。
你想想看,一个2x2的像素块里,RGGB是左上角红色、右上和左下绿色、右下蓝色。GRBG呢?左上绿色、右上红色、左下蓝色、右下绿色。就这么个排列差异,搞不好整个图像就偏色了。
关键点: Bayer格式决定了后续插值算法的参考方向。选错Pattern,图像会整体偏移一个像素。
我在项目中遇到过一件事:某款传感器手册写的是RGGB,结果实际输出是GRBG。团队按RGGB做了三个月算法,一上硬件全偏色。后来我让测试组直接拍一张纯白画面,用脚本统计四个通道的均值,才揪出这个问题。
| Bayer类型 | 2x2排列 | 常见传感器 | 插值起点 |
|---|---|---|---|
| RGGB | R G / G B | Sony IMX系列 | 左上R |
| GRBG | G R / B G | OmniVision多数型号 | 左上G |
| BGGR | B G / G R | 部分安森美传感器 | 左上B |
| GBRG | G B / R G | 少数工业相机 | 左上G |
我个人习惯在驱动初始化阶段,用寄存器读取Bayer ID,而不是硬编码。这样换传感器时不用改算法层代码。
4.2 坏点校正(DPC)算法优化
坏点,就是传感器上那些永远亮或永远暗的像素。每个传感器都有,只是多少的问题。DPC算法要做的,就是把这些坏点找出来,然后用周围像素的值把它填上。
DPC分两步:检测和校正。检测阶段,我常用的是中值比较法。拿当前像素和周围8个邻域比,如果差值超过阈值,就标记为坏点。
// 简化的坏点检测逻辑
uint8_t is_dead_pixel(uint16_t center, uint16_t neighbors[8]) {
uint16_t median = get_median(neighbors, 8);
uint16_t diff = abs(center - median);
uint16_t threshold = 40; // 经验值,需根据传感器调整
return (diff > threshold) ? 1 : 0;
}
校正方法呢?我推荐用加权平均。别用简单的均值,那样会模糊边缘。加权平均给距离近的像素更高权重,效果好很多。
经验之谈: 阈值不要设死。我习惯根据ISO值动态调整阈值——ISO越高,噪声越大,阈值也要跟着放大。否则高ISO下全是假坏点。
算法优化上,有几个坑要注意:
- 不要逐帧全图检测:坏点位置是固定的,检测一次存下来就行。我见过有人每帧都跑检测,CPU占用直接飙到30%。
- 坏点表要持久化:第一次上电检测后,把坏点坐标存到Flash里。下次开机直接加载,省掉检测时间。
- 边界处理要小心:图像边缘的像素没有完整邻域,我一般直接跳过不检测,或者用镜像填充。
注意: 坏点校正不能替代传感器标定。如果坏点数量超过传感器总像素的0.1%,建议直接联系供应商换货。算法只能补救,不能根治。
4.3 黑电平校正(BLC)的硬件加速思路
黑电平校正,说白了就是消除暗电流带来的偏置。传感器在全黑环境下应该输出0,但实际上会有个固定偏置值。BLC就是把这个偏置减掉。
软件做BLC很简单:每个像素减去一个固定值。但问题是,这个减法在嵌入式平台上很费时间。一张200万像素的RAW图,逐像素做减法,ARM Cortex-A7上大概要花8-10ms。
怎么加速?我给出三个思路:
- 查表法:把减法结果预计算好,存成LUT。输入像素值直接查表输出。代价是额外占用256字节或1024字节的RAM。
- SIMD优化:ARM平台的NEON指令集,一次可以处理16个像素。我实测过,NEON版本的BLC比C循环快4-5倍。
- ISP硬件模块:如果SoC集成了ISP,通常都有硬件BLC模块。配置几个寄存器就行,零CPU开销。
// NEON加速BLC示例(伪代码)
void blc_neon(uint16_t *raw, int size, uint16_t offset) {
uint16x8_t vec_offset = vdupq_n_u16(offset);
for (int i = 0; i < size; i += 8) {
uint16x8_t vec_pixel = vld1q_u16(&raw[i]);
uint16x8_t vec_result = vsubq_u16(vec_pixel, vec_offset);
vst1q_u16(&raw[i], vec_result);
}
}
我个人最推荐第三种方案。硬件加速不是非得用专用ISP,很多MCU的DMA模块也能做简单的算术操作。我曾经在一个STM32H7项目上,用DMA2D的填充加偏移功能,实现了零CPU开销的BLC。
核心思路: BLC的本质是逐像素减法。任何能并行处理多个像素的硬件单元——DMA、GPU、NEON、FPGA——都可以用来加速。别只盯着CPU。
4.4 本章知识体系
下面这张图把Bayer格式、DPC和BLC的关系串起来了。你看,RAW图进来后,先做BLC消除偏置,再做DPC修复坏点,然后才能做后续的Demosaic和颜色校正。顺序不能乱。
嗯,到这里RAW图预处理的核心内容就讲完了。Bayer格式选对、DPC算法优化好、BLC用硬件加速,这三件事做好了,后面的图像处理流程会顺畅很多。我曾经在一个项目上只优化了BLC和DPC,整条ISP流水线的帧率就从15fps提到了30fps——有时候性能瓶颈就在这些不起眼的预处理环节。