图像处理基础(2):自适应中值滤波器(基于OpenCV实现)

本文主要介绍了自适应的中值滤波器,并基于OpenCV实现了该滤波器,而且将自适应的中值滤波器和常规的中值滤波器对不一样几率的椒盐噪声的过滤效果进行了对比。最后,对中值滤波器的优缺点了进行了总结。算法

空间滤波器

一个空间滤波器包括两个部分:函数

  • 一个邻域,滤波器进行操做的像素集合,一般是一个矩形区域
  • 对邻域中像素进行的操做

一个滤波器就是在选定的邻域像素上执行预先定义好的操做产生新的像素,并用新的像素替换掉原来像素造成新的图像。
一般,也能够将滤波器称之为核(kernel),模板(template)或者窗口(window)学习

根据预约义的操做,能够将滤波器分为:测试

  • 线性滤波器
  • 非线性滤波器

而根据滤波器最终对图像形成的影响,能够将滤波器分为:spa

  • 平滑滤波器 ,一般用于模糊图像或者去除图像中的噪声
  • 锐化滤波器,突出图像中的边缘细节部分

中值滤波器 Median Filter

中值滤波器是一种经常使用的非线性滤波器,其基本原理是选择待处理像素的一个邻域中各像素值的中值来代替待处理的像素,其主要功能是像素的灰度值与周围像素比较接近,从而消除孤立的噪声点,因此中值滤波器可以很好的消除椒盐噪声。不只如此,中值滤波器在消除噪声的同时,还能有效的保护图像的边界信息,不会对图像形成很大的模糊(相比于均值滤波器)。3d

中值滤波器的效果受滤波窗口尺寸的影响较大,在消除噪声和保护图像的细节存在着矛盾:滤波窗口较小,则能很好的保护图像中的某些细节,但对噪声的过滤效果就不是很好;反之,窗口尺寸较大有较好的噪声过滤效果,可是会对图像形成必定的模糊。另外,根据中值滤波器原理,若是在滤波窗口内的噪声点的个数大于整个窗口内像素的个数,则中值滤波就不能很好的过滤掉噪声。code

自适应中值滤波器 Adaptive Median Filter

上面提到常规的中值滤波器,在噪声的密度不是很大的状况下(根据经验,噪声的出现的几率小于0.2),效果不错。可是当几率出现的几率较高时,常规的中值滤波的效果就不是很好了。有一个选择就是增大滤波器的窗口大小,这虽然在必定程度上能解决上述的问题,可是会给图像形成较大的模糊。blog

常规的中值滤波器的窗口尺寸是固定大小不变的,就不能同时兼顾去噪和保护图像的细节。这时就要寻求一种改变,根据预先设定好的条件,在滤波的过程当中,动态的改变滤波器的窗口尺寸大小,这就是自适应中值滤波器 Adaptive Median Filter。在滤波的过程当中,自适应中值滤波器会根据预先设定好的条件,改变滤波窗口的尺寸大小,同时还会根据必定的条件判断当前像素是否是噪声,若是是则用邻域中值替换掉当前像素;不是,则不做改变。排序

自适应中值滤波器有三个目的:文档

  • 滤除椒盐噪声
  • 平滑其余非脉冲噪声
  • 尽量的保护图像中细节信息,避免图像边缘的细化或者粗化。

自使用中值滤波算法描述

自适应滤波器不但可以滤除几率较大的椒盐噪声,并且可以更好的保护图像的细节,这是常规的中值滤波器作不到的。自适应的中值滤波器也须要一个矩形的窗口\(S_{xy}\),和常规中值滤波器不一样的是这个窗口的大小会在滤波处理的过程当中进行改变(增大)。须要注意的是,滤波器的输出是一个像素值,该值用来替换点\((x,y)\)处的像素值,点\((x,y)\)是滤波窗口的中心位置。

在描述自适应中值滤波器时须要用到以下的符号:

  • \(Z_{min}=S_{xy}\)中的最小灰度值
  • \(Z_{max}=S_{xy}\)中的最大灰度值
  • \(Z_{med}=S_{xy}\)中的灰度值的中值
  • \(Z_{xy}\)表示坐标\((x,y)\)处的灰度值
  • \(S_{max}=S_{xy}\)容许的最大窗口尺寸

自适应中值滤波器有两个处理过程,分别记为:A和B。
A :
A1 = \(Z_{med}-Z_{min}\)
A2 = \(Z_{med}-Z_{max}\)
若是A1 > 0 且 A2 < 0,跳转到 B;
不然,增大窗口的尺寸
若是增大后窗口的尺寸 \(\leq S_{max}\),则重复A过程。
不然,输出\(Z_{med}\)

B:
B1 = \(Z_{xy}-Z_{min}\)
B2 = \(Z_{xy}-Z_{max}\)
若是B1 > 0 且 B2 < 0,则输出\(Z_{xy}\)
不然输出\(Z_{med}\)

自适应中值滤波原理说明

过程A的目的是肯定当前窗口内获得中值\(Z_{med}\)是不是噪声。若是\(Z_{min} < Z_{med} < Z_{max}\),则中值\(Z_{med}\)不是噪声,这时转到过程B测试,当前窗口的中心位置的像素\(Z_{xy}\)是不是一个噪声点。若是\(Z_{min} < Z_{xy} < Z_{max}\),则\(Z_{xy}\)不是一个噪声,此时滤波器输出\(Z_{xy}\);若是不知足上述条件,则可断定\(Z_{xy}\)是噪声,这是输出中值\(Z_{med}\)(在A中已经判断出\(Z_{med}\)不是噪声)。

若是在过程A中,获得则\(Z_{med}\)不符合条件\(Z_{min} < Z_{med} < Z_{max}\),则可判断获得的中值\(Z_{med}\)是一个噪声。在这种状况下,须要增大滤波器的窗口尺寸,在一个更大的范围内寻找一个非噪声点的中值,直到找到一个非噪声的中值,跳转到B;或者,窗口的尺寸达到了最大值,这时返回找到的中值,退出。

从上面分析可知,噪声出现的几率较低,自适应中值滤波器能够较快的得出结果,不须要去增长窗口的尺寸;反之,噪声的出现的几率较高,则须要增大滤波器的窗口尺寸,这也符合种中值滤波器的特色:噪声点比较多时,须要更大的滤波器窗口尺寸。

实现

有了算法的详细描述,借助于OpenCV对图像的读写,自适应中值滤波器实现起来也不是很困难。

int minSize = 3; // 滤波器窗口的起始尺寸
    int maxSize = 7; // 滤波器窗口的最大尺寸
    Mat im1;
    // 扩展图像的边界
    copyMakeBorder(im, im1, maxSize / 2, maxSize / 2, maxSize / 2, maxSize / 2, BorderTypes::BORDER_REFLECT);
    // 图像循环
    for (int j = maxSize / 2; j < im1.rows - maxSize / 2; j++)
    {
        for (int i = maxSize / 2; i < im1.cols * im1.channels() - maxSize / 2; i++)
        {
            im1.at<uchar>(j, i) = adaptiveProcess(im1, j, i, minSize, maxSize);
        }
    }

首先定义滤波器最小的窗口尺寸以及最大的窗口尺寸。
要进行滤波处理,首先要扩展图像的边界,以便对图像的边界像素进行处理。copyMakeBorder根据选择的BorderTypes使用不一样的值扩充图像的边界像素,具体可参考OpenCV的文档信息。
下面就是遍历图像的像素,对每一个像素进行滤波处理。须要注意一点,不论滤波器多么的复杂,其每次的滤波过程,都是值返回一个值,来替换掉当前窗口的中心的像素值。函数adpativeProcess就是对当前像素的滤波过程,其代码以下:

uchar adaptiveProcess(const Mat &im, int row,int col,int kernelSize,int maxSize)
{
    vector<uchar> pixels;
    for (int a = -kernelSize / 2; a <= kernelSize / 2; a++)
        for (int b = -kernelSize / 2; b <= kernelSize / 2; b++)
        {
            pixels.push_back(im.at<uchar>(row + a, col + b));
        }
    sort(pixels.begin(), pixels.end());
    auto min = pixels[0];
    auto max = pixels[kernelSize * kernelSize - 1];
    auto med = pixels[kernelSize * kernelSize / 2];
    auto zxy = im.at<uchar>(row, col);
    if (med > min && med < max)
    {
        // to B
        if (zxy > min && zxy < max)
            return zxy;
        else
            return med;
    }
    else
    {
        kernelSize += 2;
        if (kernelSize <= maxSize)
            return adpativeProcess(im, row, col, kernelSize, maxSize); // 增大窗口尺寸,继续A过程。
        else
            return med;
    }
}

首先,根据当前窗口的大小,取得全部像素值存放到vector中,而后对vector进行排序,取得像素的最小值、最大值和中值。而后测试当前取得的中值是否在(min,max)之间,若是是,则中值不是噪声点,则开始对当前像素值进行处理,判断其是不是噪声点。若是,测试当前已取得的中值是噪声点,则扩大窗口的尺寸,在更大的空间中从新寻找中值。

上面自适应中值滤波器实现起来比较简单,因此问题就来了:效率及其的低下。这里,这是对自适应中值滤波器的原理的学习,能够忽略这个没必要要的细节。

结果对比

左边是添加几率为0.2的椒盐噪声,右边是原图。下面是使用常规的中值滤波和本文实现的自适应中值滤波器后的处理结果

左边是自适应中值滤波器(最小窗口为3,最大窗口为7)的结果,右图是常规中值滤波器(窗口大小为5)的结果。能够看出,不管是中值滤波仍是自适应的中值滤波,都能过滤掉图像中的噪声,自适应中值滤波器的效果要好些,常规的还有一些噪声没有过滤掉。并且,常规的中值滤波器对图像形成的模糊较明显,而自适应中值滤波器很好的的保存了图像中的细节。

下面测试更大几率噪声下,两种滤波器的工做状况。噪声几率为0.4时,

能够看出,常规的中值滤波器已经不能很好的过滤掉噪声,而自适应的中值滤波还能够胜任。

中值滤波器总结

  • 中值滤波器可以很好的滤除“椒盐”噪声。椒盐噪声是在图像上随机出现的孤立点,根据中值滤波器的原理,使用邻域像素的中值代替原像素,可以有效的消除这些孤立的噪声点。
  • 和均值滤波器相比,中值滤波在消除噪声的同时,还能在很大程度保护图像的细节,不会形成很大的模糊。
  • 和常规的中值滤波器相比,自适应中值滤波器可以更好的保护图像中的边缘细节部分。
相关文章
相关标签/搜索