双边滤波器的实现
双边滤波器的目的就是保边去噪。主要是在高斯滤波的基础上增加对于像素差的考虑,如果像素差过大则利用高斯函数降低影响,只有相近的像素差才会具有较大的权重,对于中心像素的值有较大影响 。
具体实现函数如下:
其中,权重因子由两部分组成,一部分是定义域(中心像素与领域像素的距离差):
另一部分是值域(中心像素与领域像素的像素差:)
综合起来就是:
即为第一个式子的权重因子。
具体的实现代码如下(用OpenCV实现):
#include
#include
#include
#include
#include
#include
#include
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 color_weight(channel * 256);//记录颜色信息
vector space_weight(d*d);//记录空间信息
vector 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
实验结果: