2、图像传感器基础:CCD与CMOS传感器区别、Bayer阵列原理、Sensor驱动与初始化
好,咱们开始第二讲。这一章是ISP调试的基石——图像传感器。说白了,你后面所有调优工作,都是建立在传感器把光转成电信号这个第一步上的。如果这一步没搞明白,后面调得再好也是白搭。
我个人习惯,拿到一个新项目,第一件事就是看Sensor的datasheet。不看清楚它的底细,你连它输出的数据对不对都不敢保证。咱们今天就把CCD和CMOS的区别、Bayer阵列的原理、以及Sensor怎么驱动起来,一次性讲透。
2.1 CCD与CMOS传感器:两种主流技术路线
先聊聊传感器本身。目前市面上主流的图像传感器就两种:CCD和CMOS。你可能会问,现在手机、相机不都是CMOS吗?CCD是不是过时了?嗯,也不完全是。
2.1.1 CCD传感器
CCD,全称电荷耦合器件。它的工作方式很有意思——每个像素点收集到的光生电荷,需要像接力棒一样,一行一行地传递到输出端,最后统一转换成电压信号。
优点:
- 噪声低,画质干净。这是它最大的优势。
- 填充因子高,感光面积大。
- 一致性非常好,每个像素的响应很均匀。
缺点:
- 功耗高。我记得以前用CCD的相机,拍一会儿机身就发热。
- 读取速度慢。因为要串行传输,帧率上不去。
- 成本高,工艺复杂。
- 不支持局部读取,灵活性差。
我的经验:CCD现在主要用在工业检测、天文摄影、医疗影像这些对画质要求极高、对速度不敏感的领域。消费电子领域基本被CMOS取代了。
2.1.2 CMOS传感器
CMOS,互补金属氧化物半导体。它跟CCD最大的不同在于——每个像素点旁边都自带一个放大器,直接把电荷转成电压信号输出。说白了,就是每个像素都有自己的“小喇叭”,不用排队等传递。
优点:
- 功耗低,省电。
- 读取速度快,轻松做到高帧率。
- 成本低,工艺跟主流芯片制造兼容。
- 支持窗口读取、Binning等灵活操作。
缺点:
- 噪声相对较大。每个像素的放大器一致性不如CCD。
- 填充因子低,部分面积被电路占用了。
避坑指南:我曾经在一个项目中,选了一款低成本的CMOS传感器,结果暗光下噪声大得离谱。后来才发现,它的像素尺寸太小,信噪比根本不够。所以选型时,像素尺寸和工艺制程一定要看仔细。
2.1.3 两者对比总结
| 特性 | CCD | CMOS |
|---|---|---|
| 噪声 | 低 | 较高 |
| 功耗 | 高 | 低 |
| 读取速度 | 慢 | 快 |
| 成本 | 高 | 低 |
| 灵活性 | 差 | 好 |
| 主流应用 | 工业、医疗、科研 | 手机、相机、安防、汽车 |
2.2 Bayer阵列原理:为什么传感器拍出来是彩色的?
好,传感器把光转成了电信号,但有个问题——它只能感知光的强度,分不清颜色。那彩色照片是怎么来的?这就得靠Bayer阵列了。
说白了,Bayer阵列就是在每个像素前面盖一层彩色滤光片。滤光片的排列方式很有讲究,最常见的是RGGB模式:
- 50%的像素是绿色(G)
- 25%的像素是红色(R)
- 25%的像素是蓝色(B)
为什么绿色占一半?因为人眼对绿色最敏感。你想想看,自然界中绿色信息最多,所以多分配一些像素给绿色,能更好地还原细节。
关键点:每个像素只记录一种颜色。要得到完整的彩色图像,必须通过插值算法把缺失的颜色算出来。这个过程就叫去马赛克(Demosaic),是ISP pipeline中非常重要的一步。
我刚开始做ISP时,总觉得Bayer阵列很简单。直到有一次,我调试一个低光照场景,发现图像边缘全是彩色伪影。查了半天,原来是去马赛克算法没处理好。嗯,这里要注意,Bayer阵列的排列方向(是RGGB还是BGGR)必须跟Sensor的配置一致,否则颜色会完全错乱。
2.2.1 常见的Bayer排列模式
| 模式 | 排列方式 | 常见厂商 |
|---|---|---|
| RGGB | 第一行:R G R G... 第二行:G B G B... |
Sony、OmniVision |
| BGGR | 第一行:B G B G... 第二行:G R G R... |
部分Samsung |
| GRBG | 第一行:G R G R... 第二行:B G B G... |
部分安防Sensor |
警告:配置Bayer模式时,一定要跟Sensor的datasheet核对。我曾经见过一个团队,因为搞错了Bayer顺序,整个项目的图像颜色都是反的,排查了整整两天。
2.3 Sensor驱动与初始化:让传感器开始工作
好了,理论讲完了,咱们来点实际的。怎么让Sensor开始干活?
Sensor驱动和初始化,说白了就是通过I2C或SPI总线,往Sensor的寄存器里写配置值。每个寄存器控制着Sensor的一个功能,比如曝光时间、增益、帧率、输出格式等等。
2.3.1 初始化流程
我一般按这个步骤来:
- 上电时序:先给Sensor供电,然后提供主时钟(MCLK),最后拉高复位引脚。顺序不能乱,否则Sensor可能无法正常启动。
- 读取ID:通过I2C读取Sensor的芯片ID,确认通信正常。这一步很重要,能快速排查硬件连接问题。
- 写入初始配置:按照datasheet推荐的初始化序列,写入一组寄存器值。包括输出分辨率、帧率、增益模式、Bayer排列等。
- 等待稳定:配置完成后,等待几帧时间,让Sensor内部PLL锁定,输出稳定的图像数据。
- 检查输出:通过MIPI或DVP接口抓取一帧数据,验证图像是否正常。
我的习惯:我会把初始化序列写成一个数组,每个元素包含寄存器地址和值。这样方便调试时增删改查。另外,我会在初始化完成后,回读几个关键寄存器,确认写入成功。
2.3.2 代码示例:I2C初始化Sensor
下面是一个简化的初始化代码示例,用伪代码表示:
// Sensor初始化函数
int sensor_init(void) {
// 1. 上电时序
sensor_power_on();
delay_ms(10);
// 2. 读取芯片ID
uint16_t chip_id = i2c_read(0x0000);
if (chip_id != 0x1234) {
printf("Error: Sensor ID mismatch!\n");
return -1;
}
// 3. 写入初始化序列
const reg_config_t init_seq[] = {
{0x0100, 0x00}, // 软件复位
{0x0103, 0x01}, // 进入配置模式
{0x0340, 0x02}, // 输出分辨率高字节
{0x0341, 0xD0}, // 输出分辨率低字节 (720p)
{0x0202, 0x00}, // 曝光时间高字节
{0x0203, 0x64}, // 曝光时间低字节 (100行)
{0x0204, 0x01}, // 增益高字节
{0x0205, 0x00}, // 增益低字节 (1x)
{0x0100, 0x01}, // 退出配置模式,开始输出
};
for (int i = 0; i < sizeof(init_seq)/sizeof(init_seq[0]); i++) {
i2c_write(init_seq[i].addr, init_seq[i].value);
delay_ms(1);
}
// 4. 等待稳定
delay_ms(100);
// 5. 回读验证
uint16_t check = i2c_read(0x0100);
if (check != 0x01) {
printf("Warning: Sensor not in streaming mode!\n");
return -2;
}
return 0;
}
注意:不同Sensor的初始化序列差异很大。有些Sensor需要先写入PLL配置,再设置分辨率。有些则必须先设置输出格式。一定要严格按照datasheet的时序要求来,否则Sensor可能输出花屏或者根本不工作。
2.3.3 常见问题与调试技巧
- I2C通信失败:检查上拉电阻、电压电平是否匹配。我遇到过好几次,因为电平不匹配导致通信不稳定。
- 输出花屏:大概率是MIPI lane配置不对,或者时钟频率不匹配。用示波器量一下MCLK和MIPI clock。
- 图像全黑或全白:检查曝光时间和增益是否设置合理。全黑可能是曝光时间太短,全白可能是增益太大。
- 颜色不对:检查Bayer排列模式是否配置正确。这个前面强调过了。
我的经验:调试Sensor时,我习惯先让它输出一个简单的测试图案(很多Sensor内置测试图案生成器)。如果测试图案正常,说明硬件和驱动没问题。然后再切换到正常模式,逐步排查图像质量问题。这样能快速定位是Sensor问题还是ISP问题。
好了,这一章的内容就到这里。CCD和CMOS的区别、Bayer阵列的原理、Sensor驱动初始化,这三块是ISP调试的入门必修课。下一章咱们会深入聊聊ISP pipeline的各个模块,从黑电平校正开始。到时候见。