1. RAW图基础概念:从传感器到数字图像的“底片”

大家好,我是你们的老朋友。今天咱们正式开始聊RAW图调试。说实话,做了这么多年图像传感器调试,我见过太多工程师一上来就对着BMP/JPG猛调,结果越调越懵。为什么?因为你根本没见过原始数据长什么样。这就像摄影师不懂胶片,直接看冲印好的照片去调色——能调好才怪。

所以,第一节课,咱们先把RAW图这个“底片”彻底搞明白。你想想看,所有图像质量的根基,其实都在这张RAW图里。

1.1 什么是RAW图?

RAW图,说白了就是图像传感器(CMOS/CCD)直接输出的、未经任何处理的原始数据。它记录的是每个像素点感受到的光强度——注意,是光强度,不是颜色。

我习惯把RAW图比作“数字底片”。你拍胶片时,底片记录的是化学反应的灰度信息;而RAW图记录的是每个感光单元上的电子数量。嗯,这里要注意:RAW图不是图像,它是数据

核心要点:RAW图 = 传感器原始电荷量 → 量化后的数字值。它没有颜色,没有白平衡,没有伽马校正,什么都没有。就是一堆数字。

我记得刚入行时,有个老工程师跟我说:“你什么时候能把RAW图看成是‘电压值’,而不是‘图像’,你就入门了。” 这句话我到现在都觉得是真理。

1.2 RAW图 vs BMP/JPEG:本质区别在哪?

很多新手会问:都是图片,RAW图跟BMP、JPEG到底差在哪?我直接给你列个表,一目了然。

对比项 RAW图 BMP JPEG
数据本质 传感器原始电荷量 RGB三通道像素值 压缩后的YUV数据
位深 10bit/12bit/14bit等 8bit(通常) 8bit
颜色空间 Bayer Pattern(单通道) RGB(三通道) YUV(三通道)
是否压缩 无损(或轻微压缩) 无损 有损压缩
可编辑性 可调白平衡、去马赛克等 基本不可逆调整 压缩后信息丢失
文件大小 极大(如12MP约24MB) 较大(如12MP约36MB) 小(如12MP约3-5MB)

你看,RAW图是“原材料”,BMP是“半成品”,JPEG是“成品”。调试ISP时,我们永远只跟RAW图打交道。因为一旦转成BMP或JPEG,很多原始信息就丢了——比如暗部细节、高光过曝区域的真实亮度。

我的经验:曾经有个项目,客户反馈夜景噪点大。我一看他们给的测试图,是JPEG格式。我直接让他们重新抓RAW图。结果发现,JPEG压缩把暗部噪点“抹平”了,但同时也抹掉了细节。最终问题出在去马赛克算法上,跟降噪无关。如果只看JPEG,你永远找不到根因。

1.3 Bayer Pattern详解:为什么传感器不直接输出RGB?

好,接下来是重点中的重点——Bayer Pattern。你可能会问:为什么传感器不直接输出RGB三通道?非要搞个单通道的Bayer格式?

原因很简单:成本。每个像素点如果都要同时感知红绿蓝三种光,那需要三个感光单元叠在一起,工艺复杂、成本翻倍。所以工业界想了个聪明的办法:每个像素只感知一种颜色,然后通过算法猜出另外两种颜色。

这个“猜”的过程,就叫去马赛克(Demosaic)。而Bayer Pattern,就是定义每个像素感知什么颜色的规则。

常见的Bayer Pattern类型

最常见的Bayer Pattern有四种:RGGB、GRBG、BGGR、GBRG。名字怎么来的?看左上角2x2像素块的排列顺序。

Pattern名称 左上角2x2排列 常见传感器品牌
RGGB R G
G B
Sony、OmniVision(多数)
GRBG G R
B G
Samsung(部分)
BGGR B G
G R
Onsemi(部分)
GBRG G B
R G
少数特殊传感器

你可能会问:为什么绿色像素占一半?因为人眼对绿色最敏感。所以Bayer Pattern里,绿色像素数量是红色和蓝色的两倍。这个设计很巧妙——用更多的绿色像素来模拟人眼的亮度感知

