数字图像处理16--OpenCV图像滤波,C++

图像平滑(smoothing)也称为“模糊处理”(bluring), 是一项简单且使用频率很高的图像处理方法。可以用来压制、弱化或消除图像中的细节、突变、边缘和噪声

但最常见的是用来减少图像上的噪声或者失真。降低图像分辨率时,平滑处理是很重要的。

图像噪声是图像在获取或传输的过程中受到随机信号的干扰,在图像上出现的一些随机的、离散的、孤立的像素点,这些点会干扰人眼对图像信息的分析。

图像的噪声通常是比较复杂的,很多时候将其看成是多维随机过程,因而可以借助于随即过程描述噪声,即使用概率分布函数 和 概率密度函数

噪声和图像信号的关系,可以分为:

  • 加性噪声,加性噪声和图像信号强度不相关,这类噪声可以看着理想无噪声图像f和噪声的和。
  • 乘性噪声,乘性噪声和图像信号是相关的,往往随图像信号的变化而变化。
    而为了分析处理的方便,常常将乘性噪声近似认为是加性噪声,而且总是假定信号和噪声是互相独立的。

最重要的来了,按照概率密度函数(PDF)分类:

  • 高斯噪声,高斯噪声模型经常被用于实践中。
  • 脉冲噪声(椒盐噪声),图像上一个个点,也可称为散粒和尖峰噪声。
  • 伽马噪声
  • 瑞利噪声
  • 指数分布噪声
  • 均匀分布噪声
    这种分类方法,引入了数学模型,对设计过滤算法比较有帮助。

图像滤波与滤波器

         何为图像滤波呢?指的是在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像处理中不可缺少的一项操作。好的滤波可以有效的图像处理的有效性和可靠性。我们知道,信号或者图像的能量大部分是集中在幅度谱的低频和中频段,而高频段往往会伴有噪声的存在。因此,我们设计好的滤波器必须能够较好区分高低频段。

对于图像滤波一般有两点要求:(1)不能损坏图像的重要特征信息(如轮廓和边缘等);

                                                  (2)图像经滤波处理后清晰度更高;

还有两点目的:(1)抽出图像的特征作为图像识别的特征模式;

                          (2)适应图像处理时项目的要求,尽可能的降低噪声;

        平滑滤波是低频增强的空间域滤波技术。它的目的有两类:一类是模糊;另一类是消除噪声。空间域的平滑滤波一般采用简单平均法进行,就是求邻近像元点的平均亮度值。邻域的大小与平滑的效果直接相关,邻域越大平滑的效果越好,但邻域过大,平滑会使边缘信息损失的越大,从而使输出的图像变得模糊,因此需合理选择邻域的大小(即平滑核、窗口的大小)。
 

空间滤波技术分类

      一、根据空间滤波增强目的可分为:平滑滤波和锐化滤波;

     二、根据空间滤波的特点可分为:线性滤波和非线性滤波。

  (1)平滑滤波,能减弱或消除图像中的高频分量,但不影响低频分量。因为高频分量对应图像中的区域边缘等灰度值具有较大、较快变化的部分,平滑滤波将这些分量绿区可减少局部灰度的起伏,使图像变得比较平滑。实际应用中,平滑滤波即可以用来消除噪声,又可以用在提取较大的目标前过滤去除较小的细节或将目标内的小间断连接起来。

 (2)锐化滤波,能减弱或消除图像中的低频分量,但不影响高频分量。因为低频分量对应图像中灰度值缓慢变化的区域,因而与图像的整体特性如整体对比度和平均灰度值等有关。锐化滤波将这些分量滤去可使图像反差增加,边缘明显。实际应用中,锐化滤波可用于增强图像中被模糊的细节或景物的边缘。

下面是常用的一些滤波器,分为线性滤波和非线性滤波

         方框滤波–> boxblur函数来实现 –>线性滤波-------图片的边缘信息丢失
         均值滤波(邻域平均滤波)–> blur函数 –>线性滤波 
         高斯滤波–>GaussianBlur函数 –>线性滤波 
         中值滤波–>medianBlur函数 –>非线性滤波 
         双边滤波–>bilateralFilter函数 –>非线性滤波

关于滤波和模糊


关于滤波和模糊,大家往往在初次接触的时候会弄混淆,

滤波是将信号中特定波段频率滤除的操作,是抑制和防止干扰的一项重要措施。

为了方便说明,就拿我们经常用的高斯滤波来作例子吧。我们知道,滤波可分低通滤波高通滤波两种。而高斯滤波是指用高斯函数作为滤波函数的滤波操作,至于是不是模糊,要看是高斯低通还是高斯高通,低通就是模糊,高通就是锐化。

