双边滤波器

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Coco825211943/article/details/75195799

双边滤波器的实现

        双边滤波器的目的就是保边去噪。主要是在高斯滤波的基础上增加对于像素差的考虑,如果像素差过大则利用高斯函数降低影响,只有相近的像素差才会具有较大的权重,对于中心像素的值有较大影响 。

具体实现函数如下:


其中,权重因子由两部分组成,一部分是定义域(中心像素与领域像素的距离差):


另一部分是值域(中心像素与领域像素的像素差:)


综合起来就是:

 即为第一个式子的权重因子。

具体的实现代码如下(用OpenCV实现):


#include<iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv.hpp>
#include<vector>
#include<opencv2/opencv.hpp>

using namespace cv;
using namespace std;

//自定义编写的双边滤波器的全局函数声明 
void bilateral_Filter(InputArray src,OutputArray dst,int d,double sigmaColor,double sigmaSpace,
int borderType );

void _bilateral_Filter(Mat& _src, Mat& _dst, int d, double sigmaColor, double sigmaSpace,
int borderType);

int main()
{
	Mat src = imread("C:\\Users\\l\\Desktop\\2.jpg");
	Mat dst;
	Mat test;
	int d = 15;
	double sigmaColor=50;
	double sigmaSpace=150;//在这里实现参数的定义

	//调用自定义的双边滤波函数 使用默认的borderType
	bilateral_Filter(src,dst,d,sigmaColor,sigmaSpace,BORDER_DEFAULT);
	bilateralFilter(src, test, d, sigmaColor, sigmaSpace, BORDER_DEFAULT);

	namedWindow("原图");
	namedWindow("结果图");
	namedWindow("自带函数结果图");

	imshow("原图",src);
	imshow("结果图", dst);
	imshow("自带函数结果图", test);//opencv中自带函数与自定义函数的结果可以进行对比,实验结果一致
	
	waitKey(0);
	return 0;

}

//参数意义:d为过滤过程中每个像素领域的直径,如果<0,则根据sigmaSpace来确定
//src为源图像,dst是结果图像
//sigmaColor sigmaSpace 分别为正态分布函数中的sigma。一个表示颜色  一个表示空间
void bilateral_Filter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace,
	int borderType)
{
	Mat _src = src.getMat();
	dst.create(_src.size(), _src.type());
	Mat _dst = dst.getMat();//得到图像矩阵 对图像矩阵进行操作

	//将图像矩阵传给_bilateral_Filter()
	_bilateral_Filter(_src, _dst, d, sigmaColor, sigmaSpace,borderType);
}

void _bilateral_Filter(Mat& _src, Mat& _dst, int d, double sigmaColor, double sigmaSpace,
	int borderType)
{
	//具体实现
	int channel = _src.channels();//通道数
	int r;//半径
	int i, j;//i代表行 j代表列

	r = d / 2;
	r = MAX(r, 1);//如果不满一个像素则要填满 所以r的最小值是1
	d = 2 * r + 1;//更改相应的直径

	double sigmaColor_coef = -1 / (sigmaColor*sigmaColor * 2);
	double sigmaSpace_coef = -1 / (sigmaSpace*sigmaSpace * 2);

	Mat temp;//利用临时图像扩充边缘部分 便于统一处理
	copyMakeBorder(_src, temp, r, r, r, r, borderType);

	vector<float> color_weight(channel * 256);//记录颜色信息
	vector<float> space_weight(d*d);//记录空间信息
	vector<int> space_dis(d*d);//记录模板各点与锚点的偏移量
	float* _color_weight = &color_weight[0];//初始化指针指向数组的开始,提高效率
	float* _space_weight = &space_weight[0];
	int* _space_dis = &space_dis[0];

	//初始化颜色信息
	for (int begin = 0; begin < channel*256;begin++)
	{
		_color_weight[begin] = (float)exp(begin*begin*sigmaColor_coef);
	}

	//初始化空间信息 和 偏移量
	int count = 0;
	for (i = -r; i <= r; i++)
	{
		for (j = -r; j <= r; j++)
		{
			double distance2 =sqrt((double)i*i + (double)j*j);
			if (distance2 > r)
				continue;
			_space_weight[count] = (float)exp(distance2*distance2*sigmaSpace_coef);
			//_space_dis[count++] = (int)(i*_src.step + j*channel);
			_space_dis[count++] = (int)(i*temp.step + j*channel);
		}
	}

	Size size = _src.size();

	for (i = 0; i < size.height; i++)//对于每一行来说
	{//初始化指针指向两个矩阵所对应的像素的位置
		uchar* sptr = temp.data + (i + r)*temp.step + r*channel;
		uchar* dptr = _dst.data + i * _dst.step;

		if (channel == 1)//单通道 灰度图
		{
			for (j = 0; j < size.width; j++)
			{
				float sum = 0;//分子
				float wsum = 0;//分母 用来归一化
				int src_pix = sptr[j];
				{
					for (int q = 0; q < count; q++)
					{
						int src_com_pix = sptr[j + space_dis[q]];
						float temp = _space_weight[q] * _color_weight[abs(src_pix - src_com_pix)];
						sum += temp*src_com_pix;
						wsum += temp;
					}
					dptr[j] = (uchar)cvRound(sum / wsum);
				}
			}
		}
		else if (channel == 3)//三通道 BGR
		{
			for (j = 0;j<size.width*3;j+=3)
			{//按照BGR的顺序来
				float sum_b = 0;
				float sum_g = 0;
				float sum_r = 0;
				float wsum = 0;

				int src_pix_b = sptr[j];
				int src_pix_g = sptr[j + 1];
				int src_pix_r = sptr[j + 2];
				
				for (int k = 0; k < count; k++)
				{
					const uchar* p = sptr+j + space_dis[k];
					int b = p[0];
					int g = p[1];
					int r = p[2];

					//计算权值
					float temp = _space_weight[k] * _color_weight[abs(src_pix_b - b) + abs(src_pix_g - g) + abs(src_pix_r - r)];
					sum_b += temp*b;
					sum_g += temp*g;
					sum_r += temp*r;
					wsum += temp;
				}
				dptr[j] = (uchar)cvRound(sum_b / wsum);
				dptr[j+1] = (uchar)cvRound(sum_g / wsum);
				dptr[j+2] = (uchar)cvRound(sum_r / wsum);
			}
		}
	}
}


实验结果:




猜你喜欢

转载自blog.csdn.net/Coco825211943/article/details/75195799