OpenCV学习----深入理解双边滤波器实现

前沿

和高斯滤波器相似,双边滤波器也是需要先求出系数,然后在图像上移动掩模,处理图像。
第一步:求权重系数
第二步:确定掩模大小
第三部:移动处理整个图像

双边滤波器

前面介绍的高斯滤波器仅仅是考虑空间种像素点的距离关系,并没有考虑到像素值之间的相似程度。(比如说:黑色的头发与蓝天边缘之间没有相似度)这样导致的图像就是一团模糊,双边滤波器(Bilateral Filter)在高斯滤波器基础上增加了图像像素之间的相似程度的考虑。因而,能很好地保持图像的边缘信息。

双边滤波系数

双边滤波器的系数取决于两部分:

域核


其中:i-k 是在 x 轴的间距,j-l 是在 y  轴的间距。

值域核


其中:|| f(i , j) - f(k,l) || 是像素点差值的绝对值。

双边滤波器的系数取决于两部分的成积。

双边滤波系数算法实现

这个和求高斯滤波器的系数相似,最后转化为一维矩阵方便后边处理。
void GetDistanceWeight(double* kerd) //域核
{
	int k = n/2;
	double nkerd[n][n];
	for(int i=-k; i<=k; i++)
	{
		for(int j=-k;j<=k;j++)
			nkerd[i+k][i+k] = exp(-1.0*(i*i+j*j)/(2*sigmad*sigmad));


	}
	for(int i=0;i<n;i++)  //二维矩阵转化为一维矩阵
	{
		for(int j=0;j<n;j++)
			kerd[n*i+j] = nkerd[i][j];
	}
}
值域核算法实现
像素值之间的差值在0-255之间,建立 值域核系数表格,后边直接查表格。
void GetSimilarityWwight(double* kers)//值核
{
	for(int i=0; i<256; i++)
	{
		kers[i] =exp(-1.0*(i*i)/(2*sigmar*sigmar)); //出现“exp”重载函数不明确,则添加  -1.0*.....
	}
}

双边滤波器完整代码

#include "opencv2/opencv.hpp"  
#include"opencv2/highgui/highgui.hpp"
#include <iostream>
#include <math.h>

using namespace cv;
using namespace std;

#define n       5
#define sigmad  30
#define sigmar  20

void GetDistanceWeight(double* kerd) //域核
{
	int k = n/2;
	double nkerd[n][n];
	for(int i=-k; i<=k; i++)
	{
		for(int j=-k;j<=k;j++)
			nkerd[i+k][i+k] = exp(-1.0*(i*i+j*j)/(2*sigmad*sigmad));
	}
	for(int i=0;i<n;i++)  //二维矩阵转化为一维矩阵
	{
		for(int j=0;j<n;j++)
			kerd[n*i+j] = nkerd[i][j];
	}
}
void GetSimilarityWwight(double* kers)//值核
{
	for(int i=0; i<256; i++)
	{
		kers[i] =exp(-1.0*(i*i)/(2*sigmar*sigmar));
	}
}

void BilateralFilter(Mat& src, Mat& dst, double* kerd,double* kers)
{
	dst = src.clone();
	int row = dst.rows;
	int col = dst.cols;
	int channal = dst.channels();
	int ncol = col * channal;
	int k = n/2;
	double piexl_sum ;
	int index;
	double kernal[n*n];
	double temp = 0;
	double weight_sum=0;
	for (int i = k; i < (row-k) ; i++) //n/2保证边缘的像素点不被处理
	{
		uchar* ptdst = dst.ptr<uchar>(i);
		uchar* ptsrc = src.ptr<uchar>(i);
		for (int j = channal*k;j < (ncol-channal*k); j++)  //n/2保证边缘的像素点不被处理
		{
			index =0;
			piexl_sum = weight_sum =0;
			for (int kx = (i-k);kx <= i+k; kx++) //内层 kx、ky循环求和
			{
				uchar* ptrsrc = src.ptr<uchar>(kx);
				for (int ky = (j-channal*k);ky <=(j+channal*k); ky = (ky+channal))
				{
					temp = kerd[index++]*kers[(int)abs(ptsrc[j]-ptrsrc[ky])];
					piexl_sum += (ptrsrc[ky]*temp);
					weight_sum += temp;
				}	
			}
			piexl_sum /= weight_sum;       //归一化
			ptdst[j] =saturate_cast<uchar>(piexl_sum);
		}
	}
 }
int main()
{
	Mat src,dst,dst1;	
	double kerd[n*n];
	double kers[256];
	src =imread("D:/456677.jpg");
	if(!src.data)  
	{  
		cout<<"Picture loading failed !"<<endl;  
		return -1;  
	}  
	namedWindow("Win1");
	imshow("Win1", src);
	GetDistanceWeight(kerd);
	GetSimilarityWwight(kers);
	BilateralFilter(src,dst,kerd,kers);
	namedWindow("Win2");
	imshow("Win2", dst);
	bilateralFilter(src,dst1,7,50,3);
	namedWindow("Win3");
	imshow("Win3", dst1);
	waitKey(0);
	return 0;
}

对彩色图像进行处理结果:


对灰度图像进行处理:


快速双边滤波器


参考

http://blog.csdn.net/fightingforcv/article/details/50491461
http://blog.csdn.net/abcjennifer/article/details/7616663





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值