其实说白了是很简单的,对吧:

高斯滤波是指用高斯函数作为滤波函数的滤波操作。

高斯模糊就是高斯低通滤波
 

一、方框滤波(box Filter)

1. 原理

先给出内核,用内核各点的值与其对应的图像像素值相乘


可以看出通过滤波后,图片的边缘信息会丢失。

方框滤波(box Filter)被封装在一个名为boxFilter的函数中。

void boxFilter( InputArray src, OutputArray dst, int ddepth,
                Size ksize, Point anchor = Point(-1,-1),
                bool normalize = true,
                int borderType = BORDER_DEFAULT );
  • int ddepth 输出图像的深度,-1 代表使用原图深度,即src.depth()
  • Size ksize 内核的大小。一般这样写Size(w, h)来表示内核的大小,Size(3, 3)就表示 3x3 的核大小
  • Point anchor = Point(-1,-1) 表示锚点(即被平滑的那个点),注意他有默认值Point(-1,-1) 如果这个点坐标是负值的话,就表示取核的中心为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心。
  • bool normalize = true 默认值为true,一个标识符,表示内核是否被其区域归一化(normalized)了
  • int borderType = BORDER_DEFAULT 用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT,我们一般不去管它。

函数所用的核为:

下面实例中的 α = 1/25

  • normalize = true 时,方框滤波就变成了均值滤波。也就是说,均值滤波是方框滤波归一化(normalized)后的特殊情况。其中,归一化就是把要处理的量都缩放到一个范围内,比如(0,1),以便统一处理和直观量化。
  • normalize = false 时,方框滤波用于计算每个像素邻域内的积分特性,比如密集光流算法(dense optical flow algorithms)中用到的图像倒数的协方差矩阵(covariance matrices of image derivatives)

如果我们要在可变的窗口中计算像素总和,可以使用integral()函数。
注:integral n. 积分

代码如下:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

using namespace cv;

int main() {

    Mat src = imread("image.jpg");

    imshow("src", src);

    Mat dst;

    // 方框滤波
    boxFilter(src, dst, src.depth(), Size(3, 3), Point(-1,-1),false ); // 后面1个参数都用默认值

    namedWindow("box");
    imshow("box", dst);

    waitKey(0);
    return 0;
}
结果:

二、均值滤波

1. 原理

均值滤波,是最简单的一种滤波操作,输出图像的每一个像素是核窗口内输入图像对应像素的像素的平均值( 所有像素加权系数相等),其实说白了它就是归一化后的方框滤波,blur 函数内部中其实就是调用了一下 boxFilter。

空间均值滤波的一个重要应用是为了对感兴趣的物体得到一个粗略的描述而模糊一幅图像;

2. 缺陷

均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。

均值滤波封装在一个名为blur的函数中。

void blur( InputArray src, OutputArray dst,
           Size ksize, Point anchor = Point(-1,-1),
           int borderType = BORDER_DEFAULT );

参数说明: InputArray,输入图像 src。
                   OutputArray ,输出图像 dst。
                   Int 类型 ddepth,输出图像深度, -1 代表使用原图 src 深度。

                   Size类型 ksize,内核大小 ,一般用 Size(w,h),w 为宽度,
                   h 为深度。
                  Point 类型 anchor,被平滑的点,表示取 内核中心 ,默认值 Point(-1,-1)。
                  Int 类型 boderType,推断图像外部像素的某种边界模式。默认值 BORDER_DEFAULT 

均值滤波的核:

代码:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

using namespace cv;

int main() {

    Mat src = imread("image.jpg");

    imshow("src", src);

    Mat dst;
    blur(src, dst, Size(10, 10));
    namedWindow("box");
    imshow("box", dst);

    waitKey(0);
    return 0;
}
 

结果:

三、高斯滤波

1. 原理

上面的blur的平滑原理是用邻域内的平均值来代替当前的灰度值,但是我们往往希望越靠近该像素的点提供越高的权重,这样就产生了高斯模糊滤波。它的滤波器或者叫遮罩是一个高斯分布的二维矩阵。

从数学的角度来看,图像的高斯模糊过程就是图像与正态分布做卷积,由于正态分布也被称为高斯分布,因此这项技术被称为高斯模糊。

由于高斯函数的傅立叶变换是另外一个高斯函数,所以高斯模糊对于图像来说就是一个低通滤波操作。

具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的 加权平均灰度值 去替代模板中心像素点的值。

高斯滤波器是一类 根据高斯函数的形状来选择权值的线性平滑滤波器。
高斯平滑滤波器对于 抑制服从正态分布的噪声非常有效。

