导向滤波小结:从导向滤波(guided filter)到快速导向滤波(fast guide filter)的原理,应用及opencv实现代码

本文为转载,原博客地址:https://blog.csdn.net/fu_shuwu/article/details/78508576

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)的解析与实现一文将其原理解释的非常通俗易懂了,这里就不再赘述。仅给出最后的推导结果,其中为一个窗口半径为的均值滤波器(对应的窗口大小为),corr为相关,var为方差,cov为协方差。


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

GuidedFilter()的代码,比较容易理解:
[objc]  view plain  copy
  1. cv::Mat GuidedFilter(cv::Mat I, cv::Mat p, int r, double eps)  
  2. {  
  3.     /* 
  4.     % GUIDEDFILTER   O(N) time implementation of guided filter. 
  5.     % 
  6.     %   - guidance image: I (should be a gray-scale/single channel image) 
  7.     %   - filtering input image: p (should be a gray-scale/single channel image) 
  8.     %   - local window radius: r 
  9.     %   - regularization parameter: eps 
  10.     */  
  11.   
  12.     cv::Mat _I;  
  13.     I.convertTo(_I, CV_64FC1,1.0/255);  
  14.     I = _I;  
  15.   
  16.     cv::Mat _p;  
  17.     p.convertTo(_p, CV_64FC1,1.0/255);  
  18.     p = _p;  
  19.   
  20.     //[hei, wid] = size(I);    
  21.     int hei = I.rows;  
  22.     int wid = I.cols;  
  23.   
  24.     r=2*r+1;//因为opencv自带的boxFilter()中的Size,比如9x9,我们说半径为4   
  25.   
  26.     //mean_I = boxfilter(I, r) ./ N;    
  27.     cv::Mat mean_I;  
  28.     cv::boxFilter(I, mean_I, CV_64FC1, cv::Size(r, r));  
  29.   
  30.     //mean_p = boxfilter(p, r) ./ N;    
  31.     cv::Mat mean_p;  
  32.     cv::boxFilter(p, mean_p, CV_64FC1, cv::Size(r, r));  
  33.   
  34.     //mean_Ip = boxfilter(I.*p, r) ./ N;    
  35.     cv::Mat mean_Ip;  
  36.     cv::boxFilter(I.mul(p), mean_Ip, CV_64FC1, cv::Size(r, r));  
  37.   
  38.     //cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch.    
  39.     cv::Mat cov_Ip = mean_Ip - mean_I.mul(mean_p);  
  40.   
  41.     //mean_II = boxfilter(I.*I, r) ./ N;    
  42.     cv::Mat mean_II;  
  43.     cv::boxFilter(I.mul(I), mean_II, CV_64FC1, cv::Size(r, r));  
  44.   
  45.     //var_I = mean_II - mean_I .* mean_I;    
  46.     cv::Mat var_I = mean_II - mean_I.mul(mean_I);  
  47.   
  48.     //a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper;       
  49.     cv::Mat a = cov_Ip / (var_I + eps);  
  50.   
  51.     //b = mean_p - a .* mean_I; % Eqn. (6) in the paper;    
  52.     cv::Mat b = mean_p - a.mul(mean_I);  
  53.   
  54.     //mean_a = boxfilter(a, r) ./ N;    
  55.     cv::Mat mean_a;  
  56.     cv::boxFilter(a, mean_a, CV_64FC1, cv::Size(r, r));  
  57.   
  58.     //mean_b = boxfilter(b, r) ./ N;    
  59.     cv::Mat mean_b;  
  60.     cv::boxFilter(b, mean_b, CV_64FC1, cv::Size(r, r));  
  61.   
  62.     //q = mean_a .* I + mean_b; % Eqn. (8) in the paper;    
  63.     cv::Mat q = mean_a.mul(I) + mean_b;  
  64.   
  65.     return q;  
  66. }  

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



4. 快速导向滤波

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

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

