【计算摄影学】均值滤波的简单实现

概念

均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素,再用模板中的全体像素的平均值来代替原来像素值。是较为基础的滤波算法。更广义的均值滤波可以将模板设置为任意大小,只要不超过图像大小即可。

 

理论分析

求解图像的均值滤波可以分为如下几步:

  •  读取原始图像
  •  求出均值滤波的卷积核
  •  利用 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);
}

 

posted @ 2020-03-12 19:56  Suubai  阅读(796)  评论(0编辑  收藏  举报