避坑指南:我曾经在调试一款新传感器时,默认用了RGGB的配置,结果图像偏色严重。查了两天才发现,那个传感器用的是GRBG。记住:拿到新传感器,第一件事就是确认Bayer Pattern。别想当然。

1.4 RAW图的数据存储格式

最后,咱们聊聊RAW图在内存或文件里是怎么存的。这直接关系到你怎么读数据、怎么调试。

1.4.1 位深(Bit Depth)

RAW图最常见的位深是10bit、12bit、14bit。什么意思?每个像素用多少位二进制数来表示它的亮度值。

  • 10bit:0-1023,共1024个灰度级。常见于手机传感器。
  • 12bit:0-4095,共4096个灰度级。常见于安防、车载传感器。
  • 14bit:0-16383,共16384个灰度级。常见于专业相机、工业相机。

位深越高,动态范围越大,但数据量也越大。我习惯说:位深决定了你能看到多暗的细节和多亮的高光

1.4.2 存储格式:Raw10、Raw12、Raw14

存储时,为了节省空间,通常不会直接用16bit或32bit去存。而是用“打包”的方式。

格式名称 实际位深 存储方式 每像素占用bit数
Raw10 10bit 4个像素打包成5字节(40bit) 10bit
Raw12 12bit 2个像素打包成3字节(24bit) 12bit
Raw14 14bit 4个像素打包成7字节(56bit) 14bit
Raw16 16bit(实际用14bit) 每个像素2字节,高位补0 16bit

举个例子,Raw10的打包方式:4个10bit像素(共40bit)存成5个字节。读取时,你需要按位操作才能还原出每个像素的值。嗯,这里要注意:不同厂商的打包顺序可能不同,有的高位在前,有的低位在前。

实战代码片段:读取Raw10数据(假设小端模式)

// 假设buf是5字节的Raw10数据
// 提取4个10bit像素
uint16_t pixel0 = (buf[0] & 0xFF) | ((buf[1] & 0x03) << 8);
uint16_t pixel1 = ((buf[1] >> 2) & 0xFF) | ((buf[2] & 0x0F) << 6);
uint16_t pixel2 = ((buf[2] >> 4) & 0xFF) | ((buf[3] & 0x3F) << 4);
uint16_t pixel3 = ((buf[3] >> 6) & 0xFF) | ((buf[4] & 0xFF) << 2);

你看,这代码看着就头疼。所以我建议:调试时先用工具(如RawViewer、dcraw)把RAW图转成16bit的PGM或TIFF,这样读起来方便。等算法稳定了,再优化成打包格式。

1.4.3 数据排列顺序

RAW图的数据是按行存储的。每一行里,像素按照Bayer Pattern的顺序排列。比如RGGB的传感器,第一行是R、G、R、G...,第二行是G、B、G、B...

所以,当你把RAW图当成一个二维数组时,它的形状是:

行0: R G R G R G ...
行1: G B G B G B ...
行2: R G R G R G ...
行3: G B G B G B ...
...

这个排列顺序,决定了你去马赛克算法怎么取邻域像素。我见过有人把行顺序搞反了,结果图像出现“棋盘格”伪影——嗯,那画面太美我不敢看。

我的习惯:拿到RAW图后,第一件事就是画一个2x2的像素块,确认Bayer Pattern。然后检查行顺序是否正确。这一步花不了5分钟,但能省你后面5小时的调试时间。

小结

好了,第一节课的内容就到这里。咱们回顾一下:

  • RAW图是传感器的原始电荷数据,不是图像。
  • 与BMP/JPEG的区别在于位深、颜色空间、可编辑性。
  • Bayer Pattern定义了每个像素感知的颜色,常见RGGB/GRBG等。
  • 存储格式涉及位深、打包方式、行排列顺序。

下一节课,咱们会深入讲怎么用工具查看RAW图,以及如何判断一张RAW图的质量好坏。到时候我会分享一个我踩过的坑——关于“坏像素”的误判,保证让你少走弯路。

咱们下节课见。