3、光响应非均匀性(PRNU)标定:平场采集方法、PRNU校正系数计算、镜头阴影校正(LSC)原理、增益一致性标定

好,咱们进入第三章。这一章聊的是传感器标定里最“实在”的一块——光响应非均匀性,也就是 PRNU。说白了,就是同一个传感器,在均匀光照下,每个像素的输出值却不一样。你想想看,这要是拍个蓝天,结果画面上一块亮一块暗,那多闹心。

我刚开始做嵌入式视觉那会儿,就吃过这个亏。当时调一个工业检测项目,传感器明明对着均匀的白板,结果图像上总有固定的条纹。我折腾了三天,换镜头、调光源,最后才发现是 PRNU 没标定。从那以后,我再也不敢跳过这一步了。

3.1 平场采集方法

PRNU 标定的第一步,就是采集平场图像。平场,就是均匀、无结构的亮场。怎么采?有讲究。

我的经验:平场采集最忌讳“不均匀”。哪怕光源有一点点渐变,标定出来的校正系数都会带偏。我建议用积分球,或者至少用两块高反射率的白板叠在一起,保证光照均匀度在 95% 以上。

具体步骤,我列个清单:

  1. 准备均匀光源:积分球最佳,或者用 LED 面光源加扩散板。色温要稳定,别用日光灯,频闪会让你怀疑人生。
  2. 设置传感器参数:曝光时间、增益、帧率,都要和实际应用保持一致。千万别用自动曝光,否则标定完一换参数,校正系数全废了。
  3. 采集多帧平均:单帧有随机噪声,我一般采 16 到 32 帧,然后做像素级平均。这样能有效压制 temporal noise,只留下固定的 PRNU 成分。
  4. 检查平场质量:看一眼直方图,应该是一个窄窄的单峰。如果出现双峰或者拖尾,说明光源不均匀或者传感器有坏点,得重采。

这里有个坑——暗场也要采。暗场就是盖上镜头盖,采集全黑图像。为什么?因为 PRNU 校正需要先减掉暗电流和固定模式噪声(FPN)。不采暗场,校正完你会发现暗部偏色。

注意:平场和暗场的采集条件必须完全一致——同样的曝光时间、同样的增益、同样的温度。温度一变,暗电流就变,标定就白做了。我曾经在夏天标定完,冬天用,结果暗部全是噪点,血的教训。

3.2 PRNU 校正系数计算

有了平场和暗场,接下来就是算校正系数。公式其实不复杂:

// 伪代码:PRNU 校正系数计算
// 输入:平场图像 flat[16帧平均],暗场图像 dark[16帧平均]
// 输出:增益校正系数 gain_map

// 1. 计算暗场校正后的平场
float corrected_flat = flat - dark;

// 2. 计算平场均值(所有像素的平均值)
float mean_flat = average(corrected_flat);

// 3. 每个像素的校正系数 = 均值 / 该像素值
for each pixel (x, y):
    gain_map[x][y] = mean_flat / corrected_flat[x][y];

说白了,就是让每个像素都“看齐”平均值。亮的像素乘一个小于 1 的系数,暗的像素乘一个大于 1 的系数。这样校正后,均匀光照下所有像素输出就一致了。

但这里有个细节——系数不能太大也不能太小。我一般限制在 0.8 到 1.2 之间。如果某个像素的系数超出这个范围,说明它可能是坏点,应该走坏点校正流程,而不是硬拉。

像素类型 校正系数范围 处理方式
正常像素 0.8 ~ 1.2 直接乘系数校正
偏亮像素 < 0.8 标记为疑似坏点,走坏点校正
偏暗像素 > 1.2 标记为疑似坏点,走坏点校正
死像素 无穷大或 NaN 直接替换为邻域均值
关键点:PRNU 校正系数是“像素级”的,每个像素都有自己的系数。所以存储时要用 16 位定点数或浮点数,精度不够的话,校正后会出现量化噪声。

