4. 卷帘快门伪影(二):部分曝光(Partial Exposure)与闪光灯同步问题

上一章我们聊了果冻效应,那是卷帘快门最出名的“名片”。但说实话,在实际项目中,真正让我半夜被电话叫醒的,往往是另一个问题——部分曝光,以及它带来的闪光灯同步噩梦。

什么叫部分曝光?说白了,就是一张照片里,有的行曝光时间长,有的行曝光时间短。结果就是画面一半亮一半暗,或者出现一条明显的亮度分界线。嗯,这在闪光灯摄影里尤其常见。

4.1 部分曝光的根因:行间曝光起点不同

要理解这个问题,得先回到卷帘快门的读出机制。我之前在讲卷帘快门基础时提过:每一行的曝光起始时间和结束时间都是错开的。

对于电子卷帘快门,典型的工作流程是:

  1. 复位行(Reset):把某一行像素的电荷清空
  2. 等待积分时间(Integration):让这一行收集光子
  3. 读出该行(Readout):把电荷转成电压并读出

关键点在于:复位和读出是逐行扫描的。如果闪光灯只在一瞬间点亮,那么只有恰好处于积分阶段的那几行能接收到闪光,其他行要么还没开始积分,要么已经读出了。

核心结论:卷帘快门传感器中,不同行的曝光窗口在时间轴上是不对齐的。闪光灯脉冲宽度越窄,受影响的行数越少,部分曝光现象越明显。

4.2 闪光灯同步问题的三种典型场景

我在做手机摄像头调试时,遇到过好几次闪光灯拍照出现“半黑半白”的情况。客户拿着样机来找我,说你们这传感器是不是坏了?其实不是,是闪光灯没同步上。

我把常见场景归纳为三类:

场景 闪光灯类型 典型表现 严重程度
场景一:前帘同步 LED闪光灯(短脉冲) 画面顶部亮、底部暗 高
场景二:后帘同步 LED闪光灯(短脉冲) 画面底部亮、顶部暗 高
场景三:长脉冲闪光 氙气灯(持续较长) 画面均匀但可能有亮度渐变 中

为什么会这样?你想想看:

  • 前帘同步:闪光灯在曝光开始时点亮。此时顶部行刚完成复位,开始积分;底部行还在等待复位。闪光只被顶部行接收到。
  • 后帘同步:闪光灯在曝光结束前点亮。此时顶部行已经读出,底部行还在积分。闪光只被底部行接收到。
  • 长脉冲闪光:闪光持续时间覆盖了整个曝光窗口,所有行都能接收到,但亮度可能不均匀。

注意:LED闪光灯的脉冲宽度通常在1~10毫秒,而卷帘快门一帧的读出时间可能在10~30毫秒。这意味着闪光灯只能覆盖一部分行的曝光窗口。

4.3 解决策略:硬件方案

我个人习惯把解决方案分成硬件和软件两类。先讲硬件,因为这是最根本的。

4.3.1 全局复位+卷帘读出(GR模式)

这是我最常用的硬件方案。思路很简单:让所有行同时开始曝光(全局复位),然后逐行读出。这样所有行的曝光窗口在时间上是完全对齐的。

流程如下:

  1. 全局复位所有像素
  2. 等待设定的积分时间
  3. 逐行读出(卷帘方式)

这样一来,闪光灯只要在积分时间内点亮,所有行都能接收到。我在一个安防摄像头项目里用过这个方案,闪光灯同步问题直接解决了。

小提示:GR模式需要传感器支持全局复位功能。不是所有卷帘快门传感器都支持,选型时要确认。

4.3.2 机械快门配合

对于高端相机,机械快门可以做到真正的全局曝光。机械快门打开时所有行同时开始曝光,关闭时同时结束。卷帘读出只在机械快门关闭后进行。

但机械快门有寿命问题,而且体积大、成本高。手机摄像头基本不用。

4.3.3 闪光灯脉冲宽度控制

如果传感器不支持GR模式,可以尝试拉长闪光灯脉冲宽度。让闪光持续时间覆盖整个卷帘读出周期。

我记得有一次调试一个工业相机,闪光灯脉冲只有2毫秒,部分曝光很明显。后来我们把脉冲拉到20毫秒,问题就缓解了很多。代价是功耗上升了,电池扛不住。

