引导滤波推导及实现

引导滤波推导及实现

微信公众号:幼儿园的学霸

目录

前言

引导滤波顾名思义,就是有选择(引导)性的滤波,其与我们经常提及的高斯滤波、双边滤波相比,它具有引导性,说具体点就是,它通过输入一副图像(矩阵)作为引导图,这样滤波器就知道什么地方是边缘,以此更好的保护边缘,最终达到在滤波的同时,保持边缘细节。

各向同性滤波对待噪声和边缘信息采取一致的态度,从而导致噪声被磨皮的同时,图像中边缘,纹理和细节也被抹去了

推导

介绍

引导滤波的思想用一张引导图像 I I I产生权重 W W W,对输入图像 p p p进行处理得到输出图像 q q q,使得输出图像的梯度和引导图相似,但是灰度(亮度)与输入图像相似,这个过程可以表示为公式(1)中的内容。

Note:梯度和引导图相似,而非纹理等和引导图相似,关注这里是 梯度 !!!,后面提到的 梯度翻转

q i = ∑ j W i j ( I ) ⋅ p j (1) q_{i}=\sum_{j} W_{i j}(I) \cdot p_{j} \tag{1} qi=jWij(I)pj(1)
公式中 q , I , p q,I,p q,I,p分别表示输出图像、引导图像和输入图像. i , j i,j i,j分别表示图像中像素点的索引。从公式(1)中可以看到权重 W W W仅与引导图像 I I I有关.而在双边滤波中,权重由输入图像自身决定。

在引导滤波的定义中,用到了局部线性模型。
该模型认为,某函数上一点与其邻近部分的点成线性关系,一个复杂的函数就可以用很多分段的局部的线性函数来表示,当需要求该函数上某一点的值时,只需计算所有包含该点的线性函数的值并做平均即可。可以暂时用下图简单的理解。

这种模型,在表示非解析函数上,非常有用。

引申: 局部加权线性回归

引导滤波中核心假设就是输出图像与引导图像在局部上是一个线性的模型,在局部窗口 w k w_k wk中,输入图像与引导图像的线性关系可以表示成公式(2)中的形式:
q i = a k I i + b k , ∀ i ∈ w k (2) q_{i}=a_{k} I_{i}+b_{k}, \forall i \in w_{k} \tag{2} qi=akIi+bk,iwk(2)

公式中 a k , b k a_k,b_k ak,bk是窗口中的线性系数,在每个窗口中是常数。可以看到在滤波窗口 w k w_k wk中的所有像素点 i i i,其输出 q i q_i qi均是引导图 I i I_i Ii的线性变换,这个变换由 a k , b k a_k,b_k ak,bk决定。我们对上式两边求梯度,得到:
∇ q = a ∇ I (3) \nabla q=a \nabla I \tag{3} q=aI(3)
可以看到:
1.输出图像 q q q受到引导图像 I I I的约束,当引导图像在局部有梯度变化时,输出图像对应地也会有梯度变化。
2. a k a_k ak决定了梯度保留能力,如果 a k a_k ak较大,则梯度保留效果好;反之,则平滑效果好。这里也就明白了, a k , b k a_k,b_k ak,bk就是自适应调节因子了,我们希望在边缘处 a k a_k ak大些,其他地方 a k a_k ak小些,那么 a k , b k a_k,b_k ak,bk究竟应该怎样取值,才能实现这样一个自适应调节作用呢.

推导

因为我们是要对原图像进行滤波,所以在满足上面局部线性的基础上,还需要使输出图像尽可能逼近原图像,使得输入和输出之间的差异最小,原论文作者采用的是最小二乘方法,设计了一个代价函数使输出图像 q q q与原图像 p p p之间的均方误差最小,在窗口 w k w_k wk中的代价函数公式如下:
E ( a k , b k ) = ∑ i ∈ w k ( ( a k I i + b k − p i ) 2 + ϵ a k 2 ) (4) E(a_{k}, b_{k})=\sum_{i \in w_{k}}\left(\left(a_{k} I_{i}+b_{k}-p_{i}\right)^{2}+\epsilon a_{k}^{2}\right) \tag{4} E(ak,bk)=iwk((akIi+bkpi)2+ϵak2)(4)

