中值滤波原理及c++实现

写在前面
中值滤波器是一种非线性滤波器,或者叫统计排序滤波器。

应用:中值滤波对脉冲噪声(如椒盐噪声)的抑制十分有用。

缺点:易造成图像的不连续性。

 
原理
原理很简单,如果一个信号是平缓变化的,那么某一点的输出值可以用这点的某个大小的邻域内的所有值的统计中值来代替。这个邻域在信号处理领域称之为窗(window)或者模板(Mask)。模板开的越大,输出的结果就越平滑,但也可能会把我们有用的信号特征给抹掉。所以窗的大小要根据实际的信号和噪声特性来确定。

通常我们会选择窗的大小使得窗内的数据个数为奇数个,之所以这么选是因为奇数个数据才有唯一的中间值。
 

排序
既然要求中值,那么就要对数据进行排序。常用的排序方法有7中如:冒泡、选择、插入、快速排序、堆、希尔排序等等,具体可以看:C排序|菜鸟教程、http://yansu.org/2015/09/07/sort-algorithms.html和常用排序算法总结(性能+代码)。下面的代码中用的是改进后的冒泡排序法。

效果
                                        

代码
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
 
///
///排序算法-冒泡排序(改进后)
///
void bublle_sort(std::vector<int> &arr){
    bool flag=true;
    for (int i = 0; i < arr.size() - 1; ++i){
        while (flag){
            flag = false;
            for (int j = 0; j < arr.size() - 1 - i; ++j){
                if (arr[j]>arr[j + 1]){
                    int tmp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = tmp;
                    flag = true;
                }
            }
        }
    }
}
 
 
 
//中值滤波
///
void MedianFilter(cv::Mat& src, cv::Mat& dst, cv::Size wsize){
    //图像边界扩充
    if (wsize.width % 2 == 0 || wsize.height % 2 == 0){
        fprintf(stderr, "Please enter odd size!");
        exit(-1);
    }
    int hh = (wsize.height - 1) / 2;
    int hw = (wsize.width - 1) / 2;
    cv::Mat Newsrc;
    cv::copyMakeBorder(src, Newsrc, hh, hh, hw, hw, cv::BORDER_REFLECT_101);//以边缘为轴,对称
    dst = cv::Mat::zeros(src.rows, src.cols, src.type());
 
    //中值滤波
    for (int i = hh; i < src.rows + hh; ++i){
        uchar* ptrdst = dst.ptr(i - hh);
        for (int j = hw; j < src.cols + hw; ++j){
            std::vector<int> pix;
            for (int r = i - hh; r <= i + hh; ++r){
                const uchar* ptrsrc = Newsrc.ptr(r);
                for (int c = j - hw; c <= j + hw; ++c){
                    pix.push_back(ptrsrc[c]);
                }
            }
            bublle_sort(pix);//冒泡排序
            ptrdst[j - hw] = pix[(wsize.area() - 1) / 2];//将中值映射到输出图像
        }
    }
}
 
int main(){
    cv::Mat src = cv::imread("I:\\Learning-and-Practice\\2019Change\\Image process algorithm\\Img\\salt.tif");
    if (src.empty()){
        return -1;
    }
    if (src.channels() > 1)
        cv::cvtColor(src, src, CV_RGB2GRAY);
 
    cv::Mat dst;
    cv::Mat dst1;
    cv::Size wsize(5 ,5);
 
    double t2 = (double)cv::getTickCount();
    MedianFilter(src, dst, wsize); //中值滤波
    t2 = (double)cv::getTickCount() - t2;
    double time2 = (t2 *1000.) / ((double)cv::getTickFrequency());
    std::cout << "my_process=" << time2 << " ms. " << std::endl << std::endl;
 
    cv::namedWindow("src");
    cv::imshow("src", src);
    cv::namedWindow("dst");
    cv::imshow("dst", dst);
    //cv::imwrite("I:\\Learning-and-Practice\\2019Change\\Image process algorithm\\Image Filtering\\MedianFilter\\salt.jpg",dst);
    cv::waitKey(0);
}

 
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/weixin_40647819/article/details/88779556

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值