4. 经典防抖算法:均值滤波、维纳滤波与盲去卷积
图像防抖,说白了就是让模糊的图变清楚。我入行那会儿,第一个接触的项目就是手持设备上的夜景防抖。当时甲方拿来的样张,那叫一个惨不忍睹——全是运动模糊和噪声。嗯,今天咱们就来聊聊三种最经典的防抖算法。
4.1 均值滤波:简单粗暴的起点
均值滤波的思路特别直白:用周围像素的平均值代替当前像素。你想想看,如果图像是静止的,那每个像素点拍到的应该是同一个场景。一旦抖动,相邻帧之间就会产生位移,取个均值就能把随机抖动给平滑掉。
适用场景:轻度抖动、实时预览。我建议在硬件资源受限的嵌入式设备上优先考虑它——计算量小,延迟低。
数学上就一句话:
g(x,y) = (1/N) * Σ f(x+i, y+j) // 对邻域内所有像素求和取平均
但这里有个坑。我曾经在一个监控项目里直接用均值滤波去抖,结果画面是稳了,但边缘全糊了。为什么?因为均值滤波本质上是个低通滤波器,它把高频细节(边缘、纹理)和噪声一起滤掉了。
注意:均值滤波的核越大,平滑效果越强,但细节丢失也越严重。3×3核适合轻度抖动,5×5以上就要慎重了。
4.2 维纳滤波:从频域找最优解
均值滤波太粗糙,那有没有更聪明的办法?有,维纳滤波。它不光是取平均,而是从频域角度,把图像和噪声的统计特性都考虑进去。
我个人习惯把维纳滤波理解成「带权重的去卷积」。它假设图像和噪声都是随机过程,然后找一个线性滤波器,让输出和原始图像的均方误差最小。
公式长这样:
G(u,v) = [ H*(u,v) / (|H(u,v)|² + K) ] * F(u,v)
其中 K 是噪声与信号的功率比。K 越大,去噪越强;K 越小,细节保留越多。
| 参数 | 含义 | 调参经验 |
|---|---|---|
| H(u,v) | 模糊核的频域表示 | 需要提前估计,常用点扩散函数(PSF) |
| K | 噪声-信号功率比 | 我一般从 0.01 开始试,噪声大就往上加 |
| F(u,v) | 模糊图像的频域 | 直接做 FFT 得到 |
我的经验:维纳滤波在低照度场景下表现不错,但前提是你得知道模糊核。有一次我处理手机夜景照片,运动模糊是直线型的,用维纳滤波配合 15 像素的直线 PSF,效果比均值滤波好了一个档次。
4.3 盲去卷积:不知道模糊核怎么办?
现实很骨感。很多时候你根本不知道模糊核长什么样——是平移、旋转还是缩放?这时候就需要盲去卷积了。
盲去卷积的核心思想:一边估计模糊核,一边恢复清晰图像。两个未知数,一个方程,听起来像天方夜谭?其实它靠的是迭代优化。
常用的算法是 Richardson-Lucy 盲去卷积。流程如下:
- 初始化:随便给一个模糊核(比如高斯核),给一个初始图像(比如模糊图本身)。
- 迭代更新:用当前模糊核对图像做去卷积,得到新图像;再用新图像反过来更新模糊核。
- 收敛判断:直到图像和模糊核都不再明显变化。
避坑指南:我曾经在一个天文图像处理项目里用盲去卷积,结果迭代了 100 次还没收敛。后来发现是初始核给得太离谱。建议初始核用高斯核,标准差设 1-3 像素,收敛会快很多。
代码实现(Python 伪代码):
def blind_deconvolution(blurred, iterations=30):
# 初始化
kernel = gaussian_kernel(size=15, sigma=2)
latent = blurred.copy()
for i in range(iterations):
# 更新图像
latent = richardson_lucy(blurred, kernel, num_iters=5)
# 更新核
kernel = estimate_kernel(blurred, latent)
# 归一化
kernel /= kernel.sum()
return latent, kernel
4.4 三种算法对比
我把它们放在一起比一比,方便你选型:
| 算法 | 需要模糊核 | 计算量 | 适用场景 | 我的推荐 |
|---|---|---|---|---|
| 均值滤波 | 否 | 极低 | 实时预览、轻度抖动 | 嵌入式设备首选 |
| 维纳滤波 | 是 | 中等 | 已知运动轨迹、低照度 | 手机夜景模式 |
| 盲去卷积 | 否 | 高 | 未知模糊、科研场景 | 离线处理、高精度需求 |
4.5 知识体系总览
下面这张图把三种算法的关系和适用边界画清楚了:
4.6 实战建议
最后给几条实在的建议:
- 先判断抖动类型:平移抖动用均值滤波或维纳滤波,旋转抖动得用更复杂的模型。
- 噪声水平决定算法:信噪比高(>30dB)用维纳滤波,信噪比低用盲去卷积。
- 实时性要求:均值滤波能跑 60fps,维纳滤波大概 30fps,盲去卷积可能只有 1-2fps。
小技巧:我经常把均值滤波和维纳滤波串起来用——先用均值滤波做粗去噪,再用维纳滤波做精细恢复。效果往往比单独用任何一个都好。