可以看到,除了均方误差项之外,作者还添加了含ϵ的一项。作者在原文中解释说这是一个正则化参数,用来防止 a k a_k ak过大。我想大部分人应该对这个很熟悉,这不就是深度学习里损失函数的正则项嘛,只不过那个是用来惩罚网络中的权重,防止过拟合罢了。另外我们试想一下,如果没有这一项,在引导图像等于输入图像时,那么最小化上式,一定存在 a k = 1 , b k = 0 a_k=1,b_k=0 ak=1,bk=0,因为没有谁比自身更接近自身了嘛,这样带来的结果就是没有任何平滑效果,输出图像就是原图像本身。所以ϵ是一个非常重要的参数,选取不当会影响输出图像,后面会讲如何选取。

添加ϵ的项被称为L2正则项,添加该项后,上面方程为岭回归(Ridge Regression)方程

代价函数公式(4)使得 ( a k , b k ) (a_k,b_k) (ak,bk)的求解变成了线性回归问题,现在根据最小二乘法来推导如何求解 ( a k , b k ) (a_k,b_k) (ak,bk)

代价函数分别对 a k , b k a_k,b_k ak,bk求偏导:
δ E δ a k = ∑ i ∈ w k ( 2 ( a k I i + b k − p i ) I i + 2 ϵ a k ) δ E δ b k = ∑ i ∈ w k 2 ( a k I i + b k − p i ) (5) \begin{aligned} &\frac{\delta E}{\delta a_{k}}=\sum_{i \in w_{k}}\left(2\left(a_{k} I_{i}+b_{k}-p_{i}\right) I_{i}+2 \epsilon a_{k}\right) \\ &\frac{\delta E}{\delta b_{k}}=\sum_{i \in w_{k}} 2\left(a_{k} I_{i}+b_{k}-p_{i}\right) \end{aligned} \tag{5} δakδE=iwk(2(akIi+bkpi)Ii+2ϵak)δbkδE=iwk2(akIi+bkpi)(5)
N N N为窗口 w k w_k wk内像素点的数量,根据极小值处偏导数为0:
δ E δ b k = 0 ⇒ a k ∑ i ∈ w k I i − ∑ i ∈ w k p i + ∑ i ∈ w k b k = 0 ⇒ N b k = ∑ i ∈ w k p i − a k ∑ i ∈ w k I i ⇒ b k = ∑ i ∈ w k p i − a k ∑ i ∈ w k I i N = p ˉ k − a k μ k (6) \begin{aligned} &\frac{\delta E}{\delta b_{k}} =0 \\ &\Rightarrow a_{k} \sum_{i \in w_{k}} I_{i}-\sum_{i \in w_{k}} p_{i}+\sum_{i \in w_{k}} b_{k}=0 \\ &\Rightarrow N b_{k}=\sum_{i \in w_{k}} p_{i}-a_{k} \sum_{i \in w_{k}} I_{i} \\ &\Rightarrow b_{k} =\frac{\sum_{i \in w_{k}} p_{i}-a_{k} \sum_{i \in w_{k}} I_{i}}{N} = \bar{p}_{k}-a_{k} \mu_{k} \end{aligned} \tag{6} δbkδE=0akiwkIiiwkpi+iwkbk=0Nbk=iwkpiakiwkIibk=NiwkpiakiwkIi=pˉkakμk(6)
其中: μ k \mu_k μk为窗口 w k w_k wk范围内引导图 I I I的均值; p ˉ k \bar{p}_k pˉk为窗口 w k w_k wk范围内输入图 p p p的均值.

