3. RAW图数据格式:RAW10/RAW12/RAW14、黑电平与坏点校正、RAW图存储与读取
各位做ISP调优的同行,咱们今天聊聊RAW图。这是整个图像处理管线的起点,也是决定画质上限的关键。我见过不少工程师一上来就调RGB或者YUV,结果发现怎么调都调不好——说白了,根儿上的RAW数据就没处理好。
RAW图是什么?就是Sensor直接输出的原始数据,没经过任何处理。它保留了最完整的场景信息,但也带着Sensor本身的瑕疵。咱们这一章就把RAW的格式、校正和存储讲透。
3.1 RAW数据格式:RAW10 / RAW12 / RAW14
Sensor输出的RAW数据,每个像素用多少比特来表示,这就是位深。常见的位深有10bit、12bit、14bit。你可能会问:为什么不用8bit?嗯,8bit只有256个灰阶,对于安防监控这种需要暗部细节的场景,根本不够用。
| 位深 | 灰阶数 | 动态范围 | 典型应用 |
|---|---|---|---|
| RAW10 | 1024 | 约60dB | 低端IPC、USB摄像头 |
| RAW12 | 4096 | 约72dB | 主流安防摄像机 |
| RAW14 | 16384 | 约84dB | 高端AI摄像机、车载 |
我个人习惯把位深理解为「精度」。RAW10就像一把毫米尺,RAW14就是一把游标卡尺。在暗光场景下,RAW14能分辨出更细微的亮度差异,后期提亮时不容易出现色阶断层。
3.2 黑电平校正
黑电平,英文叫Black Level,简称BL。Sensor在完全无光的情况下,理论上应该输出0,但实际上会有一个偏移值。这个偏移就是黑电平。
为什么会这样?Sensor的像素在暗电流和读出电路噪声的共同作用下,会有一个基础电压。如果不把这个偏移减掉,整个图像会偏灰,暗部细节被淹没。
黑电平校正的公式很简单:
校正后像素值 = 原始像素值 - 黑电平值
但实际做的时候有几个坑:
- 黑电平不是固定值——它会随温度、增益、曝光时间变化。我建议在每一帧的OB(Optical Black)区域实时采样,动态计算。
- 不同通道的黑电平可能不同——R、Gr、Gb、B四个通道的暗电流特性有差异,需要分别校正。
- 黑电平校正后要钳位——减完可能变成负数,必须钳位到0。
3.3 坏点校正
Sensor的像素阵列里,总会有一些「坏」的像素。它们要么一直亮(白点),要么一直暗(黑点),要么响应异常。这些坏点如果不处理,在图像上就是固定位置的噪点,非常显眼。
坏点校正分两步:
- 坏点检测——找出哪些像素是坏的。
- 坏点替换——用周围像素的值把坏点补上。
检测方法我常用两种:
- 静态检测:在出厂前,用均匀光源拍一张图,找出偏离均值超过阈值的像素,生成坏点表。
- 动态检测:在运行中,比较当前像素和周围8邻域的差异,如果差异过大,判定为坏点。
替换方法也有讲究:
// 中值替换——对孤立坏点效果好
pixel_out = median(pixel_left, pixel_right, pixel_up, pixel_down)
// 均值替换——对坏点簇效果好
pixel_out = (pixel_left + pixel_right + pixel_up + pixel_down) / 4
3.4 RAW图存储与读取
RAW图怎么存?常见的有两种格式:
| 格式 | 存储方式 | 优点 | 缺点 |
|---|---|---|---|
| Packed | 连续比特流,无浪费 | 节省存储空间 | 读取时需要位操作,速度慢 |
| Unpacked | 每个像素对齐到字节 | 读取快,方便处理 | 浪费存储空间 |
举个例子,RAW12的Packed格式:每3个像素占36bit,正好4.5个字节。而Unpacked格式,每个像素占2字节(16bit),浪费了4bit。
我个人习惯在调试阶段用Unpacked格式,方便用文本工具查看。量产时再切到Packed,节省带宽和存储。
读取RAW图时,要注意Bayer Pattern的排列顺序。常见的Bayer格式有BGGR、RGGB、GRBG、GBRG四种。读错顺序,图像颜色就全乱了。
// 以BGGR为例,读取一个像素
uint16_t read_raw_pixel(uint8_t *raw_data, int x, int y, int width) {
// 计算偏移:y * width + x
int offset = y * width + x;
// 如果是RAW12 Unpacked,每个像素占2字节
return ((uint16_t *)raw_data)[offset];
}
好了,RAW图的基础知识就这些。下一节咱们开始讲ISP管线中的第一个处理模块——去噪。不过那是后话了,先把RAW数据吃透,后面的路才好走。