4.4 解决策略:软件方案

硬件方案搞不定的时候,就得靠软件来“擦屁股”了。说实话,我在项目里用软件方案更多,因为成本低、改动快。

4.4.1 闪光灯同步信号校准

核心思路:让闪光灯的点亮时刻与传感器曝光窗口对齐。

具体做法:

  • 传感器输出VSYNC(帧同步)和HSYNC(行同步)信号
  • 根据设定的曝光时间,计算闪光灯应该在哪一行开始点亮
  • 通过GPIO或I2C触发闪光灯

代码示例(伪代码):

// 假设传感器参数
int total_lines = 1920;      // 总行数
int exposure_lines = 960;    // 曝光行数(对应曝光时间)
int flash_duration_lines = 100; // 闪光灯持续时间(换算成行数)

// 计算闪光灯触发位置(前帘同步)
int flash_start_line = 0;    // 从第一行开始触发

// 或者后帘同步
int flash_start_line = total_lines - exposure_lines;

// 等待到指定行数时触发闪光灯
while(current_line < flash_start_line) {
    wait_for_next_line();
}
trigger_flash();

关键点:闪光灯触发时刻必须精确到行级别。误差超过一行,就会出现亮度不均匀。

4.4.2 多帧合成

这个方案比较“暴力”,但效果不错。拍多张照片,每张用不同的闪光灯时序,然后合成一张。

比如:

  • 第一帧:闪光灯在顶部行曝光时点亮
  • 第二帧:闪光灯在中间行曝光时点亮
  • 第三帧:闪光灯在底部行曝光时点亮

然后取每帧中曝光正确的区域,合成一张完整的图像。我在一个医疗内窥镜项目里用过这个方案,虽然帧率降了,但图像质量达标了。

4.4.3 亮度校正(Lens Shading Correction扩展)

如果部分曝光是固定的(比如每次都在同一位置出现亮度差异),可以用校正矩阵来补偿。

做法:

  1. 拍摄一张均匀光照的参考图像
  2. 计算每行的增益系数
  3. 在ISP(图像信号处理器)中逐行应用增益

但这个方法只适用于固定模式的部分曝光。如果闪光灯时序变化,校正矩阵也得跟着变。

4.5 知识结构图:部分曝光与闪光灯同步

下面这张图总结了本章的核心逻辑,从根因到解决方案的完整链路:

部分曝光与闪光灯同步问题知识结构 部分曝光与闪光灯同步问题 — 知识结构 根因:行间曝光窗口不对齐 现象:部分曝光(Partial Exposure) 前帘同步(顶部亮) 后帘同步(底部亮) 长脉冲闪光(渐变) 解决方案 硬件方案 软件方案 全局复位(GR) 机械快门 闪光灯脉冲宽度控制 同步信号校准 多帧合成 亮度校正(LSC扩展) 核心原则:让所有行在闪光灯点亮期间都处于积分状态,或精确控制闪光灯触发时刻

4.6 避坑指南

做闪光灯同步调试,我踩过不少坑。分享几个典型的:

坑一:忽略传感器内部延迟

我曾经以为只要在VSYNC上升沿触发闪光灯就行。结果发现传感器内部有几十微秒的延迟,闪光灯总是早了一点点。后来加了延迟补偿才搞定。

坑二:闪光灯驱动电路的响应时间

LED闪光灯不是瞬间点亮的。从GPIO拉高到LED真正达到最大亮度,可能需要几百微秒。这个时间在行扫描周期里已经能影响好几行了。

建议:在量产前,一定要用示波器同时抓VSYNC、HSYNC和闪光灯触发信号。确认时序对齐了再放行。

4.7 小结

部分曝光和闪光灯同步问题,本质上是卷帘快门的时间不对齐特性与短脉冲光源之间的矛盾。解决思路无非两条:要么让所有行同时曝光(硬件方案),要么精确控制闪光灯触发时刻(软件方案)。

我个人更倾向于先试软件方案,因为改动成本低。但如果产品对图像质量要求极高,比如医疗或工业检测,那还是得上全局复位或机械快门。

嗯,这一章就到这里。记住:下次遇到闪光灯拍照一半亮一半暗,别急着骂传感器,先看看闪光灯时序对不对。