2. 图像传感器与噪声模型:光子散粒噪声、读出噪声、暗电流噪声
各位同学,咱们今天聊点实在的。做低光照自动对焦,你绕不开一个东西——噪声。
我刚开始接触这个领域时,总觉得算法调参是万能的。直到有一次,在0.1 lux的暗光场景下,AF评价函数曲线抖得像心电图,我才意识到:不懂噪声,你连评价函数为什么失效都搞不清楚。
这一节,我们就来拆解图像传感器里的三大噪声:光子散粒噪声、读出噪声、暗电流噪声。我会结合项目中的实际案例,告诉你它们怎么影响AF评价函数。
2.1 三大噪声的物理来源
先看一张总览图,理清它们的关系。
2.2 光子散粒噪声
这是最根本的噪声,物理上无法消除。
光子的到达是随机的,服从泊松分布。你想想看,一个像素接收到的光子数N,它的标准差就是√N。信号越弱,信噪比越低。
核心公式:
信噪比 SNR = N / √N = √N
低光照下,N很小,SNR急剧恶化。
我在项目中遇到过一款手机摄像头,在10 lux以下,散粒噪声直接让AF评价函数的峰值信噪比从30dB掉到12dB。评价函数曲线不再是单峰,而是出现大量毛刺。
2.3 读出噪声
读出噪声来自像素电荷转换、放大、ADC量化等电路环节。它与信号强度无关,是一个固定基底。
说白了,就算你把镜头盖住,读出电路也会产生噪声。这个噪声在低光照下特别致命——信号本来就弱,再叠加上固定噪声,对比度信息就被淹没了。
| 噪声类型 | 典型值(e-) | 与信号关系 | 低光照影响 |
|---|---|---|---|
| 光子散粒噪声 | √N | 随信号增大 | 主导噪声源 |
| 读出噪声 | 2~10 e- | 固定 | 限制信噪比下限 |
| 暗电流噪声 | 0.1~10 e-/s | 随时间线性 | 长曝光时严重 |
避坑指南:我曾经在调试一款工业相机时,发现AF评价函数在暗光下始终有0.3的偏移量。排查了三天,最后发现是读出噪声的固定模式噪声(FPN)没有被校正。加上暗场减除后,问题立刻解决。
2.4 暗电流噪声
暗电流是热激发产生的电子-空穴对。温度每升高6-8°C,暗电流翻倍。长曝光时,暗电流会积累大量电荷,形成固定的背景偏移。
嗯,这里要注意:暗电流噪声包含两部分——固定部分(可以通过暗场校正去除)和散粒噪声部分(无法去除)。
对于AF算法来说,暗电流噪声会导致评价函数的基线漂移。如果算法没有做动态阈值处理,可能会把暗电流噪声误判为图像细节,产生假峰值。
2.5 噪声对AF评价函数的影响
我们常用的AF评价函数,比如Tenengrad、Laplacian、Brenner,本质上都是高频能量检测器。噪声本身就是高频信号,它会污染评价函数的输出。
具体影响有三点:
- 峰值抖动:噪声导致评价函数曲线出现多个局部极值,对焦位置不稳定。
- 对比度下降:噪声淹没了真实边缘的高频分量,评价函数的最大值降低。
- 峰值偏移:当噪声分布不均匀时,评价函数的全局最大值可能偏离真实对焦位置。
实战警告:不要试图用简单的平滑滤波去噪来改善AF评价函数。低通滤波会同时滤掉图像的高频细节,导致对焦精度下降。我见过有人用高斯滤波预处理图像做AF,结果对焦永远差那么一点点——这就是典型的过度平滑。
2.6 噪声建模与仿真代码
为了验证噪声对AF的影响,我习惯在仿真阶段就加入噪声模型。下面是一个简单的Python代码片段,模拟三种噪声对图像的影响。
import numpy as np
import cv2
def add_noise_model(image, gain=1.0, read_noise=2.0, dark_current=0.5, exposure_time=1.0):
"""
模拟图像传感器噪声
:param image: 输入图像 (0-255 uint8)
:param gain: 模拟增益
:param read_noise: 读出噪声标准差 (e-)
:param dark_current: 暗电流速率 (e-/s)
:param exposure_time: 曝光时间 (s)
:return: 含噪声图像
"""
# 转换为电子数(假设满阱容量为30000 e-)
electrons = image.astype(np.float32) / 255.0 * 30000.0
# 1. 光子散粒噪声
shot_noise = np.random.poisson(electrons).astype(np.float32) - electrons
# 2. 暗电流噪声
dark_electrons = dark_current * exposure_time
dark_shot = np.random.poisson(dark_electrons).astype(np.float32) - dark_electrons
# 3. 读出噪声
read_noise_arr = np.random.normal(0, read_noise, electrons.shape).astype(np.float32)
# 叠加噪声
noisy_electrons = electrons + shot_noise + dark_shot + read_noise_arr
# 应用增益并量化
noisy_image = np.clip(noisy_electrons / 30000.0 * 255.0 * gain, 0, 255).astype(np.uint8)
return noisy_image
# 使用示例
img = cv2.imread('test_pattern.png', 0)
noisy_img = add_noise_model(img, gain=4.0, read_noise=3.0, dark_current=1.0, exposure_time=0.5)
我的习惯:在调优AF算法前,先用这个噪声模型生成不同信噪比的测试序列。这样可以量化评价函数在不同噪声水平下的性能边界,避免在真实硬件上反复试错。
2.7 本章小结
记住三句话:
- 光子散粒噪声是低光照下的头号敌人,它决定了信噪比的理论上限。
- 读出噪声是固定基底,限制了AF评价函数在极暗场景下的灵敏度。
- 暗电流噪声在长曝光时不可忽视,会导致评价函数基线漂移和假峰值。