【计算摄影学】均值滤波的简单实现
概念
均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素,再用模板中的全体像素的平均值来代替原来像素值。是较为基础的滤波算法。更广义的均值滤波可以将模板设置为任意大小,只要不超过图像大小即可。
理论分析
求解图像的均值滤波可以分为如下几步:
- 读取原始图像
- 求出均值滤波的卷积核
- 利用 filter2D 函数进行卷积操作
- 写入均值滤波后的图像
在具体的操作过程中,还必须适当地加上条件控制,例如图像是否读取成功,或者判断卷积核的大小是否超过了整个图像。
实验细节
1、卷积核的求取
由于均值滤波是对周围的像素及本身求出平均值并进行替代,其卷积核比较简单,就是一个全为1的Mat矩阵,利用ones函数即可快速求取:
kernel = Mat::ones(height, width, CV_32F) / (float)(height*width); //均值滤波的核
2、利用 filter2D 函数进行卷积操作
Point anchor(-1, -1); //中间的点 int depth = -1; //深度和输入一样 int delta = 0; //在处理之后 再加上delta,默认0 kernel = Mat::ones(height, width, CV_32F) / (float)(height*width);//均值滤波的核 filter2D(src, dst, depth, kernel, anchor, delta);
该步直接利用 filter2D 函数进行卷积操作,其中 kernel 为卷积核,anchor 指示的是卷积核的中心点, depth 设置为-1表示输出图像的位深度与输入图像一致,最后的 delta 默认设置为0,它表示在储存目标图像前可选的添加到像素的值。
这样就完成了卷积操作。
3、条件控制
对图像读取成功与否进行判断,进而对输入卷积核大小的合理性进行判断。
// 进行初始判断 src = imread(image_name, IMREAD_COLOR); if (src.empty()){ cout << "图像读取失败!" << endl; return 0; } else { // 若读取成功,判断卷积核的大小与图像大小的关系 img_height = src.rows; img_width = src.cols; if (img_height < height * 2 + 1 || img_width < width * 2 + 1) { cout << "卷积核大小超过图像大小!" << endl; return 0; } }
结果展示
(原始图像)
(均值滤波后图像,卷积核大小取5*5)
最后附上完整代码:
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { Mat src, dst; Mat kernel; string image_name; string output_name; int width, height, img_height, img_width; cout << "请输入需要读取的图像名称:"; cin >> image_name; cout << "请输入输出的图像名称:"; cin >> output_name; cout << "请输入卷积核的宽度:"; cin >> width; cout << "请输入卷积核的高度:"; cin >> height; cout << "正在处理,请稍后……" << endl;; // 进行初始判断 src = imread(image_name, IMREAD_COLOR); if (src.empty()){ cout << "图像读取失败!" << endl; return 0; } else { // 若读取成功,判断卷积核的大小与图像大小的关系 img_height = src.rows; img_width = src.cols; if (img_height < height * 2 + 1 || img_width < width * 2 + 1) { cout << "卷积核大小超过图像大小!" << endl; return 0; } } Point anchor(-1, -1); //中间的点 int depth = -1;//深度和输入一样 int delta = 0; //在处理之后 再加上delta,默认0 kernel = Mat::ones(height, width, CV_32F) / (float)(height*width);//均值滤波的核 filter2D(src, dst, depth, kernel, anchor, delta); imshow("均值滤波", dst); imwrite(output_name, dst); waitKey(0); }