本站使用了 Pjax 等基于 JavaScript 的开发技术,但您的浏览器已禁用 JavaScript,请开启 JavaScript 以保证网站正常显示!

中值滤波

本文主要介绍了以下几点内容:

  • 什么是中值滤波以及中值滤波的基本原理
  • 中值滤波有何特点以及应用场景是什么
  • 中值滤波的简单算法实现以及优化后的高效中值滤波

中值滤波

在图像处理中,在进行图像处理操作之前往往要对图像进行滤波操作。中值滤波为一种非线性的数字滤波器,它的原理基于用像素点邻域点集像素值的中值代替像素点的值,从而消除孤立的噪声点。中值滤波是非线性的、对斑点噪声椒盐噪声的滤波处理效果比较好,只要选取合适的阈值阀,中值滤波能在保留较好的边缘下降噪。

  • 斑点噪声

斑点噪声是SAR成像系统的一大特色,源自基本分辨单元内地物的随机散射,在图像上表现为信号相关(如在空间上相关)的小斑点,它既降低了图像的画面质量,又严重影响图像的自动分割、分类、目标检测以及其它定量专题信息的提取 。

  • 椒盐噪声

椒盐噪声也称为脉冲噪声,是图像中经常见到的一种噪声,它是一种随机出现的白点或者黑点,可能是亮的区域有黑色像素或是在暗的区域有白色像素(或是两者皆有)。椒盐噪声的成因可能是影像讯号受到突如其来的强烈干扰而产生、模数转换器或位元传输错误等。例如失效的感应器导致像素值为最小值,饱和的感应器导致像素值为最大值。

中值滤波算法步骤以及代码实现

基于中值滤波的设计思想,算法步骤非常简单

(1) 用一个滑动窗口去遍历图像,这个滑动窗口的范围就是像素点的邻域。
(2) 获取滑动窗口的像素值集合,并且排序,得到中值替换原像素点。
(3) 遍历图像重复步骤(2)至结束。

// This main.cpp
// median filtering sample
// author:mango
// copyright: https://mangoroom.cn

#include<iostream>
#include<vector>

#include<opencv2/opencv.hpp>

// median filtering 
void MedianFilter(const cv::Mat& input_image, cv::Mat& output_image, const int& kernel_size)
{
    // 输入参数检查
    if (input_image.empty())
    {
        throw "Input image is empty!!!";
    }
    else if(input_image.channels() != 1)
    {
        throw "Input image not be gray!!!";
    }

    // 遍历图像
    output_image = input_image.clone();
    int rows = input_image.rows;
    int cols = input_image.cols;
    
    std::vector<int> filter_windows(kernel_size*kernel_size, 0);
    
    for (auto i  = kernel_size / 2;  i < rows - (kernel_size /  2); i++)
    {
        for (auto j = kernel_size / 2; j < cols - (kernel_size / 2); j++)
        {
            // 滤波窗口元素排序
            int index = 0;
            for (auto m = 0; m < kernel_size; m++)
            {
                for (auto n = 0; n < kernel_size; n++)
                {
                    filter_windows.at(index) = input_image.at<uchar>(i - kernel_size / 2 + m, j - kernel_size / 2 + n);
                    index++;
                }
            }
            std::sort(filter_windows.begin(), filter_windows.end());

            // 更新图像像素
            output_image.at<uchar>(i, j) = filter_windows.at(kernel_size * kernel_size / 2);
        }
    }
}

int main()
{
    cv::Mat img = cv::imread("Noise_salt_and_pepper.png", 0);
    cv::Mat dst;
    MedianFilter(img, dst, 3);
    cv::imshow("img", img);
    cv::imshow("dst", dst);
    cv::waitKey(0);
    return 0;
}

但是以上直白思路的算法效率是非常低的,每个滑动窗口中的像素点每一次都需要重新排序,假如窗口选取比较大和图像比较大,显然这开销是巨大的。我们发现窗口每一次移动的时候,窗口内容丢掉的只是最左侧的一列而新增的是最右侧的一例,对于窗口的其他像素点并没有发生变化,不需要重新排序。此优化的算法步骤如下:

(1)置$t = \frac{mn}{2}$
如果m和n都为奇数,则对t取整,这样我们总是可以避免不必要的浮点数运算。
(2)将窗口移至一个新行的开始,对其内容排序。建立窗口像素的直方图H,确定其中值m,记下亮度小于或者等于m的像素数目$n_m$。
(3)对于最左列亮度是$p_g$的每个像素p,做
$$H[p_g] = H[p_g] - 1$$
进一步,如果$p_g \leq m$, 置$n_m = n_m-1$。
(4)将窗口右移一列,对于最右列亮度是$p_g$的每个像素$p$,做
$$H[p_g] = H[p_g] + 1$$
如果$p_g \leq m$, 置$n_m = n_m + 1$。
(5)如果$n_m = t$,则跳转至步骤8.
(6)如果$n_m > t$ 则跳转至步骤7。
重复
$$m = m + 1$$
$$n_m = n_m + H[m]$$
直到$n_m \geq t$则跳转至步骤8。
(7)(此时有$n_m > t$。重复
$$n_m = n_m - H[m]$$
$$m = m - 1$$
直到$n_m \leq t$。
(8) 如果有窗口的右侧列不是图像的有边界,则跳转至步骤3。
(9) 如果窗口的底行不是图像的下边界,跳转至步骤2.

滤波效果.png

references

【1】图像处理、分析与机器视觉4th-page135
【2】中值滤波-维基百科
【3】斑点噪声-百度知道
【4】椒盐噪声-维基百科


 继续浏览关于 图像处理计算机视觉图像处理算法中值滤波滤波 的文章

 本文最后更新于:2020/03/07 17:52:12,可能因经年累月而与现状有所差异

 引用转载请注明:芒果的Blog > opencv,算法,计算机视觉 > 中值滤波