接下来求 a k a_k ak
δ E δ a k = 0 ⇒ ∑ i ∈ w k ( a k I i 2 + b k I i − p i I i + ϵ a k ) = 0 ⇒ ∑ i ∈ w k ( a k I i 2 + ( p ˉ k − a k μ k ) I i − p i I i + ϵ a k ) = 0 ⇒ a k = ∑ i ∈ w k ( p i I i ) − ∑ i ∈ w k ( p ˉ k I i ) ∑ i ∈ w k ( I i 2 − μ k I i + ϵ ) = ∑ i ∈ w k ( p i ∗ I i ) − ∑ i ∈ w k ( p ˉ k ∗ I i ) ∑ i ∈ w k I i 2 − μ k ∗ ∑ i ∈ w k I i + ∑ i ∈ w k ϵ = ∑ i ∈ w k ( p i ∗ I i ) − ( 1 N ∑ i ∈ w k p i ) ( ∑ i ∈ w k I i ) ∑ i ∈ w k I i 2 − ( 1 N ∑ i ∈ w k I i ) ∗ ( ∑ i ∈ w k I i ) + N ϵ = 1 N ∑ i ∈ w k ( p i ∗ I i ) − ( 1 N ∑ i ∈ w k p i ) ( 1 N ∑ i ∈ w k I i ) 1 N ∑ i ∈ w k I i 2 − ( 1 N ∑ i ∈ w k I i ) ∗ ( 1 N ∑ i ∈ w k I i ) + ϵ (7) \begin{aligned} &\frac{\delta E}{\delta a_{k}} = 0 \\ &\Rightarrow \sum_{i \in w_{k}}\left(a_{k} I_{i}^{2}+b_{k} I_{i}-p_{i} I_{i}+\epsilon a_{k}\right)=0 \\ &\Rightarrow \sum_{i \in w_{k}}\left(a_{k} I_{i}^{2}+ (\bar{p}_{k}-a_{k} \mu_{k}) I_{i}-p_{i} I_{i}+\epsilon a_{k}\right)=0 \\ \Rightarrow a_k &= \frac{\sum_{i \in w_{k}}(p_i I_i) - \sum_{i \in w_{k}}(\bar{p}_{k} I_i) }{ \sum_{i \in w_{k}}(I_{i}{^2}-\mu_k I_i + \epsilon ) } \\ &= \frac{\sum_{i \in w_{k}}(p_i *I_i) - \sum_{i \in w_{k}}(\bar{p}_{k} *I_i) }{ \sum_{i \in w_{k}}I_{i}{^2}- \mu_k*\sum_{i \in w_{k}} I_i + \sum_{i \in w_{k}} \epsilon } \\ &= \frac{\sum_{i \in w_{k}}(p_i *I_i) - (\frac{1}{N}\sum_{i \in w_{k}}p_i) (\sum_{i \in w_{k}}I_i )}{ \sum_{i \in w_{k}}I_{i}{^2}- (\frac{1}{N} \sum_{i \in w_{k}}I_i)*\left( \sum_{i \in w_{k}} I_i \right)+ N \epsilon } \\ &= \frac{\frac{1}{N} \sum_{i \in w_{k}}(p_i *I_i) - (\frac{1}{N}\sum_{i \in w_{k}}p_i) (\frac{1}{N}\sum_{i \in w_{k}}I_i )}{ \frac{1}{N}\sum_{i \in w_{k}}I_{i}{^2}- (\frac{1}{N} \sum_{i \in w_{k}}I_i)*\left( \frac{1}{N} \sum_{i \in w_{k}} I_i \right)+ \epsilon } \end{aligned} \tag{7} akδakδE=0iwk(akIi2+bkIipiIi+ϵak)=0iwk(akIi2+(pˉkakμk)IipiIi+ϵak)=0=iwk(Ii2μkIi+ϵ)iwk(piIi)iwk(pˉkIi)=iwkIi2μkiwkIi+iwkϵiwk(piIi)iwk(pˉkIi)=iwkIi2(N1iwkIi)(iwkIi)+Nϵiwk(piIi)(N1iwkpi)(iwkIi)=N1iwkIi2(N1iwkIi)(N1iwkIi)+ϵN1iwk(piIi)(N1iwkpi)(N1iwkIi)(7)
根据方差、协方差公式,以及方差和期望关系公式:
D ( X ) = E ( X − E ( X ) ) 2 = E ( X 2 − 2 X E ( X ) + E 2 ( X ) ) = E ( X 2 ) − 2 E ( X ) E ( X ) + E 2 ( X ) = E ( X 2 ) − E 2 ( X ) (8) \begin{aligned} D(X) &=E\left(X-E(X)\right)^{2}=E\left(X^{2}-2XE(X)+E^2(X)\right) \\ &=E(X^2)-2E(X)E(X)+E^2(X) \\ &=E(X^2)-E^2(X) \end{aligned} \tag{8} D(X)=E(XE(X))2=E(X22XE(X)+E2(X))=E(X2)2E(X)E(X)+E2(X)=E(X2)E2(X)(8)

Cov ⁡ ( X , Y ) = E [ ( X − E ( X ) ) ⋅ ( Y − E ( Y ) ) ] = E ( X Y ) − E [ X E ( Y ) + Y E ( X ) ] + E [ E ( X ) E ( Y ) ] = E ( X Y ) − 2 E ( X ) E ( Y ) + E ( X ) E ( Y ) = E ( X Y ) − E ( X ) E ( Y ) (9) \begin{aligned} \operatorname{Cov}(X, Y) &=E[(X-E(X)) \cdot(Y-E(Y))] \\ &=E(X Y)-E[X E(Y)+Y E(X)]+E[E(X) E(Y)] \\ &=E(X Y)-2 E(X) E(Y)+E(X) E(Y) \\ &=E(X Y)-E(X) E(Y) \end{aligned} \tag{9} Cov(X,Y)=E[(XE(X))(YE(Y))]=E(XY)E[XE(Y)+YE(X)]+E[E(X)E(Y)]=E(XY)2E(X)E(Y)+E(X)E(Y)=E(XY)E(X)E(Y)(9)
X = Y X=Y X=Y时,
Cov ⁡ ( X , X ) = E ( X X ) − E ( X ) E ( X ) = D ( X ) (10) \begin{aligned} \operatorname{Cov}(X, X) &=E(X X)-E(X) E(X) \\ &=D(X) \end{aligned} \tag{10} Cov(X,X)=E(XX)E(X)E(X)=D(X)(10)
根据公式(8)(9)对公式(7)进行整理,可得:
a k = Cov ⁡ ( p , I ) D ( I ) + ϵ = Cov ⁡ ( p , I ) σ k 2 + ϵ (11) a_k = \frac{\operatorname{Cov}(p, I)}{D(I)+\epsilon} = \frac{\operatorname{Cov}(p, I)}{\sigma_{k}^{2}+\epsilon} \tag{11} ak=D(I)+ϵCov(p,I)=σk2+ϵCov(p,I)(11)

得到上述 a k , b k a_k,b_k ak,bk后,可以对每个窗口 w k w_k wk计算一个 ( a k , b k ) (a_k,b_k) (ak,bk),但是,同一个像素会被不同的滤波窗口所包含。如下图所示:
滤波窗口

上图中存在黑色和红色两个3x3的滤波窗口,对于两个窗口交叠区域的那个像素q,假设在黑色和红色窗中,求得的 a k , b k a_k,b_k ak,bk分别为 ( a k 1 , b k 1 ) , ( ( a k 2 , b k 2 ) ) (a_{k1},b_{k1}),((a_{k2},b_{k2})) (ak1,bk1),((ak2,bk2));
那么在黑色窗中,它的输出可以表示为 q 1 = a k 1 I i 1 + b k 1 q_1=a_{k1}I_{i1}+b_{k1} q1=ak1Ii1+bk1,在红色窗中,它的输出可以表示为 q 2 = a k 2 I i 2 + b k 2 q_2=a_{k2}I_{i2}+b_{k2} q2=ak2Ii2+bk2。可见,对每个像素,都能计算出多个不同的 ( a k , b k ) (a_k,b_k) (ak,bk),因此作者使用各窗口 ( a k , b k ) (a_k,b_k) (ak,bk)计算得到的 q i q_i qi值求平均得到输出的 q i q_i qi值,上述过程描述如下:
q i = 1 N ∑ k , i ∈ w k ( a k I i + b k ) = a ˉ i I i + b ˉ i (12) \begin{aligned} q_{i} &=\frac{1}{N} \sum_{k, i \in w_{k}}\left(a_{k} I_{i}+b_{k}\right) \\ &=\bar{a}_{i} I_{i}+\bar{b}_{i} \end{aligned} \tag{12} qi=N1k,iwk(akIi+bk)=aˉiIi+bˉi(12)

