2、图像传感器基础:CMOS传感器工作原理、Bayer阵列与RAW数据、传感器接口协议
做AI ISP,第一件事不是调算法,而是搞懂传感器。你想想看,整个图像处理管线的源头就是传感器输出的RAW数据。源头如果搞不清楚,后面再怎么调也是白搭。
我个人习惯,拿到一块新的传感器模组,先不看数据手册里的电气参数,而是先搞清楚它的像素结构、输出格式和接口时序。这三样搞明白了,后面写驱动、调ISP心里才有底。
2.1 CMOS传感器工作原理
CMOS传感器,说白了就是一个像素阵列加一套读出电路。每个像素里有一个光电二极管和一个放大器。光打在二极管上产生电荷,电荷量跟光照强度成正比。然后通过行选、列选的方式,把每个像素的电压值依次读出来。
这里有个关键点:曝光方式。CMOS传感器主要分两种:
- 卷帘快门(Rolling Shutter):逐行曝光,逐行读出。成本低,但拍运动物体会产生果冻效应。
- 全局快门(Global Shutter):所有像素同时曝光,同时读出。没有果冻效应,但像素结构复杂,填充因子低。
经验之谈:做AI ISP时,如果场景里有高速运动目标(比如自动驾驶、工业检测),尽量选全局快门。我曾在一个人脸识别门禁项目里用了卷帘快门,结果人脸快速转动时图像扭曲,算法直接崩了。后来换成全局快门,问题解决。
还有一个容易被忽略的参数——满阱容量(Full Well Capacity)。它决定了像素能存多少电荷,直接影响动态范围。满阱越大,高光越不容易过曝。
| 参数 | 典型值 | 影响 |
|---|---|---|
| 满阱容量 | 10k~100k e⁻ | 动态范围、信噪比 |
| 转换增益 | 30~150 µV/e⁻ | 灵敏度、读出噪声 |
| 暗电流 | 10~100 e⁻/s | 暗场噪声、热像素 |
| 读出噪声 | 1~10 e⁻ rms | 低光照下的信噪比 |
2.2 Bayer阵列与RAW数据
CMOS传感器本身只能感知光的强度,分不清颜色。那彩色图像怎么来的?答案是Bayer阵列——在像素表面覆盖一层彩色滤光片(CFA),每个像素只允许一种颜色通过。
最常见的Bayer模式是RGGB:
R G R G ...
G B G B ...
R G R G ...
G B G B ...
...
为什么绿色像素比红蓝多一倍?因为人眼对绿色最敏感。这个设计是Bryce Bayer在1976年提出的,一直用到现在。
避坑指南:我曾经在调试一个4K传感器时,发现图像偏绿。查了半天,原来是驱动里把Bayer顺序配错了。传感器输出的是BGGR,我按RGGB去解,颜色当然不对。所以拿到新传感器,第一件事就是确认Bayer顺序。
RAW数据就是传感器直接输出的、未经任何处理的像素值。每个像素12bit或10bit,按Bayer排列。RAW数据有几个关键特征:
- 线性响应:像素值与光照强度成正比(未做伽马校正)
- 高位深:通常10~14bit,比8bit的JPEG细腻得多
- 未去马赛克:每个像素只有一种颜色,需要插值才能变成全彩
- 包含传感器噪声:暗电流、读出噪声、固定模式噪声都在里面
做AI ISP时,我强烈建议直接用RAW数据做训练和推理。为什么?因为RAW保留了完整的传感器信息,没有经过ISP的压缩和失真。AI模型可以从RAW里学到更真实的噪声分布和颜色响应。
注意:不同传感器的RAW格式不通用。Sony的RAW和OmniVision的RAW,位深、排列、黑电平值都不一样。写ISP时一定要按传感器数据手册来解析。
2.3 传感器接口协议
传感器和ISP芯片之间怎么传数据?目前主流的有三种接口:
| 接口 | 带宽 | 线数 | 典型应用 |
|---|---|---|---|
| DVP(并行) | ~100 Mbps | 10~12根数据线 | 低分辨率、老平台 |
| MIPI CSI-2(串行) | ~10 Gbps | 1~4对差分线 | 手机、车载、安防 |
| LVDS(串行) | ~3 Gbps | 4~8对差分线 | 工业、医疗、高速 |
现在最常用的是MIPI CSI-2。它用差分信号传输,抗干扰能力强,带宽也够。MIPI的物理层叫D-PHY,分1.0、1.2、2.0版本,速率从80 Mbps/lane到4.5 Gbps/lane不等。
MIPI CSI-2的协议层定义了数据包格式:
帧开始(FS) → 行数据包1 → 行数据包2 → ... → 帧结束(FE)
每个行数据包:
[包首] [RAW像素数据] [包尾]
包首:数据类型(RAW10/RAW12等)、行号、ECC校验
包尾:CRC校验
嗯,这里要注意:MIPI的时序要求很严格。差分对的阻抗要控制在100Ω±10%,走线长度要匹配,否则信号质量会下降。我见过一个项目,传感器和ISP之间距离长了5cm,结果图像出现条纹。后来加了均衡器才解决。
个人经验:调试MIPI接口时,先用示波器看差分信号的眼图。眼图张开得越大,信号质量越好。如果眼图闭合,先检查阻抗匹配和走线长度,别急着调软件。
除了物理层,还有控制接口——I²C或SPI。传感器寄存器配置、曝光时间、增益设置都通过这个接口来写。我习惯把传感器初始化流程写成结构体数组,清晰又好维护:
// 传感器初始化序列示例
struct sensor_reg {
uint16_t addr;
uint16_t value;
};
const struct sensor_reg init_seq[] = {
{0x0103, 0x01}, // 软件复位
{0x0100, 0x00}, // 进入待机
{0x0305, 0x04}, // PLL配置
{0x0307, 0x38}, // 分频系数
{0x0340, 0x07}, // 帧长高字节
{0x0341, 0xD0}, // 帧长低字节
{0x0342, 0x0B}, // 行长高字节
{0x0343, 0xA0}, // 行长低字节
{0x0100, 0x01}, // 退出待机
};
最后,我把本章的核心知识点画成一张图,方便你理解传感器到ISP的数据流:
这张图把从光信号到ISP接收的完整链路串起来了。每个环节都有坑,后面章节我会逐个展开讲怎么处理。