图像处理方法——导向滤波的原理
参考链接:详解——导向滤波(Guided Filter)和快速导向滤波
前言
1. 保边滤波的核心目标
核心矛盾:传统滤波(如高斯滤波)在平滑噪声时会模糊图像边缘
解决思路:在平滑区域内进行强滤波,在边缘处保持弱滤波
数学本质:设计权重函数使滤波器对边缘区域敏感
2. 经典保边滤波算法分类
(1) 基于局部统计的方法
- 双边滤波 (Bilateral Filter)
- 核心公式:
- 特点:空间+颜色相似性双重约束
- 缺点:O(N²)计算复杂度
(2) 基于偏微分方程的方法
- 各向异性扩散 (Anisotropic Diffusion)
- 原理:沿边缘切线方向扩散,法线方向抑制扩散
- 控制方程:
(3) 全局优化方法
- 加权最小二乘 (WLS Filter)
- 能量函数:
- 特点:显式控制平滑强度
(4) 基于引导图像的方法 → 导向滤波 (Guided Filter)
- 核心创新:利用引导图像生成线性系数
- 关键公式:
- 优势:O(N)线性复杂度,边缘保持性强
3. 导向滤波技术详解 算法流程
输入:引导图像,输入图像,窗口半径,正则化参数
计算局部均值: ,
计算方差与协方差: ,
线性系数计算: ,
输出滤波结果:
特性对比
| 滤波器类型 | 时间复杂度 | 边缘保持 | 梯度反转 | 硬件友好性 |
|---|---|---|---|---|
| 双边滤波 | O(N²) | 优秀 | 存在 | 差 |
| WLS | O(N) | 极好 | 无 | 一般 |
| 导向滤波 | O(N) | 优秀 | 无 | 极佳 |
导向滤波实现

输入: 输入图像p,经过引导图像I, 滤波得到输出图像q
公式推导见前文参考博客

最终结果如上, 为引导图I在窗口内的均值, 下面的 为引导图的方差。
过程来说,我们需要实现的是窗口内的I均值,p均值和Ip乘积的均值。至于方差换算,很容易推导得到为I的平方减去I均值的平方。
实际上可以直接用平均值卷积核来实现上述的所有操作。
python代码如下
def Guidedfilter(im, p, r, eps):
mean_I = cv2.boxFilter(im, cv2.CV_64F, (r, r))
mean_p = cv2.boxFilter(p, cv2.CV_64F, (r, r))
mean_Ip = cv2.boxFilter(im * p, cv2.CV_64F, (r, r))
cov_Ip = mean_Ip - mean_I * mean_p
mean_II = cv2.boxFilter(im * im, cv2.CV_64F, (r, r))
var_I = mean_II - mean_I * mean_I
a = cov_Ip / (var_I + eps)
b = mean_p - a * mean_I
mean_a = cv2.boxFilter(a, cv2.CV_64F, (r, r))
mean_b = cv2.boxFilter(b, cv2.CV_64F, (r, r))
return mean_a * im + mean_b该工作运用在诸如去雾等上面。用灰度图当引导图——
加一个新问题,如果输入“图像”p 是一个离散的数据又该如何处理。
答案是公式不变,但是不再使用简单的平均值卷积核。
下面给出相关修改,其中的mask作为一个判断是否为合法离散值的掩码,其余加入的一些极小值操作是为了防止出现0相除的情况,其余大部分同正常算法。
def lidar_guided_filter(I, p, r, eps=1e-3):
# 定义mask
mask = (p > 0) & (p < 1)
p = p * mask
# 定义窗口图f_k
f_k = cv2.boxFilter(mask.astype(np.float32), -1, (r, r), normalize=False)
# 计算m_p
m_p = cv2.boxFilter(p + 1e-6, -1, (r, r), normalize=False) / (f_k + 1e-6)
# 计算m_Ip
m_Ip = cv2.boxFilter(I * p + 1e-6, -1, (r, r), normalize=False) / (f_k + 1e-6)
# 计算m_II
I_mask = I * mask
m_II = cv2.boxFilter(I_mask * I_mask + 1e-6, -1, (r, r), normalize=False) / (f_k + 1e-6)
# 其余步骤不变
cov_Ip = m_Ip - m_p * m_p
var_I = m_II - m_p * m_p
a = cov_Ip / (var_I + eps)
b = m_p - a * m_p
m_a = cv2.boxFilter(a, -1, (r, r))
m_b = cv2.boxFilter(b, -1, (r, r))
cv2.imshow('m_a', m_a)
cv2.waitKey(0)
cv2.imshow('m_b', m_b)
cv2.waitKey(0)
return m_a * I + m_b