其中, a ˉ i , b ˉ i \bar{a}_{i},\bar{b}_{i} aˉi,bˉi表示窗口 w k w_k wk范围内所有像素计算得到的 a k , b k a_k,b_k ak,bk的均值。(理论上,此处,不做均值处理也是可以的)
需要注意的是,经过公式(12)的变换后,输出图像不再是引导图像的简单的尺度缩放, ∇ q \nabla q q也不再是 ∇ I \nabla I I的简单缩放了,因为 ( a ˉ i , b ˉ i ) (\bar{a}_{i},\bar{b}_{i}) (aˉi,bˉi)空间可变,因此相当于被一个均值滤波器滤波,是一个平均值,所以输出图像的梯度将会比输入图像的梯度小一些。在这种情况下, ∇ q ≈ a ˉ ∇ I \nabla q \approx \bar{a} \nabla I qaˉI

引导滤波的算法流程及实现

计算流程

引导滤波的流程较为简单,按照上面的推导的公式进行计算即可:
0.输入引导图I和待处理图像p
1.计算引导图I的均值与方差、待处理图像p的均值,以及引导图和输入图像的乘积I*p
2.计算 ( a k , b k ) (a_k,b_k) (ak,bk)
a k = ( ( I ∗ p ) m e a n − I mean  ∗ p mean  ) / ( V a r ( I ) + ϵ ) b k = p mean  − a k ∗ I mean  \begin{aligned} &a_k=\left((I*p)_{mean}-I_{\text {mean }}* p_{\text {mean }}\right) /\left(Var(I)+\epsilon\right) \\ &b_k=p_{\text {mean }}-a_k *I_{\text {mean }} \end{aligned} ak=((Ip)meanImean pmean )/(Var(I)+ϵ)bk=pmean akImean 
3.计算a,b均值 a m e a n , b m e a n a_{mean},b_{mean} amean,bmean
4.根据a,b均值求解导向滤波结果
q = a m e a n ∗ I + b m e a n q=a_{mean}*I+b_{mean} q=ameanI+bmean
引导滤波流程

快速引导滤波流程

由于引导滤波效率问题,何凯明博士在2015年,对其做了优化,主要是采用了图像金字塔思想,基本原理是将引导图,输入图都进行下采样计算 ( a k , b k ) (a_k,b_k) (ak,bk),然后 ( a k , b k ) (a_k,b_k) (ak,bk)进行上采样恢复原始大小,整个算法流程如下:
快速引导滤波流程

自定义实现及效果

引导滤波算法快的关键之处在于计算 a k , b k a_k,b_k akbk所需的均值与方差都可以通过盒式滤波去实现,盒式滤波是一种与滤波半径大小无关的算法,其实现方法类似积分图思想,都是一种以空间换取时间的方式。
一般实现:

/*!
 * 自定义引导滤波
 * @param I 引导图CV_8UC1
 * @param p 待滤波图像CV_8UC1
 * @param dst 输出结果
 * @param r 滤波半径
 * @param eps 惩罚因子
 * @author liheng
 */
