做机器视觉这些年,被问得最多的问题就是:CCD和CMOS到底差在哪?为什么工业相机还在用CCD?手机传感器是CMOS为什么画质也那么好?还有不少人把图像传感器领域的CMOS,和电脑主板上那个保存BIOS设置的纽扣电池混到一块去,一搜“cmos checksum error”还以为传感器坏了。
这篇文章就把CCD与CMOS图像传感器的原理、信号处理链路、选型思路和调试排查一次性讲清楚。不管你是做嵌入式视觉、工业相机选型,还是刚入行做图像信号处理,看完都能搞明白光信号是怎么一步步变成一张能用的数字图像,也清楚遇到画质问题该往哪个方向排查。
1. 图像传感器原理:光子是怎么变成数字图像的
1.1 像素结构:每个像素都是一个小水桶
图像传感器说白了就是一个极其密集的光子计数器阵列。每个像素的核心是一个光电二极管,光子照进来之后,在半导体内部激发出电子空穴对,电子被收集在势阱里,这个电荷量和入射光强基本成正比。
我习惯把像素比作一个小水桶:光子是往水桶里倒水,倒得越多水位越高,而水位就是最终要读出来的信号。这个比喻能帮你理解后面几乎所有概念。
像素在物理结构上并不是只有光电二极管一个组件。为了提升光线利用效率,像素上面还会做微透镜,把光汇聚到感光区域,否则相当一部分光会浪费在电路晶体管之间的缝隙里。另外,要得到彩色图像,还需要在像素上叠加彩色滤光片,最常见的就是拜耳阵列(Bayer pattern),用RGGB四像素一组还原色彩。
这里有个关键点:像素的势阱容量是有限的。电子装满之后,再有光子打进来也存不进去,图像就会表现为高光溢出、发白一片。这就是“满阱容量”参数的意义,后面选型部分会详细展开。
1.2 CCD和CMOS的本质区别:电荷搬运工与独立加工厂
CCD和CMOS的底层感光原理完全一样,都是光电效应,区别只在于“读出方式”。
CCD像一条流水线:所有像素的光生电荷,需要在时钟脉冲驱动下,像水桶接力一样逐行逐列往外传,最后从唯一的输出端口统一读出。这个过程叫电荷耦合转移。因为最终只有一个输出放大器,而且电荷转移过程非常规矩,所以CCD像素间的一致性极好,读出噪声可以做得非常低。代价就是,要想读出快,就得把电荷转移的时钟频率拉得极高,驱动功耗和电路复杂度都跟着上去。
CMOS则像每一个像素都有自己的独立加工厂。每个像素旁边自带一个放大器(也就是常说的有源像素传感器APS),通过行列寻址开关,直接读出每个像素的电压信号。好处是读出速度快、集成度高、功耗低,甚至可以把时序控制、ADC、ISP都做进同一颗芯片里。代价是,每颗像素的放大器都有工艺偏差,导致像素间响应不一致,会出现固定模式噪声(FPN),需要靠后期校正去压。
所以本质说完,CCD适合追求极致画质、弱光性能、高一致性的场景;CMOS适合追求速度、功耗、集成度的大众场景。近十年来CCD在消费领域几乎被CMOS完全替代,但在部分科学级、工业级领域,CCD依然有位置。
2. 信号处理链路:从RAW到一张能看的图
2.1 模拟前端:读出噪声怎么被压下去
传感器输出端给出的不是现成的数字图像,而是一系列模拟电压信号,电平非常弱,尤其是暗光环境下,一个像素可能只有几毫伏的输出。
这时候模拟前端(AFE)要做三件关键的事:
第一件事是相关双采样(CDS)。像素复位后会有一个复位电平,这个电平每次都有随机抖动,叫做复位噪声(kTC噪声)。CDS的思路是先采样复位电平,再采样光信号转移后的电平,两者相减,就把复位噪声消掉了。这是整个传感器信号处理里最经典的一招,几乎所有CCD和CMOS传感器都靠它把噪声压下去。
第二件事是可变增益放大(VGA/AGC)。把微弱的像素信号放大到一个合适的幅度,让后级ADC能充分利用量程。要注意,增益不是越高越好,因为放大器会把信号和噪声一起放大,增益倍增意味着信噪比并不会改善多少,只是让微弱信号“够得着”ADC的分辨率。
第三件事是模数转换(ADC)。把模拟电压量化成数字码,常见的是10bit、12bit甚至14bit。CMOS传感器现在普遍做成列并行ADC,就是一列像素配一个ADC,并行转换,所以帧率能做得很高。CCD要用高速串行ADC,受限于单输出端口,速率上不去。
2.2 数字处理流水线:ISP在做什么
ADC输出的是RAW图,在RAW图阶段,每个像素只有单一的亮度值,还带着拜耳滤色阵列的颜色信息,直接看是发灰、偏暗的。所以要靠ISP(图像信号处理器)来还原。
一个标准ISP流水线大致包括这样几步:
- 坏点校正:传感器晶圆上总有几个像素是不正常的,需要先检测出来,再用周围像素插值补掉。
- 黑电平校正:把无光照时的本底信号减掉,恢复正常零点。
- 镜头阴影校正:镜头边缘进光量本身低于中心,需要用增益补偿。
- 去马赛克/色彩插值:利用拜耳阵列上相邻RGB像素,估计每个像素的完整RGB值。
- 色彩校正矩阵:校正色彩串扰,把传感器光谱响应“拉”回标准色彩空间。
- 伽马校正和色调映射:把线性亮度关系压缩到人眼感受更自然的非线性区间。
- 降噪和边缘增强:压掉噪声的同时保边缘,这是个一直打架的环节,降噪太狠图像会发肉,增强太猛会有光晕。
实际项目中,ISP可能集成在传感器模组里,比如手机摄像头模组;也可能在SoC的独立ISP核里;工业相机则往往在相机内做,或者把RAW数据直接给到主机端算。
2.3 与阵列信号处理的交汇:传感器不止是拍照片
图像传感器本质上就是一个二维分布的信号采集阵列,每个像素都是一个采样点。所以图像处理和阵列信号处理之间有很深的方法论相通之处。
举个例子,麦克风阵列通过多路信号的时延估计和波束成形,可以从嘈杂环境里“听”出一个方向的声音;雷达阵列通过多通道相位差,可以测出目标的方位和速度。图像传感器里的像素阵列也做类似的事:拜耳色彩插值是在空间域做信号重建,超分辨率是用多帧图像估计亚像素位移,光场相机则是用微透镜阵列记录光线的角度信息,跟阵列信号处理里的孔径综合是一个思想。
做分布式传感、多相机同步项目的朋友,应该对这句话有体会:图像传感器信号处理和阵列信号处理,底层用的数学工具有一大半是重叠的,快速傅里叶变换、相关分析、空时滤波、多通道校准,这些本领学会了,两边都能用。这也是为什么这行的人往往既写嵌入式代码,又能上手MATLAB做算法仿真。
3. 选型实战:什么时候用CCD,什么时候用CMOS
3.1 核心指标:噪声、动态范围、帧率怎么权衡
选传感器不能只看纸面分辨率,真正决定用起来顺不顺手的是几个核心参数:
- 量子效率(QE):每个光子能产生多少电子的比例,QE越高,灵敏度越好。
- 满阱容量(FWC):像素最多能装多少电子,决定高光不过曝的上限。
- 暗电流:没有光照时热激发产生的电子,曝光时间越长越明显,表现为暗部发红发亮。
- 读出噪声:读出过程引入的本底噪声,直接决定暗部能分辨多细微的光强差异。
- 动态范围:满阱容量和底噪的比值,通常用dB表示,动态范围大意味着能同时拍清楚亮部和暗部。
CCD的优势是读出噪声低、暗电流小、像素一致性好,在同尺寸下动态范围往往更宽。CMOS的高端型号也在追赶,尤其背照式(BSI)和堆叠式工艺把量子效率提升了很多。
帧率这块,CMOS有压倒性优势。高速机器视觉用的CMOS传感器,跑几百帧到上千帧都很正常,而科学级CCD往往只能跑几帧到几十帧,长时间曝光倒是很在行。
3.2 快门机制与3D传感器:全局快门、iToF与SPAD
这里有个经常被忽略却很实用的点:快门机制。
CMOS传感器常见的是卷帘快门,像素逐行曝光、逐行读出。好处是电路简单,坏处是拍运动物体时会产生“果冻效应”,物体边缘歪斜。CCD靠机械快门或电子快门做全局曝光,所有像素同时开始同时结束,运动抓拍不变形。
现在高端工业CMOS也有全局快门设计了,每个像素旁边多加了一个存储节点,曝光完成后先把电荷保存住,再逐行读出,既保留了CMOS的速度优势,又解决了果冻效应。
再延伸一下,3D视觉领域也经常问:iToF到底用CMOS还是SPAD工艺?我实测和查资料下来的结论是:iToF一般用CMOS图像传感器工艺,因为它需要高速调制光源、对反射光做相位解算,CMOS像素加解调电路就能做。而dToF需要单光子级灵敏度,主流方案是用SPAD(单光子雪崩二极管)工艺,它能把单个光子到达时刻记录下来。所以不能说“3D传感器就是CMOS”,要看是哪种3D方案。
3.3 典型应用场景对照
拿实际选型经验来说,这几类场景基本不会选错:
- 天文观测、生物荧光显微、科学光谱分析:优先考虑科学级CCD,甚至背照深耗尽CCD,弱光性能确实强,长期曝光暗电流控制很成熟。当然现在也有科学级sCMOS替代趋势,高帧率需求越来越多,但CCD仍有一席之地。
- 工业高速检测、运动追踪、机器人视觉:选全局快门CMOS,帧率、功耗、集成度都更合适。
- 手机、安防、车载摄像头:成品化CMOS模组,现在背照式、堆叠式工艺已经能做得很小,画质在光线好的情况下非常能打。
- 多相机同步、阵列式采集:同样优先CMOS,因为容易做同步触发和并行读出。
| 对比维度 | CCD | CMOS |
|---|---|---|
| 读出方式 | 电荷逐一转移、统一输出 | 像素独立寻址、列并行读出 |
| 读出噪声 | 低 | 中高端型号已接近 |
| 像素一致性 | 很好 | 有固定模式噪声需校正 |
| 帧率 | 低 | 高 |
| 功耗 | 高 | 低 |
| 集成度 | 低,需外部驱动电路 | 高,可集成ADC/ISP |
| 全局快门 | 天然全局曝光 | 需要额外像素设计 |
| 典型价格 | 科学级昂贵 | 消费级便宜、高端工业级也在下行 |
4. 传感器调试中的经典问题与排查方法
4.1 “CMOS”混淆:图像传感器和主板电池不是一回事
先澄清一个特别常见的认知坑。热词里“cmos checksum error”“cmos battery is bad”指的不是图像传感器,而是电脑主板上的CMOS存储芯片和给BIOS供电的纽扣电池。
这两者都叫“CMOS”,原因是它俩早期用的都是互补金属氧化物半导体工艺。做图像的高端叫CMOS图像传感器,做存储的也有CMOS工艺的静态存储器,刚好撞了名字。如果你搞硬件调试,开机报“cmos checksum error”,实际上建议检查主板电池有没有电,而不是去怀疑相机坏了。这个点看起来小事,但真的能让人绕半天。
4.2 暗场、坏点、条纹噪声:问题定位的思路
实际调试视觉系统时,图像出问题先别急着怀疑传感器本身,按顺序排查。
第一招是拍暗场。盖上镜头盖,用同样参数拍一张全黑图。如果暗场图有固定位置的亮点,那是坏点或热像素;如果整幅图像偏亮,那是黑电平没校好;如果出现横向或纵向的亮条纹、明暗不均,多半是电源纹波干扰或读出电路的问题。暗场图是最便宜的噪声诊断工具,我每次装机都会先拍几十帧暗场存下来做对比。
第二招是拍均匀亮场。对着均匀光源拍一张灰图,如果发现规则的网格状亮度变化,那可能是镜头阴影或像素响应不均匀,需要做平场校正。平场校正的做法就是对每颗像素算一个增益系数,把响应拉齐。
第三招是检查卷帘快门引起的果冻效应。如果拍高速运动物体出现斜切、拖影,确认传感器是不是工作在卷帘模式、曝光时间是不是偏长。工控现场经常是LED灯的频闪和卷帘快门产生干涉条纹,导致画面出现滚动明暗带,解决办法是调整曝光时间避开工频频率,或者改用全局快门传感器。
4.3 寄存器配置与测试图检查
传感器上电之后不是直接出图的,需要先通过I2C或SPI接口配置一堆寄存器,包括曝光时间、增益、输出格式、测试图模式等。
我强烈建议调试时先用传感器自带的内置测试图(通常是一张彩色条纹图)验证链路通不通。链路正常的标志是:收到内嵌测试图的RAW数据流,并且数据格式、行场时序和你预期一致。如果这一步都过不了,后面的图像处理都是白搭。
一个实用的排查顺序是:
- 检查时钟是否起振、频率对不对。
- 通过寄存器读回传感器ID,确认通信正常。
- 打开测试图模式,验证数据通路。
- 关闭测试图,接入镜头,逐步调亮场和暗场校正。
- 锁定噪声和画质问题,再决定是调寄存器还是调硬件设计。
这套流程我用了好多个项目,基本能覆盖八成初始化问题。
5. 传感器信号处理的实用工具链
5.1 数据采集:寄存器配置与接口布线
传感器输出RAW数据要接回处理端,接口类型很重要。手机摄像头、嵌入视觉模块多用MIPI CSI-2接口;工业相机常见的是LVDS或者更高速的SLVS、CoaXPress;还有PCIe接口的采集卡,比较适合高速高带宽场合。
如果你是做嵌入式或FPGA开发,布线长度、差分阻抗、时钟和数据对的等长关系都要控制好,否则信号完整性出问题,RAW数据会随机错位,图像看起来像被撕裂。我之前遇到过图像偶尔出现整行偏色的情况,查到最后是MIPI时钟线上的干扰,把速度降了一档就好了。
寄存器配置方面,不同传感器厂商都会给一个初始化序列,照着写就行。要注意的是,不同传感器对曝光和增益的单位定义很不一样,有的曝光以行数为单位,有的是以微秒为单位,换算错了画面会过曝或全黑。
5.2 离线处理:MATLAB和Python的RAW图像还原
拿到RAW文件后,处理起来有很多现成工具。MATLAB的Image Processing Toolbox里可以直接读入RAW数据,按拜耳排列重组显示;雷达信号处理里常用的MATLAB仿真习惯也可以迁移过来,把传感器看成二维阵列,用傅里叶分析看频谱。
Python生态里,OpenCV的cv2.cvtColor支持拜耳转BGR,scikit-image也有对应的去马赛克函数。想做更底层控制,就自己写黑电平减除、坏点校正和色彩校正矩阵。
给你一个最简Python流程做参考:
import cv2 import numpy as np # 假设读取的是10bit RAW,存成16bit无符号 raw = np.fromfile("sensor.raw", dtype=np.uint16).reshape(2048, 2448) # 黑电平减除,例如传感器黑电平为64(10bit下) black_level = 64 raw = raw.astype(np.float32) - black_level # 去掉小于0的值 raw = np.clip(raw, 0, None) # 拜耳去马赛克 color = cv2.cvtColor(raw.astype(np.uint16), cv2.COLOR_BayerRG2BGR) # 归一化到8bit预览 preview = cv2.normalize(color, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) cv2.imwrite("preview.png", preview)这段代码的核心就是先做黑电平校正,再做色彩重建。实际项目中,还要在前面加坏点校正,后面加白平衡、色彩校正矩阵和gamma,就能搭一个最简ISP原型了。
5.3 一条可落地的调试路径
给一个可以照着走的调试路径:
- 拿到一款新传感器,先搭好最小硬件,确保供电、时钟、I2C通信正常。
- 读取传感器ID,初始化寄存器,把输出格式设置成预期bits数。
- 打开内置测试图,确认数据线和接收端能拿到正确的RAW流。
- 接上镜头,对均匀目标拍一帧,确认正常曝光。
- 固定曝光参数,拍暗场和多组亮度平场,做黑电平校正和平场校正。
- 根据项目需求做ISP处理,输出标准图像。
- 做整机长时间运行测试,记录温度和噪声变化,确认长时间曝光不产生过度暗电流。
这套路径里,每一步出现问题都能快速定位到是硬件、配置、还是算法问题,不会让你在调试的泥潭里打转。
我个人在实际项目里最深的体会是:图像传感器本身并不难理解,难的是把它放进整个信号处理链路里通盘考虑。很多时候画质问题不是传感器不好,而是前面的光电信号没采好,或者后面的ISP参数没调对。搞明白CCD与CMOS图像传感器的核心差异,再掌握信号处理的完整流程,你就不容易被表象参数迷惑,真正做出能交付的视觉系统。