C++实现中值滤波的示例代码

 更新时间:2022年05月12日 11:39:02   作者:小魏612  
本文主要介绍了C++实现中值滤波的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

为了加深对中值滤波算法的理解以及方便以后更好的复习,我将该算法的一些重点细节和实现过程踩过的坑记录下来。

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

适用对象:带椒盐噪声的图像

由于椒盐噪声像素值与原图像素值没有关联,随机性较大,因此使用中值滤波可有效滤掉噪声。

中值滤波需要对像素值进行排序,因此首先写一个冒泡排序算法。

冒泡排序实现:

为提高效率加入标志位flag,当第i次寻找最大值时,如果相邻两个数均未发生互换,此时flag位为false,即说明此时数组已经按照递增排列,可提前终止。此处应该注意flag=false所在位置,因为需要保证第i次寻找最大值过程中,遍历到所有未参与排列的数据,所以flag=false应该放在循环条件for(int j=0; j<len-1-i; j++)的外部。

void bubble(std::vector<int> &arr, int len)
{
    bool flag = true;
    for (int i = 0; i < len-1; i++)
    {
        while (flag)
        {
            flag = false;
            for (int j = 0; j < len - i - 1; j++)
            {
                
                if (arr[j + 1] < arr[j])
                {
                    flag = true;  //只要发生一次交换就继续判断
                    int temp = arr[j + 1];
                    arr[j + 1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }    
}

中值滤波的实现:

需要注意的主要问题:

为了能够遍历到原图的边界,需要对原图进行边界扩充,扩充长度为(窗口的长度-1)/ 2。
注意利用窗口对扩充后的图像遍历时,起始的位置不是0,而是扩充的长度,因为这时对应的才是原图的第一个像素点,同理结束的位置也是原图的最后一个像素点。
另外为了方便将窗口内对应的像素存到容器中,可以写两个循环,循环长度为窗口的长度与宽度,依次将像素值存入容器中。
最后对容器内的像素按照递增排列后,取中值赋给目标矩阵相应的位置,而此时的位置也应该用i-h,对应扩充前的位置。
经实践证明我写的这两个算法可有效使用。

void medianFilter(cv::Mat& src, cv::Mat& dst, cv::Size width)
{
    //判断窗口是否为奇数
    if (width.width % 2 == 0 || width.height % 2 == 0)
    {
        std::cout << "输入窗口大小应该为奇数,请重新输入" << endl;
        exit(-1);
    }
    else
    {
        //计算边界扩充长度
        int h = (width.height - 1) / 2;
        int w = (width.width - 1) / 2;
 
        //对原图边界扩充
        cv::Mat src_border;
        cv::copyMakeBorder(src, src_border, h, h, w, w, cv::BORDER_REFLECT_101);
        for (int i = h; i < src.rows + h; i++)
        {
 
            for (int j = w; j < src.cols + w; j++)
            {
                //定义容器存放窗口对应的像素
                std::vector <int> v;
                for (int ii = i - h; ii <= i + h; ii++)
                {
                    for (int jj = j - w; jj <= j + w; jj++)
                    {
 
                        v.push_back(src_border.at<uchar>(ii, jj));
                    }
                }
                //对容器内存放的像素排序
                int len = width.area();
                bubble(v, len);
                //将中值赋给目标图像对应位置
                dst.at<uchar>(i-h, j-w) = v[(len - 1) / 2];
                
            }
        }
        
    }
 
}

到此这篇关于C++实现中值滤波的示例代码的文章就介绍到这了,更多相关C++ 中值滤波内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言实现黎曼和求定积分

    C语言实现黎曼和求定积分

    这篇文章主要为大家详细介绍了用C语言程序实现黎曼和求定积分,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • 深入遍历二叉树的各种操作详解(非递归遍历)

    深入遍历二叉树的各种操作详解(非递归遍历)

    本篇文章是对遍历二叉树的各种操作进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C语言实现动态开辟存储杨辉三角

    C语言实现动态开辟存储杨辉三角

    这篇文章主要介绍了如何利用C语言实现动态开辟存储杨辉三角,可以灵活的开辟空间,充分的利用空间。文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下
    2022-03-03
  • Qt5+QMediaPlayer实现音乐播放器的示例代码

    Qt5+QMediaPlayer实现音乐播放器的示例代码

    这篇文章主要为大家详细介绍了如何利用Qt5和QMediaPlayer实现简易的音乐播放器,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
    2022-12-12
  • 一篇文章带你了解C语言操作符

    一篇文章带你了解C语言操作符

    这篇文章主要以图文结合的方式为大家详细介绍了C语言操作符基础知识,感兴趣的小伙伴们可以参考一下,希望能给你带来帮助
    2021-09-09
  • VS2019中在源文件中如何使用自己写的头文件

    VS2019中在源文件中如何使用自己写的头文件

    通过头文件的形式直接调用自定义的函数,从而免去对函数的原型进行声明,本文就详细的介绍一下VS2019中在源文件中如何使用自己写的头文件,感兴趣的可以了解一下
    2021-09-09
  • 解析C++中构造函数的默认参数和构造函数的重载

    解析C++中构造函数的默认参数和构造函数的重载

    这篇文章主要介绍了解析C++中构造函数的默认参数和构造函数的重载,是C++入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • Ubuntu 环境下的 C/C++ 编译与调试配置方法

    Ubuntu 环境下的 C/C++ 编译与调试配置方法

    本文档详细介绍了如何在Ubuntu环境中使用VSCode进行C/C++的编译与调试配置,通过配置`tasks.json`和`launch.json`,实现了统一管理输出文件、优化调试流程以及跨平台兼容性,配置了`g++`编译器和`gdb`调试器,并使用C/C++插件来提高开发效率,感兴趣的朋友跟随小编一起看看吧
    2024-11-11
  • C++私有继承与EBO深入分析讲解

    C++私有继承与EBO深入分析讲解

    这篇文章主要介绍了C++私有继承,在私有继承当中,基类的公有成员和保护成员都会成为派生类的私有成员。这意味着基类的方法都会被private关键字描述,我们可以在派生类中使用它,但类对象无法直接调用,下面来看看详细内容吧
    2022-08-08
  • C语言的数字游戏算法效率问题探讨实例

    C语言的数字游戏算法效率问题探讨实例

    这篇文章主要介绍了C语言的数字游戏算法效率问题探讨实例,需要的朋友可以参考下
    2014-04-04

最新评论