3.3 镜头阴影校正(LSC)原理

PRNU 校正完,画面均匀了吗?不一定。因为还有镜头阴影——也就是镜头边缘进光量比中心少,导致四角变暗。这个现象叫“渐晕”(vignetting)。

LSC 和 PRNU 的区别在哪?我画个图你就明白了。

PRNU 与 LSC 的区别 PRNU(像素级) 每个像素独立校正 系数随机分布 针对传感器本身 LSC(区域级) 中心亮 边缘暗 平滑渐变 按距离中心半径校正 系数呈径向分布 针对镜头光学特性

PRNU 是像素级的随机差异,LSC 是区域级的平滑渐变。所以校正方法也不一样——PRNU 用像素级系数表,LSC 用径向多项式或查表。

LSC 的经典模型是这样的:

// LSC 校正模型
// 对于像素 (x, y),计算其到图像中心的距离 r
float cx = width / 2.0f;
float cy = height / 2.0f;
float dx = (x - cx) / cx;  // 归一化到 [-1, 1]
float dy = (y - cy) / cy;
float r = sqrt(dx*dx + dy*dy);

// 用多项式拟合衰减曲线
// L(r) = 1 + a1*r^2 + a2*r^4 + a3*r^6
float gain = 1.0f + a1*r*r + a2*r*r*r*r + a3*r*r*r*r*r*r;

// 校正后的像素值 = 原始值 * gain
pixel_out[x][y] = pixel_in[x][y] * gain;

为什么只用偶次项?因为镜头阴影是对称的,奇次项会引入不对称。我见过有人用三次项,结果画面一边亮一边暗,那叫一个尴尬。

我的习惯:LSC 系数我一般用 5 阶或 7 阶偶次多项式。阶数太低拟合不准,阶数太高容易过拟合。标定完一定要用网格图验证——拍一张均匀白板,看四角和中心的亮度差是否在 1% 以内。

3.4 增益一致性标定

最后聊增益一致性。这个和 PRNU 有点像,但针对的是模拟增益(Analog Gain)和数字增益(Digital Gain)的线性度。

说白了,你给传感器设增益 2x,它是不是真的把信号放大了 2 倍?不一定。不同增益档位下,放大器的线性度会有偏差。尤其是高增益下,非线性会更明显。

标定方法也不复杂:

  1. 固定光源亮度,用积分球保证稳定。
  2. 从低到高切换增益,比如 1x、2x、4x、8x、16x。
  3. 记录每个增益下的输出均值。
  4. 拟合增益响应曲线,计算实际增益与理论增益的偏差。

我举个例子:

理论增益 输出均值(DN) 实际增益 偏差
1x 100 1.00x 0%
2x 198 1.98x -1%
4x 388 3.88x -3%
8x 752 7.52x -6%
16x 1408 14.08x -12%

你看,增益越高,偏差越大。如果不校正,高增益下画面会偏暗,而且不同通道的增益偏差还会导致偏色。

注意:增益一致性标定要分通道做。RGB 三个通道的增益响应可能不一样,尤其是 Bayer 传感器。我曾经遇到一个项目,绿色通道增益线性度很好,红色通道在高增益下直接饱和了——查了半天,原来是红色通道的放大器设计有问题。

校正方法也很直接——查表。把每个增益档位的实际增益值存下来,使用时做线性插值补偿。比如你要用 3x 增益,但实际 2x 是 1.98x,4x 是 3.88x,那就插值算出 3x 对应的实际增益,然后调整曝光时间或数字增益来补偿。

总结一下:PRNU 校正、LSC 校正、增益一致性标定,这三者合起来,才能让传感器输出真正“均匀”的图像。顺序也很重要——先做暗场校正,再做 PRNU,然后 LSC,最后增益补偿。顺序乱了,校正效果会互相干扰。

嗯,这一章的内容就到这儿。标定是个细致活,急不得。你只要把平场采好了,系数算准了,后面的图像质量就有保障了。