基于上面的理论,只需调用resize()函数来实现下采样和上采样,关于resize()函数的使用可以参考 resize()代码如下:
[objc]  view plain  copy
  1. cv::Mat fastGuidedFilter(cv::Mat I_org, cv::Mat p_org, int r, double eps, int s)  
  2. {  
  3.     /* 
  4.     % GUIDEDFILTER   O(N) time implementation of guided filter. 
  5.     % 
  6.     %   - guidance image: I (should be a gray-scale/single channel image) 
  7.     %   - filtering input image: p (should be a gray-scale/single channel image) 
  8.     %   - local window radius: r 
  9.     %   - regularization parameter: eps 
  10.     */  
  11.   
  12.     cv::Mat I,_I;  
  13.     I_org.convertTo(_I, CV_64FC11.0 / 255);  
  14.   
  15.     resize(_I,I,Size(),1.0/s,1.0/s,1);  
  16.   
  17.   
  18.   
  19.     cv::Mat p,_p;  
  20.     p_org.convertTo(_p, CV_64FC11.0 / 255);  
  21.     //p = _p;  
  22.     resize(_p, p, Size(),1.0/s,1.0/s,1);  
  23.   
  24.     //[hei, wid] = size(I);      
  25.     int hei = I.rows;  
  26.     int wid = I.cols;  
  27.   
  28.     r = (22 * r + 1)/s+1;//因为opencv自带的boxFilter()中的Size,比如9x9,我们说半径为4     
  29.   
  30.     //mean_I = boxfilter(I, r) ./ N;      
  31.     cv::Mat mean_I;  
  32.     cv::boxFilter(I, mean_I, CV_64FC1, cv::Size(r, r));  
  33.   
  34.     //mean_p = boxfilter(p, r) ./ N;      
  35.     cv::Mat mean_p;  
  36.     cv::boxFilter(p, mean_p, CV_64FC1, cv::Size(r, r));  
  37.   
  38.     //mean_Ip = boxfilter(I.*p, r) ./ N;      
  39.     cv::Mat mean_Ip;  
  40.     cv::boxFilter(I.mul(p), mean_Ip, CV_64FC1, cv::Size(r, r));  
  41.   
  42.     //cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch.      
  43.     cv::Mat cov_Ip = mean_Ip - mean_I.mul(mean_p);  
  44.   
  45.     //mean_II = boxfilter(I.*I, r) ./ N;      
  46.     cv::Mat mean_II;  
  47.     cv::boxFilter(I.mul(I), mean_II, CV_64FC1, cv::Size(r, r));  
  48.   
  49.     //var_I = mean_II - mean_I .* mean_I;      
  50.     cv::Mat var_I = mean_II - mean_I.mul(mean_I);  
  51.   
  52.     //a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper;         
  53.     cv::Mat a = cov_Ip / (var_I + eps);  
  54.   
  55.     //b = mean_p - a .* mean_I; % Eqn. (6) in the paper;      
  56.     cv::Mat b = mean_p - a.mul(mean_I);  
  57.   
  58.     //mean_a = boxfilter(a, r) ./ N;      
  59.     cv::Mat mean_a;  
  60.     cv::boxFilter(a, mean_a, CV_64FC1, cv::Size(r, r));  
  61.     Mat rmean_a;  
  62.     resize(mean_a, rmean_a, Size(I_org.cols, I_org.rows),1);  
  63.   
  64.     //mean_b = boxfilter(b, r) ./ N;      
  65.     cv::Mat mean_b;  
  66.     cv::boxFilter(b, mean_b, CV_64FC1, cv::Size(r, r));  
  67.     Mat rmean_b;  
  68.     resize(mean_b, rmean_b, Size(I_org.cols, I_org.rows),1);  
  69.       
  70.     //q = mean_a .* I + mean_b; % Eqn. (8) in the paper;      
  71.     cv::Mat q = rmean_a.mul(_I) + rmean_b;  
  72.   
  73.     return q;  
  74. }  

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


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

4. opencv API 调用

[objc]  view plain  copy
  1. #include<opencv.hpp>  
  2. #include<ximgproc.hpp>  
  3.   
  4. int main(void)  
  5. {  
  6.     cv::Mat src = cv::imread("d:/Opencv Picture/bilateral filter.png"1);  
  7.     cv::imshow("src", src);  
  8.     cv::Mat dst(src.size(), src.type());  
  9.     float eps = 0.02 * 2255 * 255;//eps的取值很关键(乘于255的平方)  
  10.     cv::ximgproc::guidedFilter(src,src,dst,16,eps,-1);  
  11.     cv::imshow("dst", dst);  
  12.     cvWaitKey();  
  13.     return 0;  
  14. }  



  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV中的导向滤波是通过cv.ximgproc.guidedFilter函数来实现的。这种算法的关键思想是盒式滤波(box filter),并且必须通过积分图来实现盒式滤波,以保证与窗口大小无关。 为了实现导向滤波算法,可以使用以下参考例程: ```python import cv2 import matplotlib.pyplot as plt img = cv2.imread("../images/imgFabricNoise.png", flags=1) imgGuide = cv2.imread("../images/imgFabric.png", flags=1) imgGuidedFilter = cv2.ximgproc.guidedFilter(imgGuide, img, 10, 2, -1) plt.figure(figsize=(9,6)) plt.subplot(131), plt.axis('off'), plt.title("Original") plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.subplot(133), plt.axis('off'), plt.title("cv2.guidedFilter") plt.imshow(cv2.cvtColor(imgGuidedFilter, cv2.COLOR_BGR2RGB)) plt.tight_layout() plt.show() ``` 这段代码演示了如何使用cv2.ximgproc.guidedFilter函数对图像进行导向滤波处理。首先读取图像和引导图像,然后使用guidedFilter函数对图像进行滤波处理,最后显示原图和滤波结果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【OpenCV 例程200篇】61. 导向滤波Guided filter)](https://blog.csdn.net/youcans/article/details/122008763)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [【拜小白opencv】33-平滑处理6——引导滤波/导向滤波Guided Filter)](https://blog.csdn.net/sinat_36264666/article/details/77990790)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值