高斯函数的一般形式,其中 a > 0, b, c 为实数

高斯函数一般形式

高斯函数趋势图

  • μ:平均值,确定图像位置
  • σ:标准差,越大图像越分散(矮胖), 越小图像越集中(高瘦)

一维零均值 高斯函数为:

二维零均值 离散高斯函数

图像处理来说,常用二维零均值离散高斯函数作平滑滤波器。

高斯滤波封装在一个名为GaussianBlur的函数中。

void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                   double sigmaX, double sigmaY = 0,
                   int borderType = BORDER_DEFAULT );
  • Size ksize ksize.width 和 ksize.height 可以不同,但他们都必须为正数和奇数,或者为0,可由 sigma 计算而来
  • double sigmaX 高斯核函数在 X 方向的的标准差
  • double sigmaY 高斯核函数在 Y 方向的的标准差
    若 sigmaY 为零,就将它设为 sigmaX;
    若 sigmaX 和 sigmaY 都是0,那么就由 ksize.width 和 ksize.height 计算出来


代码:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

using namespace cv;

int main() {

    Mat src = imread("image.jpg");

    imshow("src", src);

    Mat dst;
    // 高斯滤波
    // sigmaX 和 sigmaY 都是0,就由 ksize.width 和 ksize.height 计算出来
    // Size w,h 必须为奇数
    GaussianBlur(src, dst, Size(5, 5), 0, 0);
    namedWindow("gaussi");
    imshow("gaussi", dst);

    waitKey(0);
    return 0;
}
结果:

 

非线性滤波

线性滤波易于构造,且易于从频率响应的角度分析,但如果噪声是散粒噪声而非高斯噪声时线性滤波不能去除噪声。如图像突然出现很大的值,线性滤波只是转换为柔和但仍可见的散粒。这时需要非线性滤波。

中值滤波(Median filter)是一种典型的非线性滤波技术,基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,该方法在去除脉冲噪声、椒盐噪声的同时又能保留图像边缘细节.

中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,其基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点,对于斑点噪声(speckle noise)和椒盐噪声(salt-and-pepper noise)来说尤其有用,因为它不依赖于邻域内那些与典型值差别很大的值。中值滤波器在处理连续图像窗函数时与线性滤波器的工作方式类似,但滤波过程却不再是加权运算。

中值滤波在一定的条件下可以克服常见线性滤波器如最小均方滤波、方框滤波器、均值滤波等带来的图像细节模糊,而且对滤除脉冲干扰及图像扫描噪声非常有效,也常用于保护边缘信息, 保存边缘的特性使它在不希望出现边缘模糊的场合也很有用,是非常经典的平滑噪声处理方法。

.中值滤波: medianBlur 函数
函数原型: void medianBlur(InputArray src,OutputArray dst,int ksize) 
参数说明: InputArray,输入图像 src。
                   OutputArray ,输出图像 dst. 
                   int 类型 ksize,孔径的线性尺寸,这个参数必须是大于1 的奇数

代码:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

using namespace cv;

int main() {

    Mat src = imread("image.jpg");

    imshow("src", src);

    Mat dst;
    medianBlur( src, dst, 9);
    namedWindow("media");
    imshow("media", dst);

    waitKey(0);
    return 0;
}
结果:

●中值滤波 与均值滤波器比较

中值滤波器与均值滤波器比较的 优势 :在均值滤波器中,由于噪声成分被放入平均计算中,所以输出受到了噪声的影响,但是在中值滤波器中,由于噪声成分很难选上,所以几乎不会影响到输出。因此同样用3x3区域进行处理,中值滤波消除的噪声能力更胜一筹。中值滤波无论是在消除噪声还是保存边缘方面都是一个不错的方法。  

中值滤波器与均值滤波器比较的 劣势 :中值滤波花费的时间是均值滤波的5倍以上。

1.3 双边滤波

双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。具有简单、非迭代、局部的特点。

双边滤波器的好处是可以做边缘保存(edge preserving),一般过去用的维纳滤波或者高斯滤波去降噪,都会较明显地模糊边缘,对于高频细节的保护效果并不明显。双边滤波器顾名思义比高斯滤波多了一个高斯方差sigma-d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素值,这样就保证了边缘附近像素值的保存。但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤波。

在双边滤波器中,输出像素的值依赖于邻域像素值的加权值组合:

而加权系数w(i,j,k,l)取决于定义域核和值域核的乘积。

其中定义域核表示如下(如图):

定义域滤波 对应图示:

值域核表示为:


