精华内容
下载资源
问答
  • 导向滤波小结:从导向滤波(guided filter)到快速导向滤波(fast guide filter)的原理,应用及opencv实现...
    2021-04-22 09:26:06

    http://blog.csdn.net/kuweicai/article/details/78385871

    1. 导向滤波简介

    导向滤波是何凯明在学生时代提出的一个保边滤波(edge-preserving smoothing)算法。何凯明在cv圈应该算是名人了,学生时代关于图像去雾的研究就以第一作者的身份获得Best Paper Award(CVPR 2009),而且今年刚刚又斩获Marr Prize(ICCV 2017)。更多关于何凯明的最新研究动态可以点击以下链接何凯明。

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

    导向滤波作为一种保边滤波,可以运用在很多场合,比如美颜,去雾,三维重建等。

    如果你仅仅只是需要运用这个算法,现在opencv 3.0和MATLAB 14都已经添加了guided filter的API,可以直接调用。

    opencv中的API如下void cv::ximgproc::guidedFilter(),具体的可以参考opencv的帮助文档关于导向滤波的介绍guidedFilter。

    但是需要提醒的是,opencv中guidedFilter()函数包含在ximgproc模块下,但是从官方下载的标准的opencv.exe程序中并不包含该模块,需要分别下载opencv的source文件和contrib模块的source文件,然后自己编译,具体可以参考opencv3.1.0+contrib模块编译总结。

    2. 导向滤波的原理

    查看了很多相关的资料,觉得白马负金羁的导向滤波(Guided Filter)的解析与实现一文将其原理解释的非常通俗易懂了,这里就不再赘述。仅给出最后的推导结果,其中fmean为一个窗口半径为r的均值滤波器(对应的窗口大小为2r+1),corr为相关,var为方差,cov为协方差。

    35c016de0e8662b2efb25e4cc6c46ea7.png

    3. opencv实现代码

    这一部分主要参考了

    OpenCV导向滤波(引导滤波)实现(Guided Filter)代码,以及使用颜色先验算法去雾中的代码,进行了修改和注释。GuidedFilter()调用opencv自带的boxFilter()函数来实现求取平均值。关于opencv自带的boxFilter()函数的相关介绍可以参考

    boxFilter。

    GuidedFilter()的代码,比较容易理解:

    cv::Mat GuidedFilter(cv::Mat I,cv::Mat p,intr,doubleeps)

    {

    /*

    % 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.convertTo(_I, CV_64FC1,1.0/255);

    I = _I;

    cv::Mat _p;

    p.convertTo(_p, CV_64FC1,1.0/255);

    p = _p;

    //[hei, wid] = size(I);

    inthei = I.rows;

    intwid = I.cols;

    r=2*r+1;//因为opencv自带的boxFilter()中的Size,比如9x9,我们说半径为4

    //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));

    //mean_b = boxfilter(b, r) ./ N;

    cv::Mat mean_b;

    cv::boxFilter(b, mean_b, CV_64FC1,cv::Size(r, r));

    //q = mean_a .* I + mean_b; % Eqn. (8) in the paper;

    cv::Mat q = mean_a.mul(I) + mean_b;

    returnq;

    }

    需要注意的是,上面的函数只能对单一通道进行处理(如果是多通道,需要split后进行滤波,然后merge)。下面是调用GuidedFilter(),r=16, eps=0.01,对原图像进行滤波的结果。

    7552dfa80a43dc5da8d09e01fc53faab.png

    4. 快速导向滤波

    导向滤波的时间复杂度为O(N),其中N为像素点的个数。

    何凯明在2015又发表了一篇《Fast Guided Filter》的文章,阐述了一种很实用的更快速的导向滤波流程。如下所示。其本质是通过下采样减少像素点,计算mean_a & mean_b后进行上采样回复到原有的尺寸大小。假设缩放比例为s,那么缩小后像素点的个数为N/s^2,那么时间复杂度变为O(N/s^2)(只是需要注意的是上采样和下采样本身也是有时间消化的)。

    f63053d43d944fde739941d82e117dbd.png

    基于上面的理论,只需调用resize()函数来实现下采样和上采样,关于resize()函数的使用可以参考

    resize()代码如下:

    cv::Mat fastGuidedFilter(cv::Mat I_org,cv::Mat p_org,intr,doubleeps,ints)

    {

    /*

    % 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,1.0/255);

    resize(_I,I,Size(),1.0/s,1.0/s,1);

    cv::Mat p,_p;

    p_org.convertTo(_p, CV_64FC1,1.0/255);

    //p = _p;

    resize(_p, p, Size(),1.0/s,1.0/s,1);

    //[hei, wid] = size(I);

    inthei = I.rows;

    intwid = I.cols;

    r = (22* r +1)/s+1;//因为opencv自带的boxFilter()中的Size,比如9x9,我们说半径为4

    //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));

    Mat rmean_a;

    resize(mean_a, rmean_a, Size(I_org.cols, I_org.rows),1);

    //mean_b = boxfilter(b, r) ./ N;

    cv::Mat mean_b;

    cv::boxFilter(b, mean_b, CV_64FC1,cv::Size(r, r));

    Mat rmean_b;

    resize(mean_b, rmean_b, Size(I_org.cols, I_org.rows),1);

    //q = mean_a .* I + mean_b; % Eqn. (8) in the paper;

    cv::Mat q = rmean_a.mul(_I) + rmean_b;

    returnq;

    }

    取s==8,计算结果和之前的guidedFilter()的计算结果如下所示:

    d186cce77fe73cfdb7c1e19cd5c8c357.png

    而计算时间却从 338.808ms降到100.856ms,但是滤波结果从肉眼观察几乎没有降低。

    更多相关内容
  • 基于python的导向滤波与快速导向滤波算法
  • 快速导向滤波

    2015-08-17 11:33:58
    快速导向滤波 在导向滤波的基础上进行优化,给出了优化步骤
  • 详解——导向滤波(Guided Filter)和快速导向滤波

    千次阅读 多人点赞 2020-03-09 15:31:59
    在图像滤波算法中,导向滤波、双边滤波、最小二乘滤波并称三大保边滤波器,他们是各向异性滤波器。相对于常见的均值滤波、高斯滤波等各向同性滤波器,他们最大的特点是在去除噪声的同时,能最大限度保持边缘不被平滑...

    导读

    在图像滤波算法中,导向滤波、双边滤波、最小二乘滤波并称三大保边滤波器,他们是各向异性滤波器。相对于常见的均值滤波、高斯滤波等各向同性滤波器,他们最大的特点是在去除噪声的同时,能最大限度保持边缘不被平滑。本文讲解导向滤波及其应用。
    总的来讲,导向滤波就是尽可能让输出图像的梯度和导向图相似,同时让输出图像的灰度(亮度)与输入图像相似,以此来保留边缘并且滤除噪声。


    原理推导

    我们先看下图:
    在这里插入图片描述
    输入图像 p p p,经过引导图像 I I I, 滤波得到输出图像 q q q, 导向滤波算法中有一个重要假设:即在局部窗口 w k w_k wk上,导向图 I I I和输出图 q q q存在局部线性关系:
    q i = a k I i + b k , ∀ i ∈ w k (1) q_i = a_kI_i + b_k, \forall{i\in{w_k}}\tag{1} qi=akIi+bk,iwk(1)
    同时在窗口 w k w_k wk上, 滤波后的图像 q q q和输入图像 p p p有如下关系:
    q i = p i − n i , ∀ i ∈ w k (2) q_i = p_i - n_i,\forall{i\in{w_k}}\tag{2} qi=piniiwk(2)
    这样公式 ( 1 ) (1) (1)的线性关系保证了如果在每个局部窗口 w k w_k wk中,如果导向图 I I I中存在一个边缘,输出图像 q q q将保持边缘不变。同时,滤波结果图 q q q要尽可能与输入图像 p p p相同以此减小滤波带来的信息损失,该算法的最小二乘表示即:
    a r g m i n ∑ i ∈ w k ( q i − p i ) 2 = a r g m i n ∑ i ∈ w k ( a k I i + b k − p i ) 2 argmin\sum_{i\in{w_k}}(q_i-p_i)^2 = argmin\sum_{i\in{w_k}}(a_kI_i+b_k-p_i)^2 argminiwk(qipi)2=argminiwk(akIi+bkpi)2
    这是求解最优值的问题,引入一个正则化参数 ϵ \epsilon ϵ防止 a k a_k ak过大,得到损失函数:
    E ( a k , b k ) = ∑ i ∈ w k ( ( a k I i + b k − p i ) 2 + ϵ a k 2 ) (3) E(a_k,b_k)=\sum_{i\in{w_k}}((a_kI_i+b_k-p_i)^2+\epsilon{a_k^2})\tag{3} E(ak,bk)=iwk((akIi+bkpi)2+ϵak2)(3)
    运用最小二乘法求解极小值,利用极小值处导数为0,求解过程如下, ∣ w ∣ |w| w为窗口 w k w_k wk像素数量:
    δ E a k = ∑ i ∈ w k ( 2 ( a k I i + b k − p i ) I i + 2 ϵ a k ) = 0 ⇒ ∑ i ∈ w k ( a k I i 2 + b k I i − p i I i + ϵ a k ) = 0 δ E b k = ∑ i ∈ w k 2 ( a k I i + b k − p i ) = 0 ⇒ a k ∑ i ∈ w k I i − ∑ i ∈ w k p i + ∑ i ∈ w k b k = 0 ⇒ ∣ w ∣ b k = ∑ i ∈ w k p i − a k ∑ i ∈ w k I i \begin{aligned} \frac{\delta{E}}{a_k} &= \sum_{i\in{w_k}}(2(a_kI_i+b_k-p_i)I_i+2\epsilon{a_k}) = 0 \\ & \Rightarrow \sum_{i\in{w_k}}(a_kI_i^2+b_kI_i-p_iI_i+\epsilon{a_k}) = 0 \\ \frac{\delta{E}}{b_k} & = \sum_{i\in{w_k}}2(a_kI_i+b_k-p_i)= 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 |w|b_k = \sum_{i\in{w_k}}{p_i}-a_k\sum_{i\in{w_k}}{I_i} \end{aligned} akδEbkδE=iwk(2(akIi+bkpi)Ii+2ϵak)=0iwk(akIi2+bkIipiIi+ϵak)=0=iwk2(akIi+bkpi)=0akiwkIiiwkpi+iwkbk=0wbk=iwkpiakiwkIi
    由上面推到得出:
    a k = ∑ i ∈ w k p i I i − b k ∑ i ∈ w k I i ∑ i ∈ w k ( I i 2 + ϵ ) b k = ∑ i ∈ w k p i − a k ∑ i ∈ w k I i ∣ w ∣ = p ‾ k − a k μ k (4) \begin{aligned} a_k &= \frac{\sum_{i\in{w_k}}p_iI_i-b_k\sum_{i\in{w_k}}I_i}{\sum_{i\in{w_k}}(I_i^2+\epsilon)} \\ b_k &= \frac{\sum_{i\in{w_k}}{p_i}-a_k\sum_{i\in{w_k}}{I_i}}{|w|} \\ & = \overline{p}_k - a_k\mu_k \tag{4} \end{aligned} akbk=iwk(Ii2+ϵ)iwkpiIibkiwkIi=wiwkpiakiwkIi=pkakμk(4)
    其中: μ k — — 窗 口 w k 范 围 内 引 导 图 I 的 均 值 ; p ‾ k — — 窗 口 w k 范 围 内 输 入 图 p 的 均 值 。 \begin{aligned} & \mu_k——窗口w_k范围内引导图I的均值;\\ & \overline{p}_k——窗口w_k范围内输入图p的均值。 \end{aligned} μkwkIpkwkp
    b k b_k bk代入 a k a_k ak计算可得:
    a k = ∑ i ∈ w k p i I i − b k ∑ i ∈ w k I i ∑ i ∈ w k ( I i 2 + ϵ ) a_k = \frac{\sum_{i\in{w_k}}p_iI_i-b_k\sum_{i\in{w_k}}I_i}{\sum_{i\in{w_k}}(I_i^2+\epsilon)} ak=iwk(Ii2+ϵ)iwkpiIibkiwkIi
    ⇒ a k = ∑ i ∈ w k ( p i I i − p ‾ k I i ) ∑ i ∈ w k ( I i 2 + μ k I i + ϵ ) \Rightarrow a_k = \frac{\sum_{i\in{w_k}}(p_iI_i-\overline{p}_kI_i)}{\sum_{i\in{w_k}}(I_i^2+\mu_kI_i+\epsilon)} ak=iwk(Ii2+μkIi+ϵ)iwk(piIipkIi)
    ⇒ a k = ∑ i ∈ w k ( p i I i − p ‾ k I i + μ k p i − μ k p ‾ k ) ∑ i ∈ w k ( I i 2 − μ k I i − μ k I i + μ k 2 + ϵ ) \Rightarrow a_k = \frac{\sum_{i\in{w_k}}(p_iI_i-\overline{p}_kI_i {\color{red}{+\mu_kp_i-\mu_k\overline{p}_k}})}{\sum_{i\in{w_k}}(I_i^2-\mu_kI_i{\color{red}{-\mu_kI_i+\mu_k^2}}+\epsilon)} ak=iwk(Ii2μkIiμkIi+μk2+ϵ)iwk(piIipkIi+μkpiμkpk)
    上下两边同除以 ∣ w ∣ |w| w。得到:
    a k = 1 ∣ w ∣ ∑ i ∈ w k p i I i − p ‾ k μ k + μ k p ‾ k − μ k p ‾ k 1 ∣ w ∣ ∑ i ∈ w k ( I i − μ k ) 2 + ϵ a_k = \frac{\frac{1}{|w|}\sum_{i\in{w_k}}p_iI_i-\overline{p}_k\mu_k{\color{red}{+\mu_k\overline{p}_k-\mu_k\overline{p}_k}}}{\frac{1}{|w|}\sum_{i\in{w_k}}(I_i-\mu_k)^2+\epsilon} ak=w1iwk(Iiμk)2+ϵw1iwkpiIipkμk+μkpkμkpk
    最后:
    a k = 1 ∣ w ∣ ∑ i ∈ w k p i I i − μ k p ‾ k σ k 2 + ϵ (5) \color{red}{a_k = \frac{\frac{1}{|w|}\sum_{i\in{w_k}}p_iI_i{ - \mu_k\overline{p}_k}}{\sigma_k^2+\epsilon}} \tag{5} ak=σk2+ϵw1iwkpiIiμkpk(5)
    b k = p ‾ k + a k μ k (6) \color{red}{b_k = \overline{p}_k+a_k\mu_k} \tag{6} bk=pk+akμk(6)
    得到上述公式后,可以对每个窗口 w k w_k wk计算一个 ( 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)计算得到的 q i q_i qi值求平均得到输出 q i q_i qi值,上述过程描述如下:
    q i = 1 w k ∑ k , i ∈ w k ( a k I i + b k ) = a ‾ i I i + b ‾ i \begin{aligned} q_i &= \frac{1}{w_k}\sum_{k,i\in{w_k}}(a_kI_i+b_k) \\ & = \overline{a}_iI_i+\overline{b}_i \end{aligned} qi=wk1k,iwk(akIi+bk)=aiIi+bi
    其中: a ‾ i — — 窗 口 w k 范 围 内 所 有 像 素 计 算 得 到 的 a k 的 均 值 ; b ‾ i — — 窗 口 w k 范 围 内 所 有 像 素 计 算 得 到 的 b k 的 均 值 。 \begin{aligned} & \overline{a}_i——窗口w_k范围内所有像素计算得到的a_k的均值;\\ & \overline{b}_i——窗口w_k范围内所有像素计算得到的b_k的均值。 \end{aligned} aiwkakbiwkbk

    导向滤波的应用

    • 保边滤波
      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 a_k = \frac{\sigma_k^2}{\sigma_k^2+\epsilon} \\ b_k = (1-a_k)\overline{p}_k ak=σk2+ϵσk2bk=(1ak)pk
      考虑以下两种情况:
      • Case 1:平坦区域。如果在某个滤波窗口内,该区域是相对平滑的,方差 σ k 2 \sigma_k^2 σk2将远远小于 ϵ \epsilon ϵ。从而 a k ≈ 0 , b k ≈ p ‾ k a_k≈0,b_k≈\overline{p}_k ak0,bkpk。相当于对该区域作均值滤波。
      • Case 2:高方差区域。相反,如果该区域是边缘区域,方差很大, σ k 2 \sigma_k^2 σk2将远远大于 ϵ \epsilon ϵ。从而 a k ≈ 1 , b k ≈ 0 a_k≈1,b_k≈0 ak1,bk0。相当于在区域保持原有梯度。
        以上可以出: ϵ \epsilon ϵ为界定平滑区域和边缘区域的阈值。
    • 图像去雾
      在图像去雾中,导向滤波一般用来细化透射率图像,以原图的灰度图为导向图,以粗投射率图为输入图,能得到非常精细的透射率图像。

    当然,导向滤波的应用不止以上两种,网上还有图像融合等应用,本人没有去了解。

    导向滤波的实现

    导向滤波的代码实现较为简单,我们直接贴出计算流程在这里插入图片描述

    快速导向滤波的实现

    由于导向滤波效率问题,何凯明博士在2015年,对其做了优化,基本原理是将导向图,输入图都进行下采样计算 ( a k , b k ) (a_k,b_k) (ak,bk),然后对 ( a k , b k ) (a_k,b_k) (ak,bk)进行上采样恢复原始大小,整个算法流程如下:在这里插入图片描述

    算法效果

    我们演示一下保边滤波效果:在这里插入图片描述

    代码

    接下来,废话不多说,我们上代码:https://github.com/ZPEthanWen/ImageAlgorithmDraft,为防止github无法访问,我们直接贴上代码:

    • 导向滤波
    #include <opencv2/opencv.hpp>
    //导向滤波
    void GuidedFilter(cv::Mat& srcImage, cv::Mat& guidedImage, cv::Mat& outputImage, int filterSize, double eps)
    {
    	try
    	{
    		if (srcImage.empty() || guidedImage.empty() || filterSize <= 0 || eps < 0 ||
    			srcImage.channels() != 1 || guidedImage.channels() != 1)
    		{
    			throw "params input error";
    		}
    		cv::Mat srcImageP, srcImageI, meanP, meanI, meanIP, meanII, varII, alfa, beta;
    		srcImage.convertTo(srcImageP, CV_32FC1);
    		guidedImage.convertTo(srcImageI, CV_32FC1);
    		cv::boxFilter(srcImageP, meanP, CV_32FC1, cv::Size(filterSize, filterSize));
    		cv::boxFilter(srcImageI, meanI, CV_32FC1, cv::Size(filterSize, filterSize));
    		cv::boxFilter(srcImageI.mul(srcImageP), meanIP, CV_32FC1, cv::Size(filterSize, filterSize));
    		cv::boxFilter(srcImageI.mul(srcImageI), meanII, CV_32FC1, cv::Size(filterSize, filterSize));
    		varII = meanII - meanI.mul(meanI); 
    		alfa = (meanIP - meanI.mul(meanP)) / (varII + eps);
    		beta = meanP - alfa.mul(meanI);
    		cv::boxFilter(alfa, alfa, CV_32FC1, cv::Size(filterSize, filterSize));
    		cv::boxFilter(beta, beta, CV_32FC1, cv::Size(filterSize, filterSize));
    		outputImage = (alfa.mul(srcImageI) + beta);
    	}
    	catch (cv::Exception& e)
    	{
    		throw e;
    	}
    	catch (std::exception& e)
    	{
    		throw e;
    	}
    }
    
    • 快速导向滤波
    #include <opencv2/opencv.hpp>
    //快速导向滤波
    void FastGuidedFilter(cv::Mat& srcImage, cv::Mat& guidedImage, cv::Mat& outputImage, int filterSize, double eps, int samplingRate)
    {
    	try
    	{
    		if (srcImage.empty() || guidedImage.empty() || filterSize <= 0 || eps < 0 ||
    			srcImage.channels() != 1 || guidedImage.channels() != 1 || samplingRate < 1)
    		{
    			throw "params input error";
    		}
    		cv::Mat srcImageP, srcImageSubI, srcImageI, meanP, meanI, meanIP, meanII, var, alfa, beta;
    		
    		cv::resize(srcImage, srcImageP, cv::Size(srcImage.cols / samplingRate, srcImage.rows / samplingRate));
    		cv::resize(guidedImage, srcImageSubI, cv::Size(srcImage.cols / samplingRate, srcImage.rows / samplingRate));
    
    		filterSize = filterSize / samplingRate;
    
    		srcImageP.convertTo(srcImageP, CV_32FC1);
    		guidedImage.convertTo(srcImageI, CV_32FC1);
    		srcImageSubI.convertTo(srcImageSubI, CV_32FC1);
    		cv::boxFilter(srcImageP, meanP, CV_32FC1, cv::Size(filterSize, filterSize));
    		cv::boxFilter(srcImageSubI, meanI, CV_32FC1, cv::Size(filterSize, filterSize));
    		cv::boxFilter(srcImageSubI.mul(srcImageP), meanIP, CV_32FC1, cv::Size(filterSize, filterSize));
    		cv::boxFilter(srcImageSubI.mul(srcImageSubI), meanII, CV_32FC1, cv::Size(filterSize, filterSize));
    		var = meanII - meanI.mul(meanI);
    		alfa = (meanIP - meanI.mul(meanP)) / (var + eps);
    		beta = meanP - alfa.mul(meanI);
    		cv::boxFilter(alfa, alfa, CV_32FC1, cv::Size(filterSize, filterSize));
    		cv::boxFilter(beta, beta, CV_32FC1, cv::Size(filterSize, filterSize));
    		cv::resize(alfa, alfa, cv::Size(srcImage.cols, srcImage.rows));
    		cv::resize(beta, beta, cv::Size(srcImage.cols, srcImage.rows));
    		outputImage = alfa.mul(srcImageI) + beta;
    	}
    	catch (cv::Exception& e)
    	{
    		throw e;
    	}
    	catch (std::exception& e)
    	{
    		throw e;
    	}
    }
    

    参考

    [1] 视觉一只白 .《导向滤波的原理及实现》[DB/OL].
    [2] lsflll.《导向滤波(Guided Filter)公式详解》[DB/OL]
    [3] SongpingWang.《OpenCV—Python 导向滤波》[DB/OL]

    展开全文
  • Opencv-Python-导向滤波&快速导向滤波

    千次阅读 2018-11-07 22:31:38
    导向滤波算法原理 原理可以看博主:白马负金羁 的文章导向滤波(Guided Filter)的解析与实现,对原理解释十分通俗易懂。 导向滤波: 1.实现的伪代码: 导向图像(Guidance Image) I,滤波输出图像(Filtering ...

    版本:Python:2.7.15  OpenCV:2.4.13

    导向滤波算法原理

    原理可以看博主:白马负金羁 的文章导向滤波(Guided Filter)的解析与实现,对原理解释十分通俗易懂。


    导向滤波:

    1.实现的伪代码:

    导向图像(Guidance Image) I,滤波输出图像(Filtering Input Image) p,均值平滑窗口半径 r,正则化参数 e。

    利用导向滤波进行图像平滑处理时,通常令p=I。

    2.opencv库代码实现:

    其中:guideFilter(函数调用opencv自带的库函数blur() 进行均值平滑。

    def guideFilter(I, p, winSize, eps):
        
        #I的均值平滑
        mean_I = cv2.blur(I, winSize)
        
        #p的均值平滑
        mean_p = cv2.blur(p, winSize)
        
        #I*I和I*p的均值平滑
        mean_II = cv2.blur(I*I, winSize)
        
        mean_Ip = cv2.blur(I*p, winSize)
        
        #方差
        var_I = mean_II - mean_I * mean_I #方差公式
        
        #协方差
        cov_Ip = mean_Ip - mean_I * mean_p
       
        a = cov_Ip / (var_I + eps)
        b = mean_p - a*mean_I
        
        #对a、b进行均值平滑
        mean_a = cv2.blur(a, winSize)
        mean_b = cv2.blur(b, winSize)
        
        q = mean_a*I + mean_b
        
        return q

    3.结果对比:

    下图采用了r=16也就是winSize=(16,16), eps=0.01的参数大小。


    快速导向滤波

    通过下采样减少像素点,计算mean_a & mean_b后进行上采样恢复到原有的尺寸大小。

    假设缩放比例为s,那么缩小后像素点的个数为N/s^2,那么时间复杂度变为O(N/s^2)

     

    1.实现的伪代码:

    fmean代表均值平滑,fsubsample代表图像下采样即缩小图像,fupsample代表图片上采样即放大图像,s为缩小系数。

    2.opencv库代码实现:

    这里使用opencv自带库函数resize()进行上下采样

    def guideFilter(I, p, winSize, eps, s):
        
        #输入图像的高、宽
        h, w = I.shape[:2]
        
        #缩小图像
        size = (int(round(w*s)), int(round(h*s)))
        
        small_I = cv2.resize(I, size, interpolation=cv2.INTER_CUBIC)
        small_p = cv2.resize(I, size, interpolation=cv2.INTER_CUBIC)
        
        #缩小滑动窗口
        X = winSize[0]
        small_winSize = (int(round(X*s)), int(round(X*s)))
        
        #I的均值平滑
        mean_small_I = cv2.blur(small_I, small_winSize)
        
        #p的均值平滑
        mean_small_p = cv2.blur(small_p, small_winSize)
        
        #I*I和I*p的均值平滑
        mean_small_II = cv2.blur(small_I*small_I, small_winSize)
        
        mean_small_Ip = cv2.blur(small_I*small_p, small_winSize)
        
        #方差
        var_small_I = mean_small_II - mean_small_I * mean_small_I #方差公式
        
        #协方差
        cov_small_Ip = mean_small_Ip - mean_small_I * mean_small_p
       
        small_a = cov_small_Ip / (var_small_I + eps)
        small_b = mean_small_p - small_a*mean_small_I
        
        #对a、b进行均值平滑
        mean_small_a = cv2.blur(small_a, small_winSize)
        mean_small_b = cv2.blur(small_b, small_winSize)
        
        #放大
        size1 = (w, h)
        mean_a = cv2.resize(mean_small_a, size1, interpolation=cv2.INTER_LINEAR)
        mean_b = cv2.resize(mean_small_b, size1, interpolation=cv2.INTER_LINEAR)
        
        q = mean_a*I + mean_b
        
        return q

    3.结果对比:

    下图导向滤波采用了r=16也就是winSize=(16,16), eps=0.01的参数大小。  

           快速导向滤波采用了r=16也就是winSize=(16,16), eps=0.01,s=0.5的参数大小。

    从结果上看二者的滤波结果别无二致,但是运行时间有所降低。


    代码运行注意

    1.输入图像必须归一化

    image = cv2.imread(r'C:\Users\1.jpg', cv2.IMREAD_ANYCOLOR)
    #将图像归一化
    image_0_1 = image/255.0

    2.图像保存问题

    导向滤波返回的是灰度值范围在[0,1]之间的图像矩阵,像保存8位图要先乘255,再转换数据类型。

    #保存导向滤波结果   
    gf = gf*255
    gf[gf>255] = 255
    gf = np.round(gf)
    gf = gf.astype(np.uint8)
    cv2.imwrite(r'C:\Users\2.jpg', gf)

    3.关于cv2.resize()函数

    cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) -> dst 

    参数说明:

    src - 原图

    dst - 目标图像。

    当参数dsize不为0时,dst的大小为size;否则,它的大小需要根据src的大小,参数fx和fy决定。dst的类型(type)和src图像相同

    dsize - 目标图像大小。

    当dsize为0时,它可以通过以下公式计算得出:

    所以,参数dsize和参数(fx, fy)不能够同时为0

    fx - 水平轴上的比例因子。当它为0时,计算公式如下:

    fy - 垂直轴上的比例因子。当它为0时,计算公式如下:

    interpolation - 插值方法:

    1)INTER_NEAREST - 最近邻插值法

    2)INTER_LINEAR - 双线性插值法(默认)

    3)INTER_AREA - 基于局部像素的重采样(resampling using pixel area relation)。对于图像抽取(image decimation)来说,这可能是一个更好的方法。但如果是放大图像时,它和最近邻法的效果类似。

    4)INTER_CUBIC - 基于4x4像素邻域的3次插值法

    5)INTER_LANCZOS4 - 基于8x8像素邻域的Lanczos插值

     

    4.多通道处理

    本文的两个滤波函数只能对单一通道进行处理,如果是多通道,需要split()函数将原图分为RGB三张图,然后分别进行滤波,然后再用merge()函数将三张图合为一张。

    #导向滤波(三通道)
    b, g, r = cv2.split(image_0_1)
    gf1 = guideFilter(b, b, (16,16), math.pow(0.1,2))
    gf2 = guideFilter(g, g, (16,16), math.pow(0.1,2))
    gf3 = guideFilter(r, r, (16,16), math.pow(0.1,2))
    gf = cv2.merge([gf1, gf2, gf3])

    5.计算函数运行时间

    # time start
    t1 = cv2.getTickCount()
    
    """
    代码段落
    """
    # time end
    t2 = cv2.getTickCount()
    
    #计算执行秒数,利用getTickFrequency()获取时钟频率
    t = (t2-t1)/cv2.getTickFrequency()
    print t

     

    展开全文
  • 我主要说的导向滤波其中的引导图选择问题. 百度百科的定义 : 导向图滤波是一种图像滤波技术 ,通过一张引导图G(导向图),对目标图像P(输入图像)进行滤波处理,使得最后的输出图像大体上与目标图像P相似,但是...

    引导图的选择

    我主要说的导向滤波其中的引导图选择问题.

    百度百科的定义 : 导向图滤波是一种图像滤波技术 ,通过一张引导图G(导向图),对目标图像P(输入图像)进行滤波处理,使得最后的输出图像大体上与目标图像P相似,但是纹理部分与引导图G相似。其典型应用有两个:保边图像平滑,抠图。

    注意这句话:纹理部分与引导图G相似,他是引导图的选择标准.可以是rgb中的某一个,也可以是灰度图,也可以是经过处理后的图.他的作用就是保留纹理.反之,如果不想保存呢?那就选没有纹理的.

    作用

    1. 保边图像平滑

    当引导图G与输入图P为同一个图像的时候,导向图滤波的效果与双边滤波的效果类似,但是不同于双边滤波的是,导向图滤波可以很容易设计一个与滤波半径无关的优化算法 [4-5]  。其中窗口半径为平滑半径,参数

    为平滑项参数,其值越大平滑的越明显。

    2. 抠图

    当输入图P为一个初始的mask图像时,导向图滤波的效果类似于抠图算法,其中窗口半径为抠图的半径,参数

    为平滑项。

    下面内容来源于

    https://blog.csdn.net/qq_40755643/article/details/83831071

    导向滤波算法原理

    原理可以看博主:白马负金羁 的文章导向滤波(Guided Filter)的解析与实现,对原理解释十分通俗易懂。

    导向滤波:

    1.实现的伪代码:

    https://blog.csdn.net/qq_40755643/article/details/83831071

    导向图像(Guidance Image) I,滤波输出图像(Filtering Input Image) p,均值平滑窗口半径 r,正则化参数 e。

    利用导向滤波进行图像平滑处理时,通常令p=I。
    2.opencv库代码实现:

    其中:guideFilter()函数调用opencv自带的库函数blur() 进行均值平滑。

    3.结果对比:

    下图采用了r=16也就是winSize=(16,16), eps=0.01的参数大小。


    快速导向滤波

    通过下采样减少像素点,计算mean_a & mean_b后进行上采样恢复到原有的尺寸大小。

    假设缩放比例为s,那么缩小后像素点的个数为N/s^2,那么时间复杂度变为O(N/s^2)

    1.实现的伪代码:

    fmean代表均值平滑,fsubsample代表图像下采样即缩小图像,fupsample代表图片上采样即放大图像,s为缩小系数。

    2.opencv库代码实现:

    这里使用opencv自带库函数resize()进行上下采样

    3.结果对比:

    下图导向滤波采用了r=16也就是winSize=(16,16), eps=0.01的参数大小。  

           快速导向滤波采用了r=16也就是winSize=(16,16), eps=0.01,s=0.5的参数大小。

    代码

    import cv2,math
    import numpy as np
    import pycuda.gpuarray as gpuarray
    import pycuda.cumath as cumath
    import pycuda.autoinit
    
    
    
    
    def guideFilter(I, p, winSize, eps):
        """
        导向图像(Guidance Image) I,滤波输出图像(Filtering Input Image) p,均值平滑窗口半径 r,正则化参数 e。
        利用导向滤波进行图像平滑处理时,通常令p=I。
        其中:guideFilter()函数调用opencv自带的库函数blur() 进行均值平滑。
        :param I:
        :param p:
        :param winSize:
        :param eps:
        :return:
        """
        # I的均值平滑
        mean_I = cv2.blur(I, winSize)
        # p的均值平滑
        mean_p = cv2.blur(p, winSize)
        # I*I和I*p的均值平滑
        mean_II = cv2.blur(I * I, winSize)
        mean_Ip = cv2.blur(I * p, winSize)
        # 方差
        var_I = mean_II - mean_I * mean_I  # 方差公式
        # 协方差
        cov_Ip = mean_Ip - mean_I * mean_p
        a = cov_Ip / (var_I + eps)
        b = mean_p - a * mean_I
        # 对a、b进行均值平滑
        mean_a = cv2.blur(a, winSize)
        mean_b = cv2.blur(b, winSize)
        q = mean_a * I + mean_b
        return q
    
    
    def FastguideFilter(I, p, winSize, eps, s):
        """
        快速导向滤波
        通过下采样减少像素点,计算mean_a & mean_b后进行上采样恢复到原有的尺寸大小。
        假设缩放比例为s,那么缩小后像素点的个数为N/s^2,那么时间复杂度变为O(N/s^2)
        fmean代表均值平滑,fsubsample代表图像下采样即缩小图像,fupsample代表图片上采样即放大图像,s为缩小系数。
        :param I:
        :param p:
        :param winSize:
        :param eps:
        :param s:
        :return:
        """
        # 输入图像的高、宽
        h, w = I.shape[:2]
    
        # 缩小图像
        size = (int(round(w * s)), int(round(h * s)))
    
        small_I = cv2.resize(I, size, interpolation=cv2.INTER_CUBIC)
        small_p = cv2.resize(I, size, interpolation=cv2.INTER_CUBIC)
    
        # 缩小滑动窗口
        X = winSize[0]
        small_winSize = (int(round(X * s)), int(round(X * s)))
    
        # I的均值平滑
        mean_small_I = cv2.blur(small_I, small_winSize)
    
        # p的均值平滑
        mean_small_p = cv2.blur(small_p, small_winSize)
    
        # I*I和I*p的均值平滑
        mean_small_II = cv2.blur(small_I * small_I, small_winSize)
    
        mean_small_Ip = cv2.blur(small_I * small_p, small_winSize)
    
        # 方差
        var_small_I = mean_small_II - mean_small_I * mean_small_I  # 方差公式
    
        # 协方差
        cov_small_Ip = mean_small_Ip - mean_small_I * mean_small_p
    
        small_a = cov_small_Ip / (var_small_I + eps)
        small_b = mean_small_p - small_a * mean_small_I
    
        # 对a、b进行均值平滑
        mean_small_a = cv2.blur(small_a, small_winSize)
        mean_small_b = cv2.blur(small_b, small_winSize)
    
        # 放大
        size1 = (w, h)
        mean_a = cv2.resize(mean_small_a, size1, interpolation=cv2.INTER_LINEAR)
        mean_b = cv2.resize(mean_small_b, size1, interpolation=cv2.INTER_LINEAR)
    
        q = mean_a * I + mean_b
    
        return q
    
    """
    下图导向滤波采用了r=16也就是winSize=(16,16), eps=0.01的参数大小。  
    快速导向滤波采用了r=16也就是winSize=(16,16), eps=0.01,s=0.5的参数大小。
    
    """
    def run():
        image = cv2.imread(r'/home/cheng/Documents/practice_py/cv/face03.png', cv2.IMREAD_ANYCOLOR)
        #将图像归一化
        image_0_1 = image/255.0
    
        #导向滤波(三通道)
        b, g, r = cv2.split(image_0_1)
        # 1.753212477
        # gf1 = guideFilter(b, b, (16,16), math.pow(0.1,2))
        # gf2 = guideFilter(g, g, (16,16), math.pow(0.1,2))
        # gf3 = guideFilter(r, r, (16,16), math.pow(0.1,2))
        # 0.944390349
        gf1 = FastguideFilter(b, b, (16, 16), math.pow(0.1, 2),s=0.5)
        gf2 = FastguideFilter(g, g, (16, 16), math.pow(0.1, 2),s=0.5)
        gf3 = FastguideFilter(r, r, (16, 16), math.pow(0.1, 2),s=0.5)
        gf = cv2.merge([gf1, gf2, gf3])
    
    
        #保存导向滤波结果
        gf = gf*255
        gf[gf>255] = 255
        gf = np.round(gf)
        gf = gf.astype(np.uint8)
        res = np.hstack((image,gf))
        cv2.imshow("res",res)
        cv2.imwrite(r'/home/cheng/Documents/practice_py/cv/resface03.png.jpg', gf)
        cv2.waitKey(0)
    
    
    def gpu_run():
        image = gpuarray.to_gpu(cv2.imread(r'/home/cheng/Documents/practice_py/cv/face03.png', cv2.IMREAD_ANYCOLOR))
        #将图像归一化
        image_0_1 = image/255.0
    
        #导向滤波(三通道)
        b, g, r = image_0_1[:,:,0],image_0_1[:,:,1],image_0_1[:,:,2]
        # 1.753212477
        # gf1 = guideFilter(b, b, (16,16), math.pow(0.1,2))
        # gf2 = guideFilter(g, g, (16,16), math.pow(0.1,2))
        # gf3 = guideFilter(r, r, (16,16), math.pow(0.1,2))
        # 0.944390349
        gf1 = FastguideFilter(b, b, (16, 16), math.pow(0.1, 2),s=0.5)
        gf2 = FastguideFilter(g, g, (16, 16), math.pow(0.1, 2),s=0.5)
        gf3 = FastguideFilter(r, r, (16, 16), math.pow(0.1, 2),s=0.5)
        gf = cv2.merge([gf1, gf2, gf3])
    
    
        #保存导向滤波结果
        gf = gf*255
        gf[gf>255] = 255
        gf = np.round(gf)
        gf = gf.astype(np.uint8)
        res = np.hstack((image,gf))
        cv2.imshow("res",res)
        cv2.imwrite(r'/home/cheng/Documents/practice_py/cv/resface03.png.jpg', gf)
        cv2.waitKey(0)
    
    
    def costtime(func):
        # time start
        t1 = cv2.getTickCount()
        func()
        # time end
        t2 = cv2.getTickCount()
    
        # 计算执行秒数,利用getTickFrequency()获取时钟频率
        t = (t2 - t1) / cv2.getTickFrequency()
        print(t)
    
    
    
    if __name__ == "__main__":
        # costtime(gpu_run)
        costtime(run)
    
    


     

     

    展开全文
  • } } 5.2 快速导向滤波 #include //快速导向滤波 void FastGuidedFilter(cv::Mat& srcImage, cv::Mat& guidedImage, cv::Mat& outputImage, int filterSize, double eps, int samplingRate) { try { if ...
  • 基于导向滤波的work论文,写的非常详细,希望能够帮助到广大科研人员
  • import numpy as np from scipy import signal ...def guideFilter(I, p, winSize, eps, s): #导向滤波 # 输入图像的高、宽 h, w = I.shape[:2] # 缩小图像 size = (int(round(w * s)), int(round(h * s))) s
  • OpenCV—Python 导向滤波

    千次阅读 多人点赞 2018-11-19 15:23:13
    一、导向滤波原理 导向滤波是使用导向图像作为滤波内容图像,在导向图像上实现局部线性函数表达,实现各种不同的线性变换,输出变形之后的导向滤波图像。根据需要,导向图像可以跟输入图像不同或者一致。 公式及...
  • 点击上方“小白学视觉”,选择加"星标"或“置顶”重磅干货,第一时间送达导向滤波介绍导向滤波是使用导向图像作为滤波内容图像,在导向图像上实现局部线性函数表达,实现各种不同的线性变换,输出变形...
  • 1.介绍提到导向滤波,首先想到的是“何恺明”,他的确是真大神,在图像领域,是中国人的骄傲,深度学习流行的时候,也是提出各种新算法,比如ResNets,而最近两年,深度学习的发展已经非常缓慢了,更多都是各种组合...
  • 2. 快速导向滤波算法 通过下采样减少像素点,计算mean_a & mean_b后进行上采样恢复到原有的尺寸大小。 假设缩放比例为s,那么缩小后像素点的个数为N/s2,那么时间复杂度变为O(N/s2) 3. 代码 i...
  • 导向滤波(Guided Filter) 导向滤波(Guided Filter) 1. 前言 2. 导向滤波(Guided Filter)描述 3. 代码实现 4. 参考 1. 前言 导向滤波(Guided Filter)是何恺明2010年发表在ECCV的文章《Guided Image Filtering...
  • 快速引导滤波python-opencv

    千次阅读 2020-11-17 20:42:25
    ,:,2],image_0_1[:,:,2],(17,17),pow(0.2,2.0)) cv2.imshow("guidedFilter",result) #保存导向滤波的结果 result = result*255 result[result>255] = 255 result = np.round(result) result = result.astype(np.uint...
  • 导向滤波 导向图An example like the image below has already been widely shared on the internet, the engineering behind the trick is basically information hierarchy. The ordering of visual elements ...
  • 【OpenCV 例程200篇】61. 导向滤波(Guided filter)

    千次阅读 多人点赞 2021-12-18 09:43:47
    导向滤波又称引导滤波,通过一张引导图片反映边缘、物体等信息,对输入图像进行滤波处理,使输出图像的内容由输入图像决定,但纹理与引导图片相似。 导向滤波的原理是局部线性模型,在保持双边滤波的优势(有效保持...
  • 本文介绍的导向滤波,其与联合双边滤波类似,也需要除原始影像之外另外一副引导图,是一种保边滤波器,当然其也可以用作图像去雾、HDR压缩等。 2. 算法原理 2.1 导向滤波框架 在算法框架中,要对p进行滤波而得到q,...
  • 针对红外和可见光图像融合结果背景信息不足、对比度较低的问题,提出一种结合引导滤波快速共现滤波的融合方法。首先,以高斯滤波将源图像分解为细节层和基础层。然后以去除值域滤波器、全局统计共现信息的方式简化...
  • 本文提出了一种快速有效的图像融合方法,通过对多幅图像进行融合,生成高信息量的融合图像。该方法将图像分解为包含大规模强度变化的基层和捕捉小尺度细节的细节层。提出了一种基于引导滤波的加权平均技术,充分利用...
  • 导向滤波磨皮的对应文献为:Guided Image Filtering,这个算法速度极其之快,比其他的保边缘磨皮算法都快,甚至快上好几倍。这个算法最初来自于何明凯的图像去雾算法中,现在已然被应用封装与matlab图像处理函数库中...
  • 导向图滤波是一种图像滤波...导向滤波是由何凯明等人在2010年发表在ECCV的文章“Guided Image Filtering”文中提到的,后来陆续发表了改进算法快速导向滤波的实现。导向滤波不仅能够实现双边滤波的边缘平滑,而且在...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 932
精华内容 372
关键字:

快速导向滤波

友情链接: tushu.rar