本实验为计算机科学与技术学院计算机专业大四上限选课,2023-2024-1年度课程实验,较以往实验内容发生较大变化
本实验使用vs2019,c++语言,需要提前安装opencv,具体方法请自行搜索。
实验4:图像滤波
实现一个双边滤波(Bilateral Filter),并与高斯滤波比较保持图像边缘的效果,与cv::bilateralFilter比较效果和速度
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <vector>
#include <time.h>
using namespace std;
using namespace cv;
Mat src, dst, dst2, blurred, kernel;
int windowSize = 5;
int sigma_r = 300;
int sigma_s = 10;
clock_t startTime, endTime;
void on_Trackbar(int, void*)
{
//Gaussian();//与高斯滤波比较保持图像边缘的效果
startTime = clock();
bilateralFilter(src, dst2, windowSize*2, sigma_r, sigma_s);
imshow("Bilateral_Img", dst2);
endTime = clock();
cout << "使用库函数bilateralFilter的时间为 " << endTime - startTime << " " << endl;
startTime = clock();
// 使用双边滤波器对源图像进行滤波,将结果保存在dst2中,窗口大小为windowSize,分别有sigma_r和sigma_s控制空间域和灰度域的滤波强度
//dst2.convertTo(dst, src.type());
//imshow("My_algorithm", dst);
// 将经过双边滤波后的图像转换为与源图像相同的类型,并保存结果在dst中
//imshow("My_algorithm", dst);
int windowSize_2 = windowSize;
Mat src_tmp, dst_tmp;
// 使用copyMakeBorder函数为源图像添加边界,边界大小为windowSize_2,复制边界像素填充新边界,新边界的类型为BORDER_REPLICATE
copyMakeBorder(src, src_tmp, windowSize_2, windowSize_2, windowSize_2, windowSize_2, BORDER_REPLICATE);
// 将源图像数据转换为CV_64FC3类型(64位浮点数3通道),并缩放像素值到[0,1]范围(归一化)
src_tmp.convertTo(src_tmp, CV_64FC3, 1.0 / 255.0);
dst_tmp = Mat::zeros(src.size(), src_tmp.type());
// 获取源图像的行数和列数
int rows = src_tmp.rows, cols = src_tmp.cols;
//imshow("My_algorithm", dst);
//cout << rows << " " << cols <<" "<<windowSize_2<< endl;
//cout << "ss" << endl;
// 循环处理图像的每个像素(三通道颜色)
for (int k = 0; k < 3; ++k)
{
// 对图像的每一行进行循环(除去窗口大小的边缘像素)
for (int i = windowSize_2; i < rows - windowSize_2; ++i)
{
//列
for (int j = windowSize_2; j < cols - windowSize_2; ++j)
{
//cout << i - windowSize_2 << " " << j - windowSize_2 << endl;
//cout << j << endl;
double sum = 0, sum1 = 0, sum2 = 0;
// 对以当前像素为中心的窗口内的每个像素进行循环(包括边缘像素)
for (int x = i - windowSize_2; x <= i + windowSize_2; ++x)
{
//cout << "x= " << x << endl;
for (int y = j - windowSize_2; y <= j + windowSize_2; ++y)
{
//cout << "y= " << y << endl;
double g_s = exp(-(pow(x - i, 2) + pow(y - j, 2) / (2.0 * pow(sigma_s, 2))));//计算空间域
double g_r = exp(-pow(src_tmp.at<Vec3d>(i, j)[k] - src_tmp.at<Vec3d>(x, y)[k], 2) / (2 * pow(sigma_r, 2)));//计算像素域
sum1 += g_s * g_r * src_tmp.at<Vec3d>(x, y)[k];
sum2 += g_s * g_r;
}
}
//cout << sum2 << endl;
dst_tmp.at<Vec3d>(i - windowSize_2, j - windowSize_2)[k] = sum1 / sum2;
//cout << "{{{{" << endl;
}
}
}
//dst_tmp.convertTo(dst, src.type(), 255);//对应之前的归一化
endTime = clock();
//imshow("Bilateral_Img", dst2);
cout << "使用自己实现的双边滤波的时间为 " << endTime - startTime << " " << endl;
imshow("My_algorithm", dst_tmp);
}
int main()
{
src = imread("C:/Users/13441/Desktop/数字图像/back.png");
//namedWindow("sec_image", WINDOW_AUTOSIZE);
imshow("src_image", src);
dst = Mat::zeros(src.size(), src.type());
dst2 = Mat::zeros(src.size(), src.type());
//namedWindow("My_algorithm", WINDOW_AUTOSIZE);
namedWindow("Bilateral_Img", WINDOW_AUTOSIZE);
//createTrackbar("窗口大小", "Bilateral_Img", &windowSize, 50, on_Trackbar);
createTrackbar("Sigma_r", "Bilateral_Img", &sigma_r, 500, on_Trackbar);
createTrackbar("Sigma_s", "Bilateral_Img", &sigma_s, 20, on_Trackbar);
waitKey(0);
return 0;
}
实现的双边滤波:
cv::bilateralFilter函数: