基于OpenCV底层实现均值滤波,中值滤波和高斯滤波

4 篇文章 0 订阅

起因:自己也看到一些底层的实现代码,感觉代码质量不高,而且各种指针问题,这里自己实现一下,个人认为实现的还是蛮清晰的。

首先,对于均值滤波和中值滤波不再介绍,code can explain.
对于高斯滤波,其实就是加权平均的过程,中间元素由周围元素的加权平均得到,距离越近,权值越高

这里写图片描述
其中这里的u,v表示的是到中心点的距离,这点要注意。

可以看到,其具有sigma一个参数,但是对于我们要使用的模板,需要添加一个窗口大小的参数,因此,根据上面的公式可以生成高斯模板。

const float pi = 3.1415;
vector<vector<float>> gaussTemplate(float sigma, int size) {
    int xcore = size / 2, ycore = size / 2;
    vector<vector<float>> res;
    float base = 1.0 / 2 / pi / sigma / sigma;
    for (int x = 0; x < size; x++) {
        vector<float>v;
        for (int y = 0; y < size; y++) {
            float t1 = (pow(x - xcore, 2) + pow(y - ycore, 2)) / 2.0 / sigma / sigma;
            float temp = base*exp(-t1);
            v.push_back(temp);
        }
        res.push_back(v);
    }
    return res;
}

如下生成与维基百科中一样的模板:

0.00000067 0.00002292 0.00019117 0.00038772 0.00019117 0.00002292 0.00000067

 0.00002292 0.00078633 0.00655972 0.01330386 0.00655972 0.00078633 0.00002292

 0.00019117 0.00655972 0.05472210 0.11098272 0.05472210 0.00655972 0.00019117

 0.00038772 0.01330386 0.11098272 0.22508571 0.11098272 0.01330386 0.00038772

 0.00019117 0.00655972 0.05472210 0.11098272 0.05472210 0.00655972 0.00019117

 0.00002292 0.00078633 0.00655972 0.01330386 0.00655972 0.00078633 0.00002292

 0.00000067 0.00002292 0.00019117 0.00038772 0.00019117 0.00002292 0.00000067

下面用代码实现均值滤波,中值滤波和不同的高斯滤波,当然你也可以改变模板的大小,这里给原图像加了椒盐噪声,可以看出中值滤波效果最好,从算法的角度上也可得出这一结论。

#include "opencv2/opencv.hpp"
#include "opencv2/opencv_modules.hpp"
#include "opencv2/highgui/highgui.hpp"
#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<iomanip>
using namespace cv;
using namespace std;
//添加椒盐噪声
void salt(Mat& image, int n) {
    for (int k = 0; k<n; k++) {
        int i = rand() % image.cols;    
        int j = rand() % image.rows;

        if (image.channels() == 1) {   //判断是一个通道
            image.at<uchar>(j, i) = 255;
        }
        else {
            image.at<cv::Vec3b>(j, i)[0] = 255;
            image.at<cv::Vec3b>(j, i)[1] = 255;
            image.at<cv::Vec3b>(j, i)[2] = 255;
        }
    }
}
//中值滤波
void medeanFilter(Mat& src, int win_size) {
    int rows = src.rows, cols = src.cols;
    int start = win_size/2;
    for (int m = start; m <rows - start; m++) {
        for (int n = start; n < cols - start; n++) {
            vector<uchar> model;
            for (int i = -start + m; i <= start + m; i++) {
                for (int j = -start + n; j <= start + n; j++) {
                    //cout << int(src.at<uchar>(i, j)) << endl;
                    model.push_back(src.at<uchar>(i, j));
                }
            }
            sort(model.begin(), model.end());     //采用快速排序进行
            src.at<uchar>(m, n) = model[win_size*win_size/2];
        }
    }
}
//均值滤波
void meanFilter(Mat& src, int win_size) {
    int rows = src.rows, cols = src.cols;
    int start = win_size / 2;
    for (int m = start; m <rows - start; m++) {
        for (int n = start; n < cols - start; n++) {
            int sum = 0;
            for (int i = -start + m; i <= start + m; i++) {
                for (int j = -start + n; j <= start + n; j++) {
                    sum += src.at<uchar>(i, j);
                }
            }
            src.at<uchar>(m, n) = uchar(sum / win_size / win_size);
        }
    }
}

//生成高斯模板
const float pi = 3.1415;
vector<vector<float>> gaussTemplate(float sigma, int size) {
    int xcore = size / 2, ycore = size / 2;
    vector<vector<float>> res;
    float base = 1.0 / 2 / pi / sigma / sigma;
    for (int x = 0; x < size; x++) {
        vector<float>v;
        for (int y = 0; y < size; y++) {
            float t1 = (pow(x - xcore, 2) + pow(y - ycore, 2)) / 2.0 / sigma / sigma;
            float temp = base*exp(-t1);
            v.push_back(temp);
        }
        res.push_back(v);
    }
    return res;
}

//高斯滤波
void gaussFilter(Mat& src,int size,float sigma) {
    vector<vector<float>> gaussTem = gaussTemplate(sigma,size);
    int rows = src.rows, cols = src.cols;
    int start = size / 2;
    for (int m = start; m <rows - start; m++) {
        for (int n = start; n < cols - start; n++) {
            float sum = 0;
            for (int i = -start + m; i <= start + m; i++) {
                for (int j = -start + n; j <= start + n; j++) {
                    //cout << gaussTem[i - m + start][j - n + start] << endl;
                    sum += src.at<uchar>(i, j)*gaussTem[i-m+start][j-n+start];  //重点理解!!!
                }
            }
            src.at<uchar>(m, n) = uchar(sum);
        }
    }
}

测试:

int main(){
    Mat src = imread("lena.jpg");
    cvtColor(src, src,CV_BGR2GRAY);
    //中值滤波
    Mat dst;
    src.convertTo(dst, CV_8UC1);
    salt(dst, 3000);
    namedWindow("origin");
    imshow("origin", dst);
    medeanFilter(dst,3);
    namedWindow("median filter");
    imshow("median filter", dst);
    //均值滤波
    Mat dst1;
    src.convertTo(dst1, CV_8UC1);
    salt(dst1, 3000);
    meanFilter(dst1, 3);
    namedWindow("mean filter");
    imshow("mean filter", dst1);
    float sigma = 0.84089642; int size = 7;
    vector<vector<float>> gaussTem = gaussTemplate(1, 3);
    for (auto num : gaussTem) {
        for (auto c : num)
            cout <<setprecision(8)<<std::fixed << c<< setw(11);
        cout << endl;
        cout << endl;
    }
    Mat dst2;
    src.convertTo(dst2, CV_8UC1);
    salt(dst2, 3000);
    gaussFilter(dst2, 3, 1);
    namedWindow("gause");
    imshow("gause", dst2);
    Mat dst3;
    src.convertTo(dst3, CV_8UC1);
    salt(dst3, 3000);
    gaussFilter(dst3, 3, 0.6);
    namedWindow("gause2");
    imshow("gause2", dst3);
    waitKey();
    return 0;
}

结果如下图所示:
第一行为均值和中值滤波,都是使用3*3模板
第二行为用高斯滤波不同的模板得来。

这里写图片描述
这里写图片描述

参考资料:
1. https://zh.wikipedia.org/wiki/%E9%AB%98%E6%96%AF%E6%A8%A1%E7%B3%8A
2. http://blog.csdn.net/hhygcy/article/details/4329056

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值