void guidedFilter(const cv::Mat& _I, const cv::Mat& _p, cv::Mat& dst,int r, double eps)
{
    /*

% GUIDEDFILTER   O(1) time implementation of guided filter.
     guidance image: I (should be a gray-scale/single channel image)
     filtering input image: p (should be a gray-scale/single channel image)
     local window radius: r
     regularization parameter: eps
*/
    cv::Mat I;
    _I.convertTo(I, CV_64FC1);
    cv::Mat p;
    _p.convertTo(p, CV_64FC1);

    r = 2*r+1;

    //mean_I = boxfilter(I, r) ./ N;
    cv::Mat mean_I;
    cv::boxFilter(I, mean_I, CV_64FC1, cv::Size(r,r));//计算导向均值mean_I
    //mean_p = boxfilter(p, r) ./ N;
    cv::Mat mean_p;
    cv::boxFilter(p, mean_p, CV_64FC1, cv::Size(r,r));//计算输入图像均值mean_p
    //mean_Ip = boxfilter(I.*p, r) ./ N;
    cv::Mat mean_Ip;
    cv::boxFilter(I.mul(p), mean_Ip, CV_64FC1,
                  cv::Size(r, r));//互相关均值mean_Ip
    //cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch.
    cv::Mat cov_Ip = mean_Ip - mean_I.mul(mean_p);//协方差Cov(I,p)
    //mean_II = boxfilter(I.*I, r) ./ N;
    cv::Mat mean_II;
    cv::boxFilter(I.mul(I), mean_II, CV_64FC1,
                  cv::Size(r, r));//自相关均值mean_II
    //var_I = mean_II - mean_I .* mean_I;
    cv::Mat var_I = mean_II - mean_I.mul(mean_I);//方差D(I)
    //a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper;
    cv::Mat a = cov_Ip / (var_I + eps);
    //b = mean_p - a .* mean_I; % Eqn. (6) in the paper;
    cv::Mat b = mean_p - a.mul(mean_I);
    //mean_a = boxfilter(a, r) ./ N;
    cv::Mat mean_a;
    cv::boxFilter(a, mean_a, CV_64FC1, cv::Size(r,r));
    //mean_a mean_b
    cv::Mat mean_b;
    cv::boxFilter(b, mean_b, CV_64FC1, cv::Size(r,r));

    //TODO:感兴趣的可以将mean_a,mean_b 显示出来,观察其结果
    //在图中可以看到,在边缘部分或变化剧烈的部分,a的值接近于1(白色),b的值接近为0(黑色),
    // 而在变化平坦的区域,a的值接近0(黑色),b的值为平坦区域像素的均值。
    //cv::imshow("a",mean_a);
    //cv::imshow("b",mean_b);
    //cv::waitKey(0);


    //q = mean_a .* I + mean_b; % Eqn. (8) in the paper;
    cv::Mat q = mean_a.mul(I) + mean_b;
    q.convertTo(dst,CV_8UC1);
}

快速引导滤波实现:

/*!
 * 自定义实现快速引导滤波
 * @param I_org 引导图CV_8UC1
 * @param p_org 待滤波图像CV_8UC1
 * @param dst 输出结果
 * @param r 滤波半径
 * @param eps 惩罚因子
 * @param s 下采样倍数,为1时,即为上面的普通引导滤波
 * @author liheng
 */
