精华内容
下载资源
问答
  • 2021-09-23 01:44:40

    平台:Windows 10 20H2
    Visual Studio 2015
    OpenCV 4.5.3


    本文所用源码修改自双边滤波(bilateral filter)以及联合双边滤波(joint bilateral filter)—— flow_specter

    源码

    滤波器

    // 双边滤波
    // @ src 待滤波的影像
    // @ dst 输出的影像
    void BilateralFilter(Mat& src, Mat& dst, int d, double sigmaColor, double sigmaSpace)
    {
    	dst = src.clone();
    	int n_rows = dst.rows;
    	int n_cols = dst.cols;
    	int n_channels = dst.channels();
    	int n_cols_with_channels = n_cols * n_channels;
    	int half_kernel_size = d / 2;
    
    	int index;
    	double pixel_sum;
    	double weight_sum = 0;
    	double temp_bilateral_weight = 0;
    	double color_kernel[256];
    
    	// 颜色域权重确定
    	// @ color_kernel 颜色域核,1D,长度为256
    	for (int i = 0; i < 256; i++)
    	{
    		color_kernel[i] = exp(-1.0 * (i * i) / (2 * sigmaColor * sigmaColor));
    	}
    
    	// 空间域权重确定
    	// @ distance_kernel 空间域核,1D
    	// **************************************************************************************************************
    	double *distance_kernel;
    	distance_kernel = new double[d * d];
    
    	int k = d / 2;
    
    	//二维动态数组申请空间
    	double **distance_kernel_2D = new double*[d];
    	for (int i = 0; i < d; i++)
    		distance_kernel_2D[i] = new double[d];
    
    	double delta_square = 2 * sigmaSpace * sigmaSpace; //分母
    	for (int i = -k; i <= k; i++)
    	{
    		for (int j = -k; j <= k; j++)
    		{
    			double distance_numerator = i * i + j * j;
    			distance_kernel_2D[i + k][j + k] = exp(-1.0 * distance_numerator / delta_square);
    		}
    	}
    	// 将2D kernel 转换为 1D kernel
    	for (int i = 0; i < d; i++)
    	{
    		for (int j = 0; j < d; j++)
    		{
    			distance_kernel[d * i + j] = distance_kernel_2D[i][j];
    		}
    	}
    
    	//释放二维动态数组空间
    	for (int i = 0; i < d; i++)
    		delete[] distance_kernel_2D[i];
    	delete[] distance_kernel_2D;
    	// **************************************************************************************************************
    
    	// 边界不做处理
    	for (int i = half_kernel_size; i < (n_rows - half_kernel_size); i++) 
    	{
    		uchar* pt_dst = dst.ptr<uchar>(i);
    		uchar* pt_src = src.ptr<uchar>(i);
    		for (int j = n_channels * half_kernel_size; j < (n_cols_with_channels - n_channels * half_kernel_size); j++) 
    		{
    			index = 0;
    			pixel_sum = weight_sum = 0;
    
    			// 内层kx,ky循环,空间域内滤波
    			for (int kx = i - half_kernel_size; kx <= i + half_kernel_size; kx++) 
    			{
    				uchar* pt_k_src = src.ptr<uchar>(kx);
    				for (int ky = j - n_channels * half_kernel_size; ky <= (j + n_channels * half_kernel_size); ky += n_channels) 
    				{
    					temp_bilateral_weight = distance_kernel[index++] * color_kernel[(int)abs(pt_src[j] - pt_k_src[ky])];
    					weight_sum += temp_bilateral_weight;
    					pixel_sum += (pt_k_src[ky] * temp_bilateral_weight); // 邻域某像素与中心点的双边权重乘积
    				}
    			}
    
    			pixel_sum /= weight_sum; // 归一化
    			pt_dst[j] = saturate_cast<uchar>(pixel_sum); //加权赋值
    		}
    	}
    	delete[]distance_kernel;
    }
    //————————————————
    //版权声明:本文为CSDN博主「flow_specter」的原创文章,遵循CC 4.0 BY - SA版权协议,转载请附上原文出处链接及本声明。
    //原文链接:https ://blog.csdn.net/flow_specter/article/details/107557303
    

    主函数

    图片路径根据实际情况调整,注意反斜杠是转义字符的开头,故“\”应替换为“\”

    int main(int argc, char * argv[])
    {
    	Mat src = imread("D:\\Work\\OpenCV\\Workplace\\Test_1\\face.jpg");
    	Mat dst;
    
    	BilateralFilter(src, dst, 23, 35, 10);
    
    	imshow("原图", src);
    	imshow("输出", dst);
    
    	waitKey(0);
    
    	return 0;
    }
    

    效果

    在这里插入图片描述

    完整源码

    #include <opencv2\opencv.hpp>
    #include <iostream>
    
    using namespace cv;
    using namespace std;
    
    // 双边滤波
    // @ src 待滤波的影像
    // @ dst 输出的影像
    void BilateralFilter(Mat& src, Mat& dst, int d, double sigmaColor, double sigmaSpace)
    {
    	dst = src.clone();
    	int n_rows = dst.rows;
    	int n_cols = dst.cols;
    	int n_channels = dst.channels();
    	int n_cols_with_channels = n_cols * n_channels;
    	int half_kernel_size = d / 2;
    
    	int index;
    	double pixel_sum;
    	double weight_sum = 0;
    	double temp_bilateral_weight = 0;
    	double color_kernel[256];
    
    	// 颜色域权重确定
    	// @ color_kernel 颜色域核,1D,长度为256
    	for (int i = 0; i < 256; i++)
    	{
    		color_kernel[i] = exp(-1.0 * (i * i) / (2 * sigmaColor * sigmaColor));
    	}
    
    	// 空间域权重确定
    	// @ distance_kernel 空间域核,1D
    	// **************************************************************************************************************
    	double *distance_kernel;
    	distance_kernel = new double[d * d];
    
    	int k = d / 2;
    
    	//二维动态数组申请空间
    	double **distance_kernel_2D = new double*[d];
    	for (int i = 0; i < d; i++)
    		distance_kernel_2D[i] = new double[d];
    
    	double delta_square = 2 * sigmaSpace * sigmaSpace; //分母
    	for (int i = -k; i <= k; i++)
    	{
    		for (int j = -k; j <= k; j++)
    		{
    			double distance_numerator = i * i + j * j;
    			distance_kernel_2D[i + k][j + k] = exp(-1.0 * distance_numerator / delta_square);
    		}
    	}
    	// 将2D kernel 转换为 1D kernel
    	for (int i = 0; i < d; i++)
    	{
    		for (int j = 0; j < d; j++)
    		{
    			distance_kernel[d * i + j] = distance_kernel_2D[i][j];
    		}
    	}
    
    	//释放二维动态数组空间
    	for (int i = 0; i < d; i++)
    		delete[] distance_kernel_2D[i];
    	delete[] distance_kernel_2D;
    	// **************************************************************************************************************
    
    	// 边界不做处理
    	for (int i = half_kernel_size; i < (n_rows - half_kernel_size); i++) 
    	{
    		uchar* pt_dst = dst.ptr<uchar>(i);
    		uchar* pt_src = src.ptr<uchar>(i);
    		for (int j = n_channels * half_kernel_size; j < (n_cols_with_channels - n_channels * half_kernel_size); j++) 
    		{
    			index = 0;
    			pixel_sum = weight_sum = 0;
    
    			// 内层kx,ky循环,空间域内滤波
    			for (int kx = i - half_kernel_size; kx <= i + half_kernel_size; kx++) 
    			{
    				uchar* pt_k_src = src.ptr<uchar>(kx);
    				for (int ky = j - n_channels * half_kernel_size; ky <= (j + n_channels * half_kernel_size); ky += n_channels) 
    				{
    					temp_bilateral_weight = distance_kernel[index++] * color_kernel[(int)abs(pt_src[j] - pt_k_src[ky])];
    					weight_sum += temp_bilateral_weight;
    					pixel_sum += (pt_k_src[ky] * temp_bilateral_weight); // 邻域某像素与中心点的双边权重乘积
    				}
    			}
    
    			pixel_sum /= weight_sum; // 归一化
    			pt_dst[j] = saturate_cast<uchar>(pixel_sum); //加权赋值
    		}
    	}
    	delete[]distance_kernel;
    }
    //————————————————
    //版权声明:本文为CSDN博主「flow_specter」的原创文章,遵循CC 4.0 BY - SA版权协议,转载请附上原文出处链接及本声明。
    //原文链接:https ://blog.csdn.net/flow_specter/article/details/107557303
    
    int main(int argc, char * argv[])
    {
    	Mat src = imread("D:\\Work\\OpenCV\\Workplace\\Test_1\\face.jpg");
    	Mat dst;
    
    	BilateralFilter(src, dst, 23, 35, 10);
    
    	imshow("原图", src);
    	imshow("输出", dst);
    
    	waitKey(0);
    
    	return 0;
    }
    
    更多相关内容
  • 双边滤波算法

    2018-07-25 16:46:08
    基于vs2010的图像处理,双边滤波算法,对图像去噪,平滑处理
  • 基于FPGA的双边滤波算法.pdf
  • 点云双边滤波算法

    2019-06-12 11:08:38
    双边滤波算法应用于点云噪点滤除,可有效提高点云质量。高质量的输入数据对提高点云学习的人工智能训练效率与质量有显著的帮助。
  • 针对现有双边滤波算法参数设定复杂、不具通用性等问题,提出一种基于参数估计的双边滤波算法。该算法从计算图像噪声水平和边缘强度出发,在弱纹理区域采用PCA对图像的噪声水平进行估计;利用Sobel算子检测出图像的有效...
  • 利用双边滤波算法对深度图像进行处理可以得到修复图像。
  • 图像双边滤波算法,含算法原理和运行demo,实验效果不错
  • 利用双边滤波算法对深度图像进行处理可以得到修复图像。
  • 双边滤波算法,双边滤波算法原理,matlab源码.zip
  • 然后,对图像中的每个像素点进行双边滤波,其中,灰度标准差设为该点噪声标准差的2倍;最后,根据区域相似度模型判定强噪声,并利用中值滤波器去除。实验证明,所提算法在不同强度的噪声下均可取得较好的保边滤波效果和强...
  • matlab函数实现图片的双边滤波算法
  • 双边滤波算法原理及代码介绍 微信公众号:幼儿园的学霸 目录 文章目录双边滤波算法原理及代码介绍目录介绍原理算法过程过程描述σ的意义及选取OpenCV 代码分析参考资料 A bilateral filter is a non-linear, edge...

    双边滤波算法原理及代码介绍

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

    目录

    A bilateral filter is a non-linear, edge-preserving, and noise-reducing smoothing filter for images. It replaces the intensity of each pixel with a weighted average of intensity values from nearby pixels. This weight can be based on a Gaussian distribution. Crucially, the weights depend not only on Euclidean distance of pixels, but also on the radiometric differences (e.g., range differences, such as color intensity, depth distance, etc.). This preserves sharp edges.

    介绍

    双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑了像素空间差异与强度差异,达到保边去噪的目的。 均值滤波、中值滤波和高斯滤波,都属于各向同性滤波,它们对待噪声和图像的边缘信息都采取一视同仁的处理方式,结果,噪声被磨平的同时,图像中具有重要地位的边缘、纹理和细节也同时被抹平了,这是我们所不希望看到的。

    和其他滤波原理一样,双边滤波也是采用加权平均的方法,用周边像素亮度值的加权平均代表某个像素的强度,所用的加权平均基于高斯分布。最重要的是,双边滤波的权重不仅考虑了像素的欧氏距离(如普通的高斯低通滤波,只考虑了位置对中心像素的影响),还考虑了像素范围域中的辐射差异(例如卷积核中像素与中心像素之间相似程度、颜色强度,深度距离等),在计算中心像素的时候同时考虑这两个权重。

    原理

    双边滤波中(i,j)位置的像素值g(i,j)依赖于邻域内像素值f与其权重w的加权组合(k,l表示邻域像素位置):

    g ( i , j ) = ∑ k , l f ( k , l ) w ( i , j , k , l ) ∑ k , l w ( i , j , k , l ) g(i,j)=\frac{\sum_{k,l}f(k,l)w(i,j,k,l)}{\sum_{k,l}w(i,j,k,l)} g(i,j)=k,lw(i,j,k,l)k,lf(k,l)w(i,j,k,l)
    权重系数w(i,j,k,l)取决于空间域核d与值域核r的乘积:

    空间域核d,表示邻域内某点(k,l)与中心点(i,j)的欧式距离:
    d ( i , j , k , l ) = e x p ( − ( i − k ) 2 + ( j − l ) 2 2 σ d 2 ) , d(i,j,k,l)=exp(-\frac{(i-k)^2+(j-l)^2}{2\sigma_d^2}), d(i,j,k,l)=exp(2σd2(ik)2+(jl)2),

    这就是高斯滤波核

    值域核r,表示邻域内某点(k,l)的灰度值f(k,l)与中心点(i,j)灰度值f(i,j)的差的绝对值:

    可以看到值域核用来表征邻域内像素的相似程度(接近程度)

    r ( i , j , k , l ) = e x p ( − ∣ ∣ f ( i , j ) − f ( k , l ) ∣ ∣ 2 2 σ r 2 ) , r(i,j,k,l)=exp(-\frac{||f(i,j)-f(k,l)||^2}{2\sigma_r^2}), r(i,j,k,l)=exp(2σr2f(i,j)f(k,l)2),
    权重系数为空间域核和值域核的乘积:
    w ( i , j , k , l ) = d ( i , j , k , l ) ∗ r ( i , j , k , l ) = e x p ( − ( i − k ) 2 + ( j − l ) 2 2 σ d 2 − ∣ ∣ f ( i , j ) − f ( k , l ) ∣ ∣ 2 2 σ r 2 ) w(i,j,k,l)=d(i,j,k,l)*r(i,j,k,l) = \\ exp(-\frac{(i-k)^2+(j-l)^2}{2\sigma_d^2}-\frac{||f(i,j)-f(k,l)||^2}{2\sigma_r^2}) w(i,j,k,l)=d(i,j,k,l)r(i,j,k,l)=exp(2σd2(ik)2+(jl)22σr2f(i,j)f(k,l)2)

    对于高斯滤波,仅用空间距离的权值系数核与图像卷积后,确定中心点的灰度值,即认为离中心点越近的点,其权重系数越大。双边滤波中加入了对灰度信息的权重,即在邻域内,灰度值越接近中心点灰度值的点的权重更大,灰度值相差大的点权重越小。所以掩膜最终权重大小,则由空间域高斯核函数和值域高斯核函数共同确定。

    双边滤波器中的一边即为上述的高斯平滑滤波,两个像素物理距离越大则权值越小,反之则权值越大;双边滤波器中另一边由像素值值域决定,两个像素,灰度值相差越小,越不可能是边缘,那么越应该对其进行平滑处理,也就是应该提高其在滤波器中的权值,反之,像素值相差越大则越有可能是边缘,则应该尽力保留。

    双边滤波的过程如下图,在突变的边缘上,使用了像素差权重,所以很好的保留了边缘。
    双边滤波描述
    可以看到,输入是一张黑白对分,且有很多起伏噪点的图像。将箭头所指的该点作为中心点,考虑其他像素点对它的影响权重。空间上的权重分布图Gs以及值域上的权重分布图Gr分别计算得出,将两者乘在一起就得到了Bilateral的权重(注意,目前得出的仅仅是针对当前像素点的,其他像素点对其的影响权重)。所有点都用这样的方式计算以后,我们可以看到最终的输出有不错的保边效果。

    算法过程

    过程描述

    以下面一幅图像为例,
    图像,滑动窗口,核
    其可以看作是10×10的一张图像,图中的数字表示每个点的像素值。在图中存在一个5×5大小的滑动窗口,我们需要求出中心点灰度值146的新像素值。
    0. 边缘复制/边界填充(不多说)

    1. 首先遍历整个窗口,第一个遍历到的点是165,那么中心点与该点的空间域计算结果为:
      在这里插入图片描述

    2. 再计算中心点与该点的像素域结果:
      在这里插入图片描述
      σs=5σr=20时,Gσs = 0.8521,Gσr = 0.6368

    3. 接着遍历整个窗口,将窗口内每个像素点都与中心点建立联系,求出它们的GσsGσr的值,将GσsGσr 相乘即得到每个点对应的权重Wp,即Wp = Gσs × Gσr
      在遍历结束后,用每个点的Wp乘上该点的像素值I(i,j),并求和,这是作为分子。将每个点的Wp相加,作为分母,两者相除,即得到需要的新输出图像的中心点(i,j)的像素值。

    σ的意义及选取

    空间域sigma(space)选取:
    和高斯滤波一样,sigma(space)越大,图像越平滑,趋于无穷大时,每个权重都一样,类似均值滤波。
    sigma(space)越小,中心点权重越大,周围点权重越小,对图像的滤波作用越小,趋于零时,输出等同于原图。

    值域sigma(color)选取:
    Sigma(color)越大,边缘越模糊,极限情况为simga无穷大,值域系数近似相等(忽略常数时,将近为exp(0)= 1),与高斯模板(空间域模板)相乘后可认为等效于高斯滤波。
    Sigma(color)越小,边缘越清晰,极限情况为simga无限接近0,值域系数除了中心位置,其他近似为0(接近exp(-∞) =0),与高斯模板(空间域模板)相乘进行滤波的结果等效于源图像。

    OpenCV 代码分析

    OpenCV中双边滤波的源码路径在/opencv/modules/imgproc/src/bilateral_filter.dispatch.cpp中,其声明如下:

    CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d,
                                       double sigmaColor, double sigmaSpace,
                                       int borderType = BORDER_DEFAULT );
    
    //第一个参数,InputArray类型的src,输入图像,即源图像,需要为8位或者浮点型单通道、三通道的图像。
    //第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
    //第三个参数,int类型的d,表示在过滤过程中每个像素邻域的直径。如果这个值我们设其为非正数,那么OpenCV会从第五个参数sigmaSpace来计算出它来。
    //第四个参数,double类型的sigmaColor,颜色空间滤波器的sigma值。这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
    //第五个参数,double类型的sigmaSpace坐标空间中滤波器的sigma值,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。
    //第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
    

    OpenCV中该算法的实现过程中采用了优化,(1)使用查表的方式计算权重系数;(2)将二维的模板转换为一维,降低算法复杂度;(3)指令集优化及并行优化;

    关于代码的一点解释可以看参考资料[5]中查看.

    参考资料

    1.Bilateral Filtering for Gray and Color Images, C. Tomasi, R. Manduch
    2.双边滤波器原理及实现
    3.双边滤波
    4.【计算摄影学】双边滤波通俗理解以及简单实现

    5.OpenCV 双边滤波器代码实现



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

    展开全文
  • 一、双边滤波算法(Bilateral Filter) 1、原理 高斯滤波是以距离为权重,设计滤波模板作为滤波系数,只考虑了像素间的空间位置上的关系,因此滤波的结果会丢失边缘的信息。 高斯滤波的缺陷如下图所示:平坦区域正常...

    一、双边滤波算法(Bilateral Filter)

    1、原理

    高斯滤波是以距离为权重,设计滤波模板作为滤波系数,只考虑了像素间的空间位置上的关系,因此滤波的结果会丢失边缘的信息。
    高斯滤波的缺陷如下图所示:平坦区域正常滤波,图像细节没有变化,而在突变的边缘上,因为只使用了距离来确定滤波权重,导致边缘被模糊。
    在这里插入图片描述
    在高斯基础上,进一步优化,叠加了像素值的考虑,因此也就引出了双边滤波,一种非线性滤波,滤波效果对保留边缘更有效。
    在这里插入图片描述
    空间距离:当前点距离滤波模板中心点的欧式距离。
    灰度距离:当前点距离滤波模板中心点的灰度的差值的绝对值。
    双边滤波的核函数是空间域核与像素范围域核的综合结果:
    1)在图像的平坦区域,像素值变化很小,那么像素差值接近于0,对应的像素范围域权重接近于1,此时空间域权重起主要作用,相当于进行高斯模糊;
    2)在图像的边缘区域,像素值变化很大,那么像素差值大,对应的像素范围域权重变大,即使距离远空间域权重小,加上像素域权重总的系数也较大,从而保护了边缘的信息。
    双边滤波的效果如下图,在突变的边缘上,使用了像素差权重,所以很好的保留了边缘。
    在这里插入图片描述
    在这里插入图片描述

    2、opence-python 实现

    import cv2
    import numpy as np
    
    image = cv2.imread('./image/cat.jpeg')
    image_blur = cv2.blur(image, (3, 3))
    image_bilater = np.hstack([  # 结果图像的水平拼接
        image_blur,
        cv2.bilateralFilter(image_blur, 5, 21, 21),
        cv2.bilateralFilter(image_blur, 7, 31, 31),
        cv2.bilateralFilter(image_blur, 9, 41, 41)
    ])
    cv2.imshow('image_bilater', image_bilater)
    cv2.waitKey(0)
    

    在这里插入图片描述

    二、导向滤波算法(Guided Filter)

    1、原理

    引导滤波的思想用一张引导图像产生权重,从而对输入图像进行处理,这个过程可以表示为下面公式:
    在这里插入图片描述
    公式中 q、I、p分表表示输出图像、引导图像和输入图像 ,i、j分别表示图像中像素点的索引。可以看到上方公式中权重 W 仅与引导图像 I 有关,而在双边滤波中权重 W 由输入图像自身决定。
    在这里插入图片描述
    在这里插入图片描述

    2、python实现

    """
        uv通道滤波,取出颜色噪声
    """
    import cv2
    import numpy as np
    
    image_path = './image/wait_uv_filter.png'
    image = cv2.imread(image_path)
    cv2.namedWindow('image', 0)
    cv2.resizeWindow('image', 600, 500)
    cv2.imshow('image', image)
    cv2.waitKey(0)
    
    def my_guidedFilter_oneChannel(srcImg, guidedImg, rad=9, eps=0.01):
        srcImg = srcImg / 255.0
        guidedImg = guidedImg / 255.0
    
        P_mean = cv2.boxFilter(srcImg, -1, (rad, rad), normalize=True)
        I_mean = cv2.boxFilter(guidedImg, -1, (rad, rad), normalize=True)
    
        I_square_mean = cv2.boxFilter(np.multiply(guidedImg, guidedImg), -1, (rad, rad), normalize=True)
        I_mul_P_mean = cv2.boxFilter(np.multiply(srcImg, guidedImg), -1, (rad, rad), normalize=True)
    
        var_I = I_square_mean - np.multiply(I_mean, I_mean)
        cov_I_P = I_mul_P_mean - np.multiply(I_mean, P_mean)
    
        a = cov_I_P / (var_I + eps)
        b = P_mean - np.multiply(a, I_mean)
    
        a_mean = cv2.boxFilter(a, -1, (rad, rad), normalize=True)
        b_mean = cv2.boxFilter(b, -1, (rad, rad), normalize=True)
    
        dstImg = np.multiply(a_mean, guidedImg) + b_mean
    
        return dstImg * 255.0
    
    
    def my_guidedFilter_threeChannel(srcImg, guidedImg, rad=9, eps=0.01):
        img_shape = np.shape(srcImg)
        dstImg = np.zeros(img_shape, dtype=float)
        for ind in range(0, img_shape[2]):
            dstImg[:, :, ind] = my_guidedFilter_oneChannel(srcImg[:, :, ind],guidedImg[:, :, ind], rad, eps)
        dstImg = dstImg.astype(np.uint8)
        return dstImg
    
    
    def main():
        img = cv2.imread(input_fn)
        print(np.shape(img))
    
        img_y = cv2.split(img)[0]
        img_u = cv2.split(img)[1]
        img_v = cv2.split(img)[2]
    
        image_guidedFilter = my_guidedFilter_threeChannel(img, img, 15, 0.0001)
        print(np.shape(image_guidedFilter))
        cv2.namedWindow('image_guidedFilter', 0)
        cv2.resizeWindow('image_guidedFilter', 600, 500)
        cv2.imshow('image_guidedFilter', image_guidedFilter)
        cv2.waitKey(0)
    
        dst_u = my_guidedFilter_oneChannel(img_u, img_u, 9, 0.0001).astype(np.uint8)
        dst_v = my_guidedFilter_oneChannel(img_v, img_v, 9, 0.0001).astype(np.uint8)
        dstimg_uv = cv2.merge([img_y, dst_u, dst_v])
        cv2.namedWindow('dstimg_uv', 0)
        cv2.resizeWindow('dstimg_uv', 600, 500)
        cv2.imshow('dstimg_uv', dstimg_uv)
        cv2.waitKey(0)
    
    
    if __name__ == '__main__':
        main()
    
    
    展开全文
  • 双边滤波(Bilateral Filters)是非常常用的一种滤波,它可以达到保持边缘、降噪平滑的效果。和其他滤波原理一样,双边滤波也是采用加权平均的方法,用周边像素亮度值的加权平均代表某个像素的强度,所用的加权平均...

    摘要:
    双边滤波(Bilateral Filters)是非常常用的一种滤波,它可以达到保持边缘、降噪平滑的效果。和其他滤波原理一样,双边滤波也是采用加权平均的方法,用周边像素亮度值的加权平均代表某个像素的强度,所用的加权平均基于高斯分布。最重要的是,双边滤波的权重不仅考虑了像素的欧氏距离(如普通的高斯低通滤波,只考虑了位置对中心像素的影响),还考虑了像素范围域中的辐射差异(例如卷积核中像素与中心像素之间相似程度、颜色强度,深度距离等)。

    一:如何判断边缘?
    在开始之前,我们先讨论一下如何判断边缘。一般而言,区分图像是否为边缘部分的方法如下:
    1:在图像的边缘部分,像素值的变化较为剧烈。
    2:在图像的非边缘区域,像素值的变换较为平坦。
    通过以上两点,我们可以总结出,想要保留图像边缘,必须引入一个能够衡量图像像素变换剧烈程度的变量。

    二:双边滤波算法原理
    霍金曾经说过,如果一本书里面有一个公式,那么这本书的销量将会失去上万个读者。本文将出现好几个公式,按这样会有失去许多个读者,但是不出现公式是不可能的,作者将尽力解释公式的含义,希望看官看过后觉得有用就点一个订阅。话不多说,咱们开门见山。
    首先看双边滤波的公式:
    在这里插入图片描述
    其中:在这里插入图片描述
    先看到这两个公式不要慌,慢慢听我说公式中的符号是什么意思。我们先做一些准备。在这里插入图片描述
    我们选择一个的框,随便放在一张图中。像我这样选择一个5×5的框放在10像素×10像素的图上面。分别沿水平方向和竖直向下方向建立坐标轴,水平的叫X轴,竖直向下的叫Y轴。图中一个一个小方框代表一个像素值,这些像素值都有了一个坐标。咱们举一个例子:在这个5×5的框中,像素为165的这个点坐标为(0,0),像素为156的这个点的坐标为(1,0),像素为56的这个点坐标为(0,1),像素为0的这个点的坐标为(1,1),诸如此类。
    好了,现在我们做了一些准备工作,接下来解释符号含义就方便了许多。q是输入的像素点,它代表上图中5×5的方框中其中的一个像素点。我们先不管累加符号∑和q∈S这个符号,接下来需要一点数学基础, G σ s Gσ_s Gσs是为空间域核, G σ r Gσ_r Gσr是图像像素域核。
    这是两个二维高斯函数,二维高斯函数的公式为(我在网上找的一张图,带了水印,不过无关紧要):在这里插入图片描述
    不过这里我们对二维高斯函数进行了一些小的改动,让他们更加符合我们的要求,这里给出 G σ s Gσ_s Gσs G σ r Gσ_r Gσr的公式,:
    其中:
    在这里插入图片描述
    在这里插入图片描述
    q代表输入像素点,m与n是输入像素的横坐标与纵坐标,p是方框中心像素点,i与j是方框中心像素的坐标,I(m,n)代表输入像素的值,I(i,j)代表方框中心像素的值, σ s σ_s σs σ r σ_r σr是我们自己设定的值。比如:q代表输入像素,在我们的方框中,我们选择像素值为156的点为输入像素,那么它的坐标为(1,0),m=1,n=0,I(1,0)=156。方框中心的点的坐标为(2,2),那么i=2,j=2,I(2,2)=146。
    在这里插入图片描述ps:这个图片太大了,等我学会插入公式后再来修改一下) 代表输出的像素值,也就是我们在方框中心点要更新的像素值。我们现在举一个例子来说明。
    ①首先遍历整个5×5的小框,第一个遍历到的点是165,它的坐标是(0,0),像素值是165,
    那么中心点与该点的空间域计算结果为:
    在这里插入图片描述

    ②再计算中心点与该点的像素域结果:
    在这里插入图片描述
    σ s σ_s σs σ r σ_r σr 分别为5和20时,Gσs = 0.8521,Gσr = 0.6368。
    ③我们将 σ s σ_s σs σ r σ_r σr 和第一个像素值(ps:第一个像素值是165)相乘,这三个数相乘得到第一个结果。还记得累加符号∑和q∈S符号吗?其中S指的就是5×5的这个框,它的意思就是从第一个像素开始遍历,按照①②的步骤,求得每一个在5×5方框中的像素的空间域和像素域的结果,并且将像素值和空间域计算结果和像素域结果相乘,最后将这些结果相加起来,得到滤波算法公式的分子。
    在这里插入图片描述

    好了,我们解释完双边滤波算法的分子,接着解释分母。
    当我们遍历整个5x5的方框,将方框内每个像素点都与中心点建立联系,求出它们的 Gσs 与 Gσr 的值,将 Gσs 与 Gσr 相乘即得到每个点对应的Wp,即Wp = Gσs × Gσr,将方框中25个像素点对应Wp进行累加,得到一个总的Wp,便是分母,我们在计算分子的时候可以顺便算出分母。我们再来捋一遍,在遍历结束后,用每个点的Wp乘上该点的像素值I(m, n),并求和,作为分子。将每个点的Wp相加,作为分母,两者相除,即得到需要的新输出图像的中心点(i,j)的像素值。也就是我们的滤波输出,我们将小框从左往右,从上往下不断移动,按照我们的算法不断更新方框中心的像素值,就得到了双边算法的输出。
    好了,我讲完了,你听懂了吗?有问题可以留言,我会积极回答的。

    展开全文
  • 双边滤波是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空间与信息和灰度相似性,达到保边去噪的目的,具有简单、非迭代、局部处理的特点。之所以能够达到保边去噪的滤波...
  • 基于FPGA的静脉图像双边滤波算法.pdf
  • 由于共焦针孔的加入及现有太赫兹激光器输出不稳定,太赫兹共焦扫描显微成像所得图像的质量不高,将双边滤波算法应用于透射式太赫兹共焦扫描显微成像图像去噪复原,通过研究确定了适合于该情况的双边滤波参数,并且与...
  • 双边滤波原理以及双边滤波算法的实现 双边滤波(Bilateral Filter)原理 双边滤波与高斯滤波器相比,对于图像的边缘信息能过更好的保存。其原理为一个与空间距离相关的高斯函数与一个灰度距离相关的高斯函数相乘。...
  • 基于CBF交叉双边滤波算法的图像融合的MATLAB仿真
  • 递归双边滤波算法源码/DEMO,经典保留边缘滤波器。。。。。
  • 一种改进的双边滤波算法.doc
  • 针对目前滤波算法存在的亮度敏感性不足,提出基于亮度不变特征的自适应双边滤波算法。算法首先利用局部相位的最大矩和最小矩来建立空间参数的角点和边缘信息表示,接着采用灰度均一性测度来建立亮度距离参数与图像...
  • 资源包含联合双边滤波算法的matlab版代码 资源包含联合双边滤波算法的matlab版代码
  • 针对该问题提出一种基于交叉积分直方图的对偶双边滤波算法。该算法通过所构造的交叉积分直方图能够在常数时间里计算出滤波器的系数,并且算法的复杂度不受滤波半径的影响,因此有效提高了原始对偶双边滤波器的适用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,766
精华内容 1,906
关键字:

双边滤波算法

友情链接: #MHI.zip