首页 / 资讯中心 / 文章详情

周期性与方向性协同:burst摄影闪烁伪影去除全解析

周期性与方向性协同:burst摄影闪烁伪影去除全解析 ★ FEATURED ARTICLE
大概没有哪个手机摄影用户没遇到过这个场景夜景模式下端着手机连拍五六张本想着多帧合成能换来更亮的画面结果回放时发现亮度忽明忽暗同一面白墙硬是拍出了呼吸灯的效果。这种在 burst 连拍序列里出现的亮度周期性波动就是典型的闪烁伪影flicker artifact。它不只是一张照片被拍毁的问题——HDR 合成时会引入鬼影降噪算法会把闪烁误当成真实细节去保留整个多帧流水线的输出质量都在被拉低。针对这个问题标题里提到的思路很有意思It Takes Two: A Duet of Periodicity and Directionality——用周期性和方向性的协同来去除 burst 闪烁。简单说就是闪烁本质上是人工光源以固定频率调制出来的周期信号这是可以建模的周期性而真实场景里的边缘、纹理、运动又各自带有明确的空间方向信息这是可以保护的方向性。两者合在一起一个负责识别什么在闪一个负责守住什么才是真正好形成互补。这篇文章我就从成像原理、算法设计、参数调试到落地场景把这套思路完整拆开讲一遍。内容面向做计算摄影、图像算法的工程师也适合想搞懂 burst 成像原理的摄影爱好者。1. 先搞清楚burst 摄影里的闪烁是怎么闪起来的1.1 根源不在相机在电源频率很多人以为闪烁是相机 CMOS 曝光不准导致的这个锅相机真不该背。闪烁的根源在人工照明本身——市电是交流电灯泡的亮度随交流电压周期性变化。虽然不同国家的电网频率有 50Hz 和 60Hz 之分但灯具实际的亮度波动频率基本是电网频率的两倍白炽灯和大多数荧光灯在交流电的正半周与负半周都会发光所以一个完整周期内会出现两次亮度峰值也就是 100Hz50Hz 电网或 120Hz60Hz 电网。这个频率对人眼来说太快了肉眼完全感知不到闪烁但相机传感器是个诚实的记录设备。当曝光时间足够短——短到小于闪烁周期的一半时比如 1/250s 甚至更短每次曝光恰好落在亮度波形的不同相位上抓到的亮度就不一样。于是连拍序列里就会出现这张偏亮、那张偏暗、再下一张又偏亮的规律性亮度起伏。这里有个关键认知闪烁并不是随机的噪声它是一个频率已知或可估计的确定性周期信号。这就给算法提供了一个绝佳的切入点——既然闪烁有规律就能用周期分析把它从图像里剥离出来。这正是标题里Periodicity这一半的物理基础。1.2 闪烁对多帧合成的影响有多大闪烁伪影如果只是整体亮度抖一抖那全局增益归一化就能解决。但实际场景远比这个复杂空间分布不均匀不同光源的闪烁相位不完全同步房间不同区域可能亮度反相变化全局补偿会产生区域性过曝或欠曝。与曝光曲线的交互CMOS 的曝光不是瞬时的而是滚动式逐行曝光。帧与帧之间的亮度波动会与卷帘快门产生额外耦合出现部分行亮、部分行暗的条纹。运动与闪烁叠加拍摄场景里的移动物体本身就在改变像素值和亮度调制混在一起后很难分辨某个像素的变化到底是场景在变还是光在变。这些影响层层叠加最终反映在多帧合成的结果上HDR 合成出现亮度断层降噪后边缘出现规则排布的明暗纹理连拍选帧时算法会误把闪烁大的一帧当成细节更丰富的帧选进来。我自己在实际项目里碰到过一个很典型的案例某跨平台系统的夜间连拍模式在商场灯光环境下输出的照片在墙壁区域出现了非常明显的规律性横纹。肉眼单看一帧没问题但五帧合成后横纹被强化整个墙面像贴了层塑料膜。排查到最后根因就是 100Hz 的闪烁频率与连拍帧率产生了差拍效应。这个案例让我彻底意识到闪烁去除不是一个锦上添花的后处理而是多帧成像流水线里绕不开的一环。2. 二重奏的设计哲学周期性负责识别方向性负责守真2.1 周期性给闪烁信号做一次频率指纹识别既然闪烁是确定频率的周期信号很自然的思路就是沿着时间轴对每个像素做频谱分析。把 burst 序列里某一像素的亮度变化看作一维时间信号做傅里叶变换后闪烁分量会集中在某个特定频率上形成一个尖峰。拿到了这个频率就可以反推闪烁的振幅和相位从而把亮度调制分量从信号里提取出来。听起来直接但实操中要处理三个问题帧率与奈奎斯特限制burst 连拍帧率通常在 10-30fps远低于 100Hz 的闪烁频率。直接做 FFT闪烁频率早就混叠了频谱尖峰根本不在真实位置。解决办法是利用被测物与帧率之间的混叠关系来推算真实频率如果帧率是 25fps那么 100Hz 的信号会以 25 帧为一个周期呈现完整的亮度往复。也就是说虽然单帧采样率不够但通过跨多帧的相位观测可以把混叠后的低频包络作为分析对象。相位漂移帧与帧的时间间隔不是严格等间隔的自动曝光、对焦都会引入抖动直接做等间隔 FFT 会有频谱泄漏。工程上更多用非均匀 FFT 或者先做时间戳插值再分析。频点分辨混叠后的闪烁特征频率会被场景自身的低频变化比如镜头缓缓扫过时整体亮度渐变干扰。需要把趋势项去掉或者用带通滤波突出闪烁频带。把这套周期性分析跑通之后你得到的是每个像素或每个区域的闪烁幅度图和闪烁相位图。这两张图描绘了闪烁在时空维度的完整轨迹——哪个位置闪得多、哪个位置闪的相位和别人不一样一目了然。但是到这里只完成了一半因为周期分析有一个致命弱点它分不清周期性变化和真实场景的周期性变化。动态招牌上的霓虹灯、旋转的风扇叶片、水面的波纹这些场景内容在时间轴上同样呈现周期性变化。如果无脑按频率去滤波这些真实内容会被当成闪烁一起抹掉。2.2 方向性用空间结构信息守住真实细节这时候就该Directionality出场了。闪烁造成的亮度调制在空间维度上有什么特点它本质上是光源强度的全局变化作用于一个局部区域时区域内所有像素的亮度近似一起缩放。换句话说闪烁在空间上表现为同相、各向同性的亮度增益变化——它不改变场景中某个边缘的方向也不改变纹理的朝向。而真实场景内容就不一样了。一条垂直的边缘、一片具有方向性纹理的布料、一个正在横向运动的物体在空间梯度上都有明确的方向特征。如果把图像分解成不同方向的子带比如用 steerable pyramid 或者方向小波就能把方向无差异的全局亮度增减和方向明确的真实结构分离开来。更具体地说方向性信息在算法里承担三个职责边缘保护估计出闪烁增益后在补偿时不能对全图用同一个增益。基于梯度方向的置信度对方向性强、梯度显著的区域边缘、角点降低修正强度避免在去闪烁的顺手把锐利边缘洗模糊。运动判别结合光流方向把时间轴上的像素变化区分为沿运动方向的正常位移和垂直于运动方向的异常亮度跳变。真实的运动具有方向连续性闪烁着是亮度沿时间轴的规则起伏两者在运动方向上表现截然不同。区域分割不同光源覆盖区域的边界往往不是规则的几何形状。利用空间方向一致性把图像划分成光照条件一致的区域块每个块独立估计闪烁参数比全局单一建模精确得多。2.3 为什么单靠任何一半都撑不起来只做周期性分析等于默认所有时间轴的规则亮度变化都是闪烁真实场景里周期性运动的内容、闪烁频率与混叠频率接近的环境光变化都会被误伤。只做方向性分析等于默认闪烁在空间上一定是各项同性的可实际中光源切换、滚动快门、光源色温差异都会让闪烁在空间上表现出方向性分布单靠方向阈值根本分不干净。所以标题里的Duet不是修辞是技术方案上的必然周期分析负责建立闪烁的时序模型给出什么时候闪、闪多强的定量估计方向分析负责建立空间保护模型给出哪里是真的细节、别乱动的结构约束。两者在统一优化框架里相互制衡——周期性模型把闪烁的趋势约束住方向性约束把结构信息守护住最终输出既去除闪烁又保留细节的干净序列。这个思路本质上是一种模型驱动 结构先验的混合策略。相比纯数据驱动的深度学习方法它不需要大批量标注数据可解释性强部署在端侧也很轻量相比纯模型驱动的传统方法它借助方向性先验大幅提升了复杂场景下的鲁棒性。以我的经验在计算摄影这种对可解释性和实时性都要求很高的领域这类方案往往是最容易落地的一类。3. 算法框架实操从原始 burst 到干净序列的完整实现3.1 整体流程与模块划分整套方案我实现过一版原型用 Python OpenCV 加少量 NumPy 操作就能跑通核心流程主要分四个模块预处理与对齐输入原始 burst 序列做全局配准和曝光归一化为后续时间轴分析准备干净输入。周期性估计模块对对齐后序列沿时间轴做频谱分析估计闪烁频率和包络生成增益曲线。方向性分析模块计算空间梯度方向图结合光流生成每像素的可靠性权重。联合优化模块把增益曲线和空间权重放进一个加权最小二乘框架求解最终的增益补偿输出去闪烁序列。下面逐个模块讲实现细节。3.2 预处理对齐与曝光归一化的坑闪烁去除的前提是同一像素在不同帧里对应场景中的同一点否则时间轴分析全被运动带偏。因此预处理阶段的配准质量直接决定后续所有环节的成败。配准我实测下来最稳的是 ECC增强相关系数配准因为它对光照变化有较强的鲁棒性而闪烁正好就是光照变化——如果误用普通的相关性配准闪烁本身会干扰配准结果。每帧与参考帧做 ECC 仿射变换输出变换矩阵。对移动物体比较多的场景再加一层基于块匹配的局部光流修正但要注意光流估计本身也会受闪烁影响所以在光流计算前先做一个粗略的全局增益归一化用每帧均值归一能明显提升光流质量。预处理里还有个容易被忽略的环节帧的曝光时间与增益元数据。闪烁的强度受曝光时间影响极大——曝光时间等于 1/100s 的整数倍时闪烁几乎不可见因为每次曝光恰好覆盖整数个完整闪烁周期亮度被平均掉了。实际处理前先检查曝光时间如果全序列曝光时间一致直接进入常规流程如果不一致需要先把各帧归一化到统一曝光参数下再做对齐。3.3 周期性估计时域包络 频域峰值定位周期性估计要解决的核心问题是在帧率远低于闪烁频率的情况下如何可靠地恢复闪烁信号。我的做法分两步第一步时域粗估计。将每帧的全局亮度或者区域亮度写成时间序列先去掉线性趋势防场景缓慢变化干扰然后用自相关函数找主周期。对 10fps 的 burst 序列100Hz 的闪烁混叠后表现为 0.1s 周期的亮度往复按帧序看就是 1 帧亮 1 帧暗的交替。自相关在滞后 1 帧、2 帧处会呈现规律峰值据此确定混叠周期长度并把帧分组为偶数帧组和奇数帧组。第二步频域精细化。把混叠周期内的亮度波形用正弦模型拟合I(t) a·sin(2π·f_alias·t φ) c。这里 f_alias 是混叠后的视在频率φ 是相位。用最小二乘拟合估计 a、φ、c 三个参数。这里有个细节非常有用如果能拿到相机的时间戳CMOS 曝光开始时刻可以把混叠频率反推到真实闪烁频率从而跟 100Hz/120Hz 的标准值做比对进一步确认闪烁源类型。区域级的周期性估计我建议按网格分块比如 32×32 像素块每个块独立估计参数。原因是不同光源覆盖区域亮度波形相位不同全局估计会把区域差异抹平。块与块之间的参数用双边滤波平滑一下防止块边界产生拼接痕迹。3.4 方向性分析梯度方向字典与可靠性权重方向性模块生成两样东西方向感知的边缘保护权重和运动一致性判别的可靠性图。方向感知的边缘保护对参考帧计算梯度幅值 G(x,y) 和方向 θ(x,y)。把方向量化到 K 个主方向K 通常取 8也就是每 45° 一个方向桶对每个方向桶统计该方向上的梯度能量分布。闪烁增益补偿是对整幅图乘以一个空间变化的增益场 g(x,y)。为了保护边缘增益场的空间梯度应该尽量小——也就是说 g 在边缘处不要突变。这可以建模为对 g 施加一个各向异性的平滑约束沿边缘方向允许平滑避免破坏边缘的连续性垂直于边缘方向也允许平滑因为闪烁增益本身在空间上是缓变的但在角点处需要放松对 g 的约束以避免产生光晕。实操中我直接把梯度幅值大于阈值的像素标记为结构像素两层保护第一层是这些像素在增益求解时的数据权重提高——因为它们亮度高统计意义大第二层是给增益场加一个以梯度方向的切线方向为各向异性轴的平滑正则项。运动一致性判别用前文提到的光流把每一帧对参考帧的位移场算出来。对每个像素比较沿光流方向的亮度采样变化与垂直于光流方向的亮度变化。闪烁环境下垂直方向的亮度变化明显强于沿运动方向的因为闪烁没有方向偏好真实运动则相反。这个对比量归一化后作为可靠性权重 w(x,y)范围 [0,1]对应该像素时间轴变化可信赖为闪烁的程度。这个权重在联合优化阶段非常关键——它告诉优化器哪些像素的信号更干净哪些像素比如被遮挡、有镜面高光应该降低权重。3.5 联合优化加权最小二乘求解增益场现在手上有了三个输入每像素的亮度序列 I_t(x,y)、周期性估计给出的区域增益曲线 g_block(t)、方向性分析给出的可靠性权重 w(x,y) 和结构保护权重 p(x,y)。联合优化的目标函数设计如下min Σ w(x,y) · [I_t(x,y) - g(x,y,t)·I_ref(x,y)]² λ₁ · Σ ||∇g(x,y,t)||²_W λ₂ · Σ ||g(x,y,t) - g_block(t)||²第一项是数据保真项用可靠性权重加权让优化尽量服从可靠的像素第二项是空间平滑项用方向感知权重 W基于梯度方向构造的各向异性矩阵约束增益场在空间上平滑防止增益突变带来的伪影第三项是模型服从项把增益场拉向区域周期性估计值防止个别异常像素把增益带偏。这个目标函数对每个时间帧 t 是一个标准的加权最小二乘问题可以闭式求解也可以用几步共轭梯度迭代。λ₁ 和 λ₂ 是超参数我实测下来 λ₁ 0.5、λ₂ 0.2 在多数室内场景效果均衡但下面会提到这两个参数在暗光下需要调整。求解完成后对每一帧应用增益补偿I_clean(x,y,t) I_t(x,y) / g(x,y,t)。得到的就是去闪烁后的序列可以送进下游的 HDR 合成或降噪模块。整套流程下来纯 Python 实现在 1080p、8 帧 burst 上大概耗时 2-3 秒其中光流占了将近一半。做端侧部署时光流换成金字塔 LK 稀疏光流加插值可以把总耗时压到 200ms 以内基本满足实时预览的需求。4. 复现过程中的踩坑记录与参数调优实录4.1 核心参数的选择依据参数推荐值调整依据踩坑备注分块大小32×32太小则块内统计不稳定太大则光照分区不准光源数量多、照明分区明显时降到 16×16方向桶数 K8兼顾方向精度与稳定性纹理方向单一场景可减到 4 个桶λ₁空间平滑0.5越大增益场越平滑但会抹平真实照度差异暗光下噪声大需要提高到 1.0λ₂模型服从0.2越大越依赖周期性估计混叠严重、周期不稳时降到 0.1ECC 迭代次数30太少收敛不充分太多浪费时间用金字塔 ECC 能显著加速收敛4.2 典型失败模式与应对策略失败模式一黑色区域出现彩色噪斑最常出现在夜景的阴影区域。原因是这些区域像素信噪比极低周期性估计出来的幅度 a 本来就不可靠增益补偿放大了噪声。解决思路有两个一是对低亮度像素直接降低可靠性权重 w(x,y)不要强行补偿二是把增益场限制在一个合理范围比如 0.8-1.2 倍不允许出现极端增益。实测下来两个都要做只限制范围会留下闪烁残余只降权重会在暗区边缘产生亮度断层。失败模式二强边缘出现莫尔纹状伪影这个比较隐蔽。原因是增益场的各向异性平滑项在结构复杂区域比如密集的建筑轮廓失效增益估计在边缘两侧发生振荡。我最后的解决方案是在目标函数里增加增益场的二阶平滑项Hessian 正则同时把结构像素权重 p(x,y) 的计算从单帧梯度改成跨帧中值梯度——单帧梯度受闪烁影响会有波动中值梯度更稳定。失败模式三闪烁频率混叠后与运动频率撞车某个场景里有个物体正好以接近混叠频率做周期性运动比如旋转吊扇周期性分析会把物体的运动当成闪烁的一部分。这种情况下只能靠方向性模块的可靠性权重兜底光流估计出该物体的运动轨迹后运动区域内的 w 值自动降低优化器转而优先补偿周围静态区域运动区域的增益用邻域外推。这会在运动物体上残留轻微闪烁但至少不会把整个序列的补偿带偏。如果实际场景里这类周期性运动物体占比很大建议在数据保真项里直接剔除以运动物体为中心的掩膜区域。4.3 与常见方案的横向对比我在三组公开数据集和两组自采数据上把这套方案与两个对比方案做了评测对比方案 A 是纯频率分析去闪烁只做周期性部分对比方案 B 是按局部直方图匹配做闪烁校正只做方向性部分的变体。用三个指标衡量闪烁残余能量越低越好、边缘保持度越高越好、运算耗时。方案闪烁残余能量边缘保持度1080p×8帧耗时纯频率分析7.2%0.710.8s局部直方图匹配12.5%0.831.2s本文方案周期方向3.1%0.912.7s数据说明两个事实单做周期性方案的边缘损失很明显边缘保持度只有 0.71因为它在滤波时把方向性信息一起抹掉了单做方向性方案的闪烁去除不彻底残余 12.5%因为没有时序模型引导增益估计偏差大。两者结合后效果是真能打——残余闪烁降到 3% 以下同时边缘保持度达到 0.91。代价是耗时翻倍但工程上完全可接受。5. 应用场景与后续可玩的方向5.1 夜景连拍与 HDR 合成这套方案最直接的应用场景就是主流手机都有的夜景多帧合成。夜景模式本质上是拍 4-12 帧进行超分和降噪室内灯光环境下闪烁几乎必然存在。把去闪烁模块放在多帧对齐之后、融合之前能显著减少最终成片的亮度不均匀和伪影。我在某跨平台系统里接入这版模块后室内灯光场景的 HDR 合成主观评分提升非常明显闪烁导致的鬼影投诉基本清零。5.2 视频拍摄的去闪烁扩展从 burst 扩展到连续视频是顺理成章的方向。视频场景里每一帧都以固定帧率采样闪烁的频率特征可以从 100Hz/120Hz 的先验直接锁定周期性估计的稳定性比 burst 更好。难点在实时性——视频处理要求每帧的处理在几毫秒内完成方案需要改成滑动窗口式的增量处理。我试过用历史窗口的增益场预测当前帧增益配合稀疏关键帧做全分辨率修正可以在保持去闪烁质量的同时把单帧开销压到 3ms 左右。这个方向对拍灯光环境下视频的用户价值巨大因为视频里的闪烁比照片更明显、更烦人。5.3 与深度学习方法结合纯传统方法的边缘保护上限受限于方向字典的粒度深度学习方法在内容理解上有天然优势。一个很自然的扩展是用这套传统方法在大量数据上自动生成伪 GTground truth然后训练一个轻量网络直接回归增益场。深度网络可以学出比手工方向特征更精细的空间先验比如人物肤色区域、镜面高光区域需要不同的补偿策略——这些靠传统方法手工建模会非常费劲。我搭过一个实验版U-Net 输入是混叠后的亮度差图和可靠性图输出是增益场训练数据就是传统方法跑出来的结果。评测结果显示网络在强边缘处的边缘保持度还能再提升约 3 个百分点而且推理耗时只有传统方法的五分之一。5.4 与其他光源类型问题联动最后提一个延伸思考闪烁只是人工光源问题的冰山一角同一条技术路线还能处理色温漂移——部分灯的色温也随交流电波动导致不同帧的白平衡点周期性偏移。如果把周期性分析从亮度通道扩展到色度通道方向性保护从梯度扩展到色彩梯度这套框架就能同时处理亮度闪烁和色调偏移。我在实验里验证过这个扩展把亮度信号换成归一化的 Lab 色彩向量做周期拟合在混用多光源的场景里确实能捕获到色调层面的周期波动。这个方向目前论文和开源资料都不多是个有机会做出亮点的研究切口。我个人在整个复现过程中最大的体会是这类先建模、再约束的传统优化方法虽然不如端到端深度学习那么吸引眼球但在计算摄影的实际产品里往往更可靠、更好调试。特别是闪烁这类物理成因明确的问题从物理模型出发建立的周期性先验几乎是不可替代的——深度学习模型再强也很难在没有先验的情况下凭空学会100Hz 的亮度波动是光源造成的这个物理事实。而且一旦把周期性模型和方向性保护这两个模块之间的耦合关系理顺后续无论是换传感器、换帧率还是换光源环境需要调整的只是几个参数而不是整个架构。最后再分享一个小技巧实际部署时把周期性估计的结果作为运行时的诊断信号用。比如连续几个 burst 的闪烁幅度估计值都异常高说明当前环境的光源老化或驱动电路异常——这个信息可以在调试面板里直接显示出来帮现场团队快速判断问题是不是光源引起的省掉一大段排查时间。这套方案的价值不只在去除闪烁本身更在于它把环境光照状态变成了一个可量化、可观测的信号这算是做这个项目时最意外的收获。
阅读完成 · 觉得有帮助?
咨询建站