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

来源:互联网 发布:为什么是三生万物 知乎 编辑:程序博客网 时间:2024/05/17 20:54

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

首先,对于均值滤波和中值滤波不再介绍,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

1 0
原创粉丝点击