计算机视觉----实验E5:双边滤波

实验内容

实验5.1 双边滤波

实现一个双边滤波。

  • 并与高斯滤波比较保持图像边缘的效果。
  • 与cv::bilateralFilter比较效果和速度。

实验过程

1,计算位置空间权重。
for (int i = 0; i < f_size; i++) {
	for (int j = 0; j < f_size; j++) {
		space_weight[i][j] = exp(-(1.0) * (((i*1ll - center_i) * (i*1ll - center_i) + (j*1ll - center_j) * (j*1ll - center_j)) / (2.0 * sigmas * sigmas)));
	}
}
2,计算颜色空间权重。
for (int i = 0; i < 256 * channels; i++) {
	color_weight[i] = exp((-1.0 * (i*1ll * i)) / (2.0 * sigma_r * sigma_r));
}
3,双边滤波计算。

 先将像素之间的颜色差距算出来,得到颜色权重,再根据位置得到空间权重。像素的最终权重为颜色权重*位置权重。

for (int k = 0; k < f_size; k++) {
	for (int l = 0; l < f_size; l++) {
		x = i - k + (f_size / 2);
		y = j - l + (f_size / 2);
		values = abs(input.at<Vec3b>(i, j)[0] + input.at<Vec3b>(i, j)[1] + input.at<Vec3b>(i, j)[2] - input.at<Vec3b>(x, y)[0] - input.at<Vec3b>(x, y)[1] - input.at<Vec3b>(x, y)[2]);
		for (int c = 0; c < 3; c++) {
			pix[c] += (input.at<Vec3b>(x, y)[c] * color_weight[values] * space_weight[k][l]);
		}
		sum += (color_weight[values] * space_weight[k][l]); //方便归一化
	}
}
4,进行归一化。
for (int c = 0; c < 3; c++) {
	output.at<Vec3b>(i, j)[c] = pix[c]/sum; //归一化
}
5,效果。

 可以看到背景的灰色噪点消除了,线条更加清晰。
在这里插入图片描述
在这里插入图片描述

6,高斯滤波。

 可以看出整体变模糊了。
在这里插入图片描述

7,与 cv::bilateralFilter 比较。

 看出自己实现的双边滤波更慢,大约是 opencv自带函数的两倍。效果相差不大。
在这里插入图片描述在这里插入图片描述

附源代码

#include<iostream>
#include<opencv2/opencv.hpp>

using namespace cv;

//计算空间权重
double** get_space_weight(int f_size, int channels, double sigmas)
{
	double** space_weight = new double* [(long long)f_size];  
	for (int i = 0; i < f_size + 1; i++) {
		space_weight[i] = new double[(long long)f_size];
	}
	// [1-2] 高斯分布计算
	int center_i, center_j;
	center_i = center_j = f_size / 2;
	for (int i = 0; i < f_size; i++) {
		for (int j = 0; j < f_size; j++) {
			space_weight[i][j] =
				exp(-(1.0) * (((i*1ll - center_i) * (i*1ll - center_i) + (j*1ll - center_j) * (j*1ll - center_j)) /
					(2.0 * sigmas * sigmas)));
		}
	}
	return space_weight;
}

 //计算相似度权重 
double* get_color_weight(int f_size, int channels, double sigma_r)
{
	double* color_weight = new double[256ll * channels]; 
	for (int i = 0; i < 256 * channels; i++) {
		color_weight[i] = exp((-1.0 * (i*1ll * i)) / (2.0 * sigma_r * sigma_r));
	}
	return color_weight;
}

//双边扫描计算 
void doBialteral(const Mat& input, Mat& output, int f_size, double* color_weight, double** space_weight)
{
	output = input.clone();
	for (int i = (f_size / 2); i < input.rows - (f_size / 2); i++) {
		for (int j = (f_size / 2); j < input.cols - (f_size / 2); j++) {
			double pix[3] = { 0.0,0.0,0.0 };
			int x, y, values;
			double sum = 0.0;
			for (int k = 0; k < f_size; k++) {
				for (int l = 0; l < f_size; l++) {
					x = i - k + (f_size / 2);   
					y = j - l + (f_size / 2);  
					values = abs(input.at<Vec3b>(i, j)[0] + input.at<Vec3b>(i, j)[1] + input.at<Vec3b>(i, j)[2]
						- input.at<Vec3b>(x, y)[0] - input.at<Vec3b>(x, y)[1] - input.at<Vec3b>(x, y)[2]);
					for (int c = 0; c < 3; c++) {
						pix[c] += (input.at<Vec3b>(x, y)[c]
							* color_weight[values]
							* space_weight[k][l]);
					}
					sum += (color_weight[values] * space_weight[k][l]);
				}
			}
			for (int c = 0; c < 3; c++) {
				output.at<Vec3b>(i, j)[c] = pix[c]/sum; //归一化
			}
		}
	}

	return;
}

// 双边滤波函数
void myBialteralFilter(const Mat& input, Mat& output, const int f_size, const double sigma_d, const double sigma_r)
{
	output = Mat(input.size(), input.type());
	double* color_weight = get_color_weight(f_size, input.channels(), sigma_r);
	double** space_weight = get_space_weight(f_size, input.channels(), sigma_d);
	doBialteral(input, output, f_size, color_weight, space_weight);

	return;
}

int main(void)
{
	clock_t start_time, end_time;
	Mat imput = imread("02.webp");
	Mat output;
	int half_size = 12;

	// half_size,sigma_d,sigmar越大越模糊;
	start_time = clock();
	myBialteralFilter(imput, output, 2 * half_size + 1, 12, 20);	
	end_time = clock();     //获取结束时间
	double Times = (double)(end_time - start_time) / CLOCKS_PER_SEC;
	printf("%f s\n", Times);

	imshow("原图", imput);
	imshow("双边滤波", output);



	Mat img = imread("02.webp");
	Mat dstb, dstg;
	//GaussianBlur(img, dstg, cv::Size(3, 3), 0.8);
	//imshow("高斯滤波", dstg);

	start_time = clock();
	bilateralFilter(img, dstb, 25, 20, 12);
	imshow("双边滤波2", dstb);
	end_time = clock();     //获取结束时间
	Times = (double)(end_time - start_time) / CLOCKS_PER_SEC;
	printf("%f s\n", Times);

	waitKey(0);
	destroyAllWindows();

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值