void fastGuidedFilter(const cv::Mat& I_org, const cv::Mat& p_org, cv::Mat& dst,int r, double eps, int s)
{
    /*
    % GUIDEDFILTER   O(N) time implementation of guided filter.
    %
    %   - guidance image: I (should be a gray-scale/single channel image)
    %   - filtering input image: p (should be a gray-scale/single channel image)
    %   - local window radius: r
    %   - regularization parameter: eps
    */

    cv::Mat I,_I;
    I_org.convertTo(_I, CV_64FC1);

    resize(_I,I,cv::Size(),1.0/s,1.0/s);



    cv::Mat p,_p;
    p_org.convertTo(_p, CV_64FC1);
    //p = _p;
    resize(_p, p, cv::Size(),1.0/s,1.0/s);


    r = (2 * r + 1)/s+1;

    //mean_I = boxfilter(I, r) ./ N;
    cv::Mat mean_I;
    cv::boxFilter(I, mean_I, CV_64FC1, cv::Size(r, r));

    //mean_p = boxfilter(p, r) ./ N;
    cv::Mat mean_p;
    cv::boxFilter(p, mean_p, CV_64FC1, cv::Size(r, r));

    //mean_Ip = boxfilter(I.*p, r) ./ N;
    cv::Mat mean_Ip;
    cv::boxFilter(I.mul(p), mean_Ip, CV_64FC1, cv::Size(r, r));

    //cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch.
    cv::Mat cov_Ip = mean_Ip - mean_I.mul(mean_p);

    //mean_II = boxfilter(I.*I, r) ./ N;
    cv::Mat mean_II;
    cv::boxFilter(I.mul(I), mean_II, CV_64FC1, cv::Size(r, r));

    //var_I = mean_II - mean_I .* mean_I;
    cv::Mat var_I = mean_II - mean_I.mul(mean_I);

    //a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper;
    cv::Mat a = cov_Ip / (var_I + eps);

    //b = mean_p - a .* mean_I; % Eqn. (6) in the paper;
    cv::Mat b = mean_p - a.mul(mean_I);

    //mean_a = boxfilter(a, r) ./ N;
    cv::Mat mean_a;
    cv::boxFilter(a, mean_a, CV_64FC1, cv::Size(r, r));
    cv::Mat rmean_a;
    resize(mean_a, rmean_a, cv::Size(I_org.cols, I_org.rows));

    //mean_b = boxfilter(b, r) ./ N;
    cv::Mat mean_b;
    cv::boxFilter(b, mean_b, CV_64FC1, cv::Size(r, r));
    cv::Mat rmean_b;
    resize(mean_b, rmean_b, cv::Size(I_org.cols, I_org.rows));

    //q = mean_a .* I + mean_b; % Eqn. (8) in the paper;
    cv::Mat q = rmean_a.mul(_I) + rmean_b;
    q.convertTo(dst,CV_8UC1);
}

调用实例及结果:

#include <iostream>
#include <opencv2/ximgproc/edge_filter.hpp> //opencv自带引导滤波实现
#include <opencv2/opencv.hpp>

int main()
{
    cv::Mat srcImage = cv::imread("./guidefilter.bmp", cv::IMREAD_COLOR);
    cv::imshow("src", srcImage);

    //cv::Mat I;
    //cv::cvtColor(srcImage,I,cv::COLOR_BGR2GRAY);

    std::vector<cv::Mat> channels;
    cv::split(srcImage,channels);

    std::vector<cv::Mat> my_guideChannels(3),cv_guideChannels(3);


    for(int i=0;i<3;++i)
    {
        guidedFilter(channels[i],channels[i],my_guideChannels[i],9,30);
        //fastGuidedFilter(channels[i],channels[i],my_guideChannels[i],9,30,3);
        cv::ximgproc::guidedFilter(channels[i],channels[i],cv_guideChannels[i],9,30);
    }


    cv::Mat my_dst,cv_dst;
    cv::merge(my_guideChannels,my_dst);
    cv::imshow("my_dst",my_dst);

    cv::merge(cv_guideChannels,cv_dst);
    cv::imshow("cv_dst",cv_dst);

    //std::cout<<my_dst-cv_dst<<std::endl;
    cv::waitKey(0);


    return 0;
}

程序输入图像及运行结果如下:

说明图像
输入图像输入图片
自定义实现自定义实现
OpenCV自带实现OpenCV自带实现

从图像上看,自定义实现和OpenCV自带实现效果基本一致,如果将2图像进行减操作,相减结果基本均为0
当然,OpenCV自带实现的算法由于进行一定的加速,其运行效率较高。

引导滤波的应用

应用

1.保边滤波
当引导图为输入图像,即 I = p I=p I=p时,该算法成为一个保边滤波器,此时可得上述计算 ( a k , b k ) (a_k,b_k) (ak,bk)的公式变为:
a k = σ k 2 σ k 2 + ϵ b k = ( 1 − a k ) p ˉ k \begin{gathered} a_{k}=\frac{\sigma_{k}^{2}}{\sigma_{k}^{2}+\epsilon} \\ b_{k}=\left(1-a_{k}\right) \bar{p}_{k} \end{gathered} ak=σk2+ϵσk2bk=(1ak)pˉk
考虑以下两种情况:

  • Case 1:平坦区域。如果在某个滤波窗口内,该区域是相对平滑的, σ k 2 ≪ ϵ \sigma_{k}^{2}\ll \epsilon σk2ϵ时, a k ≈ 0 , b k ≈ p ˉ k a_{k} \approx 0, b_{k} \approx \bar{p}_{k} ak0,bkpˉk。相当于对该区域作均值滤波。
  • Case 2:高方差区域。相反,如果该区域是边缘区域,方差很大 σ k 2 ≫ ϵ \sigma_{k}^{2}\gg \epsilon σk2ϵ时, a k ≈ 1 , b k ≈ 0 a_{k} \approx 1, b_{k} \approx 0 ak1,bk0。相当于在区域保持原有梯度。
    由上可知, ϵ \epsilon ϵ是调整图的模糊程度与边缘检测精度的参数
    2.图像去雾
    在图像去雾中,导向滤波一般用来细化透射率图像,以原图的灰度图为导向图,以粗投射率图为输入图,能得到非常精细的透射率图像。

优点

引导滤波相对于双边滤波最大的优点在于算法的复杂度与窗口的大小无关,对于处理较为大型的图片时,在效率上有明显的提升
同时,引导滤波可以很好地克服双边滤波中出现的梯度翻转(gradient reversal )的现象,因为假设前提便是存在线性关系,可以保证梯度一致;而对于双边滤波而言,对于梯度变化大的地方,由于周围没有相似的像素,高斯函数的权重不稳定,导致最终梯度出现反转现象

其他

基于深度学习的引导滤波,论文<< Fast End-to-End Trainable Guided Filter >>
论文地址:https://arxiv.org/abs/1803.05619
代码地址:https://github.com/wuhuikai/DeepGuidedFilter

参考资料

部分参考资料的推导过程有误,建议读者阅读时适当关注一下

0.导向滤波原论文地址
1.引导滤波guideFilter原理推导与实验
2.【图像处理】引导滤波(guided image filtering)
3.引导滤波/导向滤波(Guided Filter)
4.详细的引导滤波
5.详解——导向滤波(Guided Filter)和快速导向滤波



下面的是我的公众号二维码图片,按需关注。
图注:幼儿园的学霸

### 关于暗通道先验与引导滤波去雾公式推导 #### 暗通道先验原理 对于无雾图像,在大多数局部区域中至少有一种颜色分量具有很低的强度值。这一现象被称为暗通道先验。具体来说,如果一幅彩色图像是清晰的,则其暗通道可以表示为: \[ J^{dark}(x)=\min _{C \in\{R, G, B\}}\left(\min _{y \in \Omega(x)} I^{c}(y)\right) \] 其中 \(J^{dark}\) 表示输入图像在位置\(x\)处的暗通道估计值;Ω代表以像素\(x\)为中心的一个窗口邻域[^1]。 当处理有雾场景时,大气散射模型描述了成像过程中的物理关系: \[ I(x)=J(x)t(x)+A(1-t(x)) \] 这里\(I(x)\),\(J(x)\),\(t(x)\),以及\(A\)分别对应观测到的颜色向量、真实的表面反射率、透射率和全局大气光成分[^2]。 通过上述两个方程联立求解可得恢复后的无雾图像表达式。 #### 引导滤波器的作用机制 为了更精确地估算透射率并减少噪声影响,采用基于边缘保持平滑特性的引导滤波方法来优化初始计算得到的粗略透射图。该算法能够有效地保留物体边界的同时实现均匀区域内的一致性平滑效果。 给定一对指导图片G及其对应的待过滤信号P,输出Q定义如下: \[ Q_{p}=\mu_k+\epsilon / n_k * (P-\bar P)_k \] 此处下标k标记着当前考虑的小块范围内的统计特性; μ指代均值参数而ε则是正则化项用来控制光滑程度[^3]。 将此技术应用于透射率精炼过程中,可以获得更加自然逼真的去雾成果。 ```python import cv2 import numpy as np def dark_channel_prior(img, window_size=15): min_channels = cv2.erode(img, np.ones((window_size, window_size), dtype=np.uint8)) return np.min(min_channels, axis=2) def estimate_transmission(dark_channel, omega=0.95): transmission = 1 - omega * dark_channel return transmission # 更多代码省略... ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值