值域滤波:

两者相乘后,就会产生依赖于数据的双边滤波权重函数:

双边滤波: bilateralFilter(InputArray src,OutputArray dst, int d, 
                                        double sigmaColor,double sigmaSpace, 
                                        int borderType=BORDER_DEFAULT) 
参数说明:

. InputArray src: 输入图像,可以是Mat类型,图像必须是8位或浮点型单通道、三通道的图像。 
. OutputArray dst: 输出图像,和原图像有相同的尺寸和类型。 
. int d: 表示在过滤过程中每个像素邻域的直径范围。如果这个值是非正数,则函数会从第五个参数sigmaSpace计算该值。 
. double sigmaColor: 颜色空间过滤器的sigma值,这个参数的值月大,表明该像素邻域内有月宽广的颜色会被混合到一起,产生较大的半相等颜色区域。 
. double sigmaSpace: 坐标空间中滤波器的sigma值,如果该值较大,则意味着颜色相近的较远的像素将相互影响,从而使更大的区域中足够相似的颜色获取相同的颜色。当d>0时,d指定了邻域大小且与sigmaSpace五官,否则d正比于sigmaSpace. 
. int borderType=BORDER_DEFAULT: 用于推断图像外部像素的某种边界模式,有默认值BORDER_DEFAULT.

双边滤波器可以很好的保存图像边缘细节而滤除掉低频分量的噪音,但是双边滤波器的效率不是太高,花费的时间相较于其他滤波器而言也比较长。 
对于简单的滤波而言,可以将两个sigma值设置成相同的值,如果值<10,则对滤波器影响很小,如果值>150则会对滤波器产生较大的影响,会使图片看起来像卡通

代码:

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

const int g_ndMaxValue = 100;
const int g_nsigmaColorMaxValue = 200;
const int g_nsigmaSpaceMaxValue = 200;
int g_ndValue;
int g_nsigmaColorValue;
int g_nsigmaSpaceValue;

Mat g_srcImage;
Mat g_dstImage;

void on_bilateralFilterTrackbar(int, void*);

int main()
{
    g_srcImage = imread("lena.jpg");

    if(g_srcImage.empty())
    {
        cout << "图像加载失败!" << endl;
        return -1;
    }
    else
        cout << "图像加载成功!" << endl << endl;

    namedWindow("原图像", WINDOW_AUTOSIZE);
    imshow("原图像", g_srcImage);

    namedWindow("双边滤波图像", WINDOW_AUTOSIZE);
    g_ndValue = 10;
    g_nsigmaColorValue = 10;
    g_nsigmaSpaceValue = 10;

    char dName[20];
    sprintf(dName, "邻域直径 %d", g_ndMaxValue);

    char sigmaColorName[20];
    sprintf(sigmaColorName, "sigmaColor %d", g_nsigmaColorMaxValue);

    char sigmaSpaceName[20];
    sprintf(sigmaSpaceName, "sigmaSpace %d", g_nsigmaSpaceMaxValue);

    //创建轨迹条
    createTrackbar(dName, "双边滤波图像", &g_ndValue, g_ndMaxValue, on_bilateralFilterTrackbar);
    on_bilateralFilterTrackbar(g_ndValue, 0);

    createTrackbar(sigmaColorName, "双边滤波图像", &g_nsigmaColorValue,
                     g_nsigmaColorMaxValue, on_bilateralFilterTrackbar);
    on_bilateralFilterTrackbar(g_nsigmaColorValue, 0);

    createTrackbar(sigmaSpaceName, "双边滤波图像", &g_nsigmaSpaceValue,
                    g_nsigmaSpaceMaxValue, on_bilateralFilterTrackbar);
    on_bilateralFilterTrackbar(g_nsigmaSpaceValue, 0);

    waitKey(0);

    return 0;
}

void on_bilateralFilterTrackbar(int, void*)
{
    bilateralFilter(g_srcImage, g_dstImage, g_ndValue, g_nsigmaColorValue, g_nsigmaSpaceValue);
    imshow("双边滤波图像", g_dstImage);
}
 

结果:

分析:

均值模糊无法克服边缘像素信息丢失缺陷。原因是均值滤波是基于平均权重;
高斯模糊部分克服了该缺陷,但是无法完全避免,因为没有考虑像素值的不同;
中值模糊,虽然抑制噪声算法比均值滤波略为复杂,但保持画面清晰度的效果更好;
 高斯双边模糊是边缘保留的滤波方法,避免了边缘信息丢失,保留了图像轮廓不变
 

猜你喜欢

转载自blog.csdn.net/cyf15238622067/article/details/87854437