精华内容
下载资源
问答
  • 导向滤波

    2021-03-28 13:19:22
    导向滤波(Guided Fliter)显式地利用 guidance image 计算输出图像,其中 guidance image 可以是输入图像本身或者其他图像。导向滤波比起双边滤波来说在边界附近效果较好;另外,它还具有 O(N) 的线性时间的速度...

    基本原理

    导向滤波(Guided Fliter)显式地利用 guidance image 计算输出图像,其中 guidance image 可以是输入图像本身或者其他图像。导向滤波比起双边滤波来说在边界附近效果较好;另外,它还具有 O(N) 的线性时间的速度优势。细节请查阅论文《Guided Image Filtering》
    在这里插入图片描述

    除了速度优势以外,导向滤波的一个很好的性能就是可以保持梯度,这是bilateral做不到的,因为会有梯度翻转现象。(Preserves edges, but not gradients)。
    在这里插入图片描述

    基本原理如下:
    在这里插入图片描述
    在这里插入图片描述

    其中,p为输入图像,I 为导向图,q 为输出图像。在这里我们认为输出图像可以看成导向图I 的一个局部线性变换,其中k是局部化的窗口的中点,因此属于窗口 ωk 的pixel,都可以用导向图对应的pixel通过(ak,bk)的系数进行变换计算出来。同时,我们认为输入图像 p 是由 q 加上我们不希望的噪声或纹理得到的,因此有p = q + n 。
    接下来就是解出这样的系数,使得p和q的差别尽量小,而且还可以保持局部线性模型。这里利用了带有正则项的 linear ridge regression(岭回归)
    在这里插入图片描述

    求解以上方程得到a和b在局部的值,对于一个要求的pixel可能含在多个window中,因此平均后得到:
    在这里插入图片描述

    最后得到的算法为:
    在这里插入图片描述

    示例演示

    头文件GuidedFilter.h

    #pragma once
    
    #include <opencv2\opencv.hpp>
    
    
    /*
    输入:
    guidedImg  ----引导图像,单通道或者三通道
    inputImg  ----输入待滤波图像,单通道或者三通道
    r      ----滤波窗口半径
    eps     ----截断值eps
    
    输出:
    outputImg  ----引导图滤波后图像
    */
    
    class GuidedFilter
    {
    public:
    	GuidedFilter();
    	~GuidedFilter();
    
    private:
    
    	cv::Mat runGuidedFilter_Gray(cv::Mat I, cv::Mat P, int type, int radius, double eps);
    	cv::Mat runGuidedFilter_Color(cv::Mat I, cv::Mat P, int type, int radius, double eps);
    
    public:
    	cv::Mat myGuidedFilter_GrayGuided(cv::Mat guidedImg, cv::Mat inputImg, int radius, double eps);
    	cv::Mat myGuidedFilter_ColorGuided(cv::Mat guidedImg, cv::Mat inputImg, int radius, double eps);
    
    
    };
    

    源文件GuidedFilter.cpp

    #include "guidedFilter.h"
    #include <iostream>
    #include <string>
    
    using namespace std;
    using namespace cv;
    
    
    GuidedFilter::GuidedFilter()
    {
    }
    
    GuidedFilter::~GuidedFilter()
    {
    }
    
    
    //引导图为灰度图像
    cv::Mat GuidedFilter::runGuidedFilter_Gray(cv::Mat I, cv::Mat P, int type, int radius, double eps)
    {
    	cv::Size winSize(2 * radius + 1, 2 * radius + 1);
    	//求I*I, I*P
    	cv::Mat  I2, IP;
    	multiply(I, I, I2);
    	multiply(I, P, IP);
    	//求均值
    	cv::Mat meanI, meanP, meanI2, meanIP;
    	cv::boxFilter(I, meanI, type, winSize);
    	cv::boxFilter(P, meanP, type, winSize);
    	cv::boxFilter(I2, meanI2, type, winSize);
    	cv::boxFilter(IP, meanIP, type, winSize);
    	//求方差/协方差
    	cv::Mat varI, covIP;
    	varI = meanI2 - meanI.mul(meanI);
    	covIP = meanIP - meanI.mul(meanP);
    	//求系数a, b
    	cv::Mat a, b;
    	varI += eps;
    	cv::divide(covIP, varI, a);
    	b = meanP - a.mul(meanI);
    	//a、b窗口内求平均
    	cv::Mat meanA, meanB;
    	cv::boxFilter(a, meanA, type, winSize);
    	cv::boxFilter(b, meanB, type, winSize);
    	//输出
    	cv::Mat output;
    	output = meanA.mul(I) + meanB;
    	return output;
    }
    
    //引导图I为灰度图像,输入图像P为单通道或者三通道图像
    cv::Mat GuidedFilter::myGuidedFilter_GrayGuided(cv::Mat guidedImg, cv::Mat inputImg, int radius, double eps)
    {
    	CV_Assert(guidedImg.channels() == 1);
    	CV_Assert(inputImg.channels() == 1 || inputImg.channels() == 3);
    	CV_Assert(guidedImg.rows == inputImg.rows && guidedImg.cols == inputImg.cols);
    	int type = CV_64FC1;
    	cv::Mat I, P, output;
    	inputImg.convertTo(P, type);
    	guidedImg.convertTo(I, type);
    
    	//判断输入图像是单通道还是三通道
    	int channel = inputImg.channels();
    	switch (channel)
    	{
    	case 1:
    		output = runGuidedFilter_Gray(I, P, type, radius, eps);
    		break;
    	case 3:
    	{
    		cv::Mat bgr[3], bgrFilter[3];
    		cv::split(P, bgr);
    		for (int chan = 0; chan < channel; chan++)
    		{
    			bgrFilter[chan] = runGuidedFilter_Gray(I, bgr[chan], type, radius, eps);
    		}
    		cv::merge(bgrFilter, channel, output);
    		break;
    	}
    	default:
    		cout << "err! input image channel should be 1 or 3! " << endl;
    		break;
    	}
    
    	return output;
    }
    
    //引导图I为三通道图像
    cv::Mat GuidedFilter::runGuidedFilter_Color(cv::Mat I, cv::Mat P, int type, int radius, double eps)
    {
    	cv::Size winSize(2 * radius + 1, 2 * radius + 1);
    	int channel = I.channels();
    	int H = I.rows;
    	int W = I.cols;
    
    	cv::Mat bgr[3], meanI[3];
    	//引导图各通道的均值
    	split(I, bgr);
    	for (int chan = 0; chan < channel; chan++)
    	{
    		boxFilter(bgr[chan], meanI[chan], type, winSize);
    	}
    	//输入图像均值
    	cv::Mat meanP;
    	boxFilter(P, meanP, type, winSize);
    	//引导图各通道与输入图像相乘并求均值
    	cv::Mat meanIP[3], IP;
    	for (int chan = 0; chan < channel; chan++)
    	{
    		multiply(bgr[chan], P, IP);
    		boxFilter(IP, meanIP[chan], type, winSize);
    	}
    	//引导图各通道与输入图协方差
    	cv::Mat covIP[3], meanImulP;
    	for (int chan = 0; chan < channel; chan++)
    	{
    		multiply(meanI[chan], meanP, meanImulP);
    		covIP[chan] = meanIP[chan] - meanImulP;
    	}
    
    	//求引导图协方差矩阵
    	cv::Mat varI[9], tmp, mean2Tmp, meanTmp2;
    	int varIdx = 0;
    	for (int i = 0; i < channel; i++)
    	{
    		for (int j = 0; j < channel; j++)
    		{
    			multiply(bgr[i], bgr[j], tmp);
    			boxFilter(tmp, meanTmp2, type, winSize);//mean(I*I)
    			multiply(meanI[i], meanI[j], mean2Tmp);//meanI*meanI
    			varI[varIdx] = meanTmp2 - mean2Tmp;
    			varIdx++;
    		}
    	}
    	//求a,三通道
    	cv::Mat a[3];
    	for (int chan = 0; chan < channel; chan++)
    	{
    		a[chan] = cv::Mat::zeros(I.size(), type);
    	}
    	cv::Mat epsEye = cv::Mat::eye(3, 3, type);
    	epsEye *= eps;
    	//公式(19)
    	for (int y = 0; y < H; y++)
    	{
    		double* vData[9];
    		for (int v = 0; v < 9; v++)
    		{
    			vData[v] = (double*)varI[v].ptr<double>(y);
    		}
    		double* cData[3];
    		for (int c = 0; c < 3; c++)
    		{
    			cData[c] = (double *)covIP[c].ptr<double>(y);
    		}
    		double* aData[3];
    		for (int c = 0; c < 3; c++)
    		{
    			aData[c] = (double*)a[c].ptr<double>(y);
    		}
    		for (int x = 0; x < W; x++)
    		{
    			cv::Mat sigma = (cv::Mat_<double>(3, 3) <<
    				vData[0][x], vData[1][x], vData[2][x],
    				vData[3][x], vData[4][x], vData[5][x],
    				vData[6][x], vData[7][x], vData[8][x]
    				);
    			sigma += epsEye;
    			cv::Mat cov_Ip_13 = (cv::Mat_<double>(3, 1) <<
    				cData[0][x], cData[1][x], cData[2][x]);
    			cv::Mat tmpA = sigma.inv()*cov_Ip_13;
    			double* tmpData = tmpA.ptr<double>(0);
    			for (int c = 0; c < 3; c++)
    			{
    				aData[c][x] = tmpData[c];
    			}
    		}
    	}
    
    	//求b
    	cv::Mat b = meanP - a[0].mul(meanI[0]) - a[1].mul(meanI[1]) - a[2].mul(meanI[2]);
    	//b的均值
    	cv::Mat meanB;
    	boxFilter(b, meanB, type, winSize);
    	//a的均值
    	cv::Mat meanA[3];
    	for (int c = 0; c < channel; c++)
    	{
    		boxFilter(a[c], meanA[c], type, winSize);
    	}
    	cv::Mat output = (meanA[0].mul(bgr[0]) + meanA[1].mul(bgr[1]) + meanA[2].mul(bgr[2])) + meanB;
    
    	return output;
    }
    
    //引导图I为三通道图像,输入图像P为单通道或者三通道图像
    cv::Mat GuidedFilter::myGuidedFilter_ColorGuided(cv::Mat guidedImg, cv::Mat inputImg, int radius, double eps)
    {
    	CV_Assert(guidedImg.channels() == 3);
    	CV_Assert(inputImg.channels() == 1 || inputImg.channels() == 3);
    	CV_Assert(guidedImg.cols == inputImg.cols && guidedImg.rows == inputImg.rows);
    	int type = CV_64F;
    	int channel = inputImg.channels();
    	cv::Mat I, P, output;
    	guidedImg.convertTo(I, type);
    	inputImg.convertTo(P, type);
    
    	//判断输入图像是单通道还是三通道
    	switch (channel)
    	{
    	case 1:
    		output = runGuidedFilter_Color(I, P, type, radius, eps);
    		break;
    	case 3:
    	{
    		cv::Mat bgr[3], bgrFilter[3];
    		cv::split(P, bgr);
    		for (int chan = 0; chan < channel; chan++)
    		{
    			bgrFilter[chan] = runGuidedFilter_Color(I, bgr[chan], type, radius, eps);
    		}
    		cv::merge(bgrFilter, channel, output);
    		break;
    	}
    	default:
    		cout << "err! input image channel should be 1 or 3! " << endl;
    		break;
    	}
    
    	output.convertTo(output, CV_8U);
    	return output;
    }
    

    主函数

    #include <opencv2\opencv.hpp>
    #include "guidedFilter.h"
    #include <iostream>
    
    using namespace std;
    using namespace cv;
    
    int main(int argc, char** argv)
    {
        //if (argc != 2)
        //{
        //    cout << "Usage: opencv_test <image path>" << endl;
        //    return -1;
        //}
    
        //char *imgName = argv[1]; 
    	char *imgName = "C:\\Users\\VINNO\\Desktop\\src\\cat.jpg";
        Mat inputImg;
    
        inputImg = imread(imgName, 1);
        if (!inputImg.data)
        {
            cout << "No image data" << endl;
            return -1;
        }
        Mat grayImg , guidedImg;
    	inputImg.copyTo(guidedImg);
    
    	GuidedFilter filter;
    	grayImg = filter.myGuidedFilter_ColorGuided(inputImg, guidedImg, 80, 0.001);
        imwrite("./result.jpg", grayImg);
    	imshow("", grayImg);
    	waitKey(0);
    
        return 0;
    }
    

    参考资料

    [1] K. He, J. Sun, and X. Tang. Guided image filtering. In ECCV, pages 1–14. 2010.
    [2] K. He, J. Sun, and X. Tang. Guided image filtering. TPAMI, 35(6):1397–1409, 2013
    [3] He K, Sun J. Fast Guided Filter[J]. Computer Science, 2015.

    展开全文
  • 1. 导向滤波简介 导向滤波是何凯明在学生时代提出的一个保边滤波(edge-preserving smoothing)算法。何凯明在cv圈应该算是名人了,学生时代关于图像去雾的研究就以第一作者的身份获得Best Paper Award(CVPR 2009)...

    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的均值滤波器(对应的窗口大小为2*r+1),corr为相关,var为方差,cov为协方差。


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

    GuidedFilter()的代码,比较容易理解:
    cv::Mat GuidedFilter(cv::Mat I, cv::Mat p, int r, double eps)
    {
    	/*
    	% 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);  
    	int hei = I.rows;
    	int wid = 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;
    
    	return q;
    }

    需要注意的是,上面的函数只能对单一通道进行处理(如果是多通道,需要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()代码如下:
    cv::Mat fastGuidedFilter(cv::Mat I_org, cv::Mat p_org, 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, 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);    
    	int hei = I.rows;
    	int wid = I.cols;
    
    	r = (2 * 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;
    
    	return q;
    }

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


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

    4. opencv API 调用

    #include<opencv.hpp>
    #include<ximgproc.hpp>
    
    int main(void)
    {
    	cv::Mat src = cv::imread("d:/Opencv Picture/bilateral filter.png", 1);
    	cv::imshow("src", src);
    	cv::Mat dst(src.size(), src.type());
    	float eps = 0.02 * 255 * 255;//eps的取值很关键(乘于255的平方)
    	cv::ximgproc::guidedFilter(src,src,dst,16,eps,-1);
    	cv::imshow("dst", dst);
    	cvWaitKey();
    	return 0;
    }



    展开全文
  • 1.介绍提到导向滤波,首先想到的是“何恺明”,他的确是真大神,在图像领域,是中国人的骄傲,深度学习流行的时候,也是提出各种新算法,比如ResNets,而最近两年,深度学习的发展已经非常缓慢了,更多都是各种组合...

    1.介绍

    提到导向滤波,首先想到的是“何恺明”,他的确是真大神,在图像领域,是中国人的骄傲,深度学习流行的时候,也是提出各种新算法,比如ResNets,而最近两年,深度学习的发展已经非常缓慢了,更多都是各种组合搭配。回归主题,今天的猪脚是导向滤波,我准备从三篇文章来对它进行简要介绍,导向滤波的应用范围很广泛,比如图像去雾、图像抠图和美颜等。

    2.导向滤波

    至于导向滤波的原理推导,我就不介绍了,直接把算法流程图抛出来,清晰明了,见下图:

    以边缘保留为例:

    当输入图片p和导向图I是相同的时候,下面所求协方差,方差是一样的,这样就会出现两种情况

    1)当图片区域比较平滑的时候,方差就很小,a值就趋于0了,这个时候

    ,为平滑

    2)当图片区域为边缘部分或者跳变比较大的地方,方差就很大,a值就趋于1了,这个时候

    ,为保边

    3.快速导向滤波

    普通的导向滤波,因为是处理原始大图,速度还是不够快,在算法界,也是讲究“天下武功唯快不破”,那么我们可不可以小图送进去,大图出来了,答案是肯定的,算法流程见下面,这个算法和上面算法的区别主要在于,这里首先来一个下采样(

    ),后面再来一个上采样(

    )

    4.基于深度学习的导向滤波

    在深度学习算法流行之际,有人就在想,可不可以用神经网络来构建导向滤波呢,当然是可以的,参见论文“Fast End-to-End Trainable Guided Filter”,其实,我发现,现在很多深度学习算法都是模仿传统算法,把以前人工设计部分,直接替换可学习的,这样做的好处是,简单粗暴,鲁棒性又好。整个算法的流程见下,没什么好解释的,有些地方用卷积替换了,整个流程和上面是一样的。

    展开全文
  • 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

     

    展开全文
  • 在图像滤波算法中,导向滤波、双边滤波、最小二乘滤波并称三大保边滤波器,他们是各向异性滤波器。相对于常见的均值滤波、高斯滤波等各向同性滤波器,他们最大的特点是在去除噪声的同时,能最大限度保持边缘不被平滑...
  • 本文介绍的导向滤波,其与联合双边滤波类似,也需要除原始影像之外另外一副引导图,是一种保边滤波器,当然其也可以用作图像去雾、HDR压缩等。2. 算法原理2.1 导向滤波框架在算法框架中,要对p进行滤波而得到q,还得...
  • 我主要说的导向滤波其中的引导图选择问题. 百度百科的定义 : 导向图滤波是一种图像滤波技术 ,通过一张引导图G(导向图),对目标图像P(输入图像)进行滤波处理,使得最后的输出图像大体上与目标图像P相似,但是...
  • 导向滤波(Guided Filter)的解析与实现

    万次阅读 多人点赞 2017-07-10 17:54:31
    导引滤波(Guided Filter)是由Dr. Kaiming He等人提出的一种滤波算法(现在MATLAB的图像处理工具箱中已经内置了实现该...导向滤波的核心是求解一个最小二乘问题,本文将讨论其背后的数学原理并解析其MATLAB实现代码
  • 导向滤波DEMO

    2018-06-22 14:35:34
    针对本人博客保边滤波器集锦文章,给出对应的导向滤波DEMO,算法与代码实现请参看博文。
  • OpenCV—Python 导向滤波

    千次阅读 多人点赞 2018-11-19 15:23:13
    一、导向滤波原理 导向滤波是使用导向图像作为滤波内容图像,在导向图像上实现局部线性函数表达,实现各种不同的线性变换,输出变形之后的导向滤波图像。根据需要,导向图像可以跟输入图像不同或者一致。 公式及...
  • 导向滤波源码

    2015-02-14 00:45:12
    Kaiming He的导向滤波的matlab代码。
  • matlab导向滤波函数

    2016-09-02 15:47:54
    matlab导向滤波,M文件
  • 导向滤波算法

    2014-08-22 15:55:35
    导向滤波算法,是速度比较快的滤波算法,对于图像去雾也有应用
  • 导向滤波学习

    2019-12-03 22:03:31
        今天的数字图像处理课讲到了导向滤波,就拿过来论文学习了一下,下面两篇博客对我帮助很大:  导向滤波算法分析公式推导很详细;  导向滤波详解代码是严格按照论文的算法流程来的,能理解得更清楚。  我...
  • 导向滤波算法实现图像去雾,可以直接运行。。。。。。
  • 基于opencv for unity3d,opencv导向滤波的c#实现方法,方法输入输出Texture2D,注意看方法参数说明中的r和eps参数。
  • 导向滤波matlab代码相关合集,包含增强算法,羽化算法,滤波平滑算法等。导向滤波(Guided Filtering)和双边滤波(BF)、最小二乘滤波(WLS)是三大边缘保持(Edge-perserving)滤波器。当然,引导滤波的功能不仅仅...
  • 导向滤波-何凯明

    热门讨论 2013-10-04 17:26:57
    导向滤波,何凯明的最新成果,主要用于去雾
  • guide filter导向滤波算法的matlab代码,针对guide filter有几种方式的处理效果,对比之后可根据自己的情况选择最优方案。
  • 具体涉及一种基于双通道先验和侧窗导向滤波的单幅图像去雾方法。背景技术:图像采集过程中,由于雾天的影响,使得景物的能见度大幅降低,再加上大气光线的影响,造成获得的图像受到严重的质量退化,对比度大大降低。...
  • 导向滤波算法分析

    2019-01-04 11:38:27
    本文从数学上推导导向滤波的算法,其算法的具体实现在下一篇导向滤波算法的实现介绍。 设引导图G,输入图像P,输出图像Q。导向滤波的目标是使得输入P和输出Q尽可能相同,同时纹理部分和引导图G相似。 为了满足第...
  • 基于导向滤波的work论文,写的非常详细,希望能够帮助到广大科研人员

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 366
精华内容 146
关键字:

导向滤波