iOS 模式识别

三 (3.2 imgproc) 平滑处理 - 滤波器

2018-10-24  本文已影响33人  交大小丑

滤波作用:

滤波的目的有两个:
1.抽出对象的特征作为图像识别的特征模式;
2.为适应图像处理要求,消除数字图像所混入的噪声 .
对图像滤波有两个要求:
1.不能损坏图像的轮廓和边缘等重要信息;
2.使图像清晰视觉效果更好.

三种常见线性邻域滤波:“方框滤波”,“均值滤波”,“高斯滤波” 。
非线性滤波:“中值滤波”,“双边滤波”。


线性滤波

一、 方框滤波(box Filter)

1.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 );
参数可以省略:
boxFilter(src, dst, -1, Size(10, 10)); // 后面3个参数都用默认值
                                       // Point anchor = Point(-1,-1)
                                       // bool normalize = true
                                       // int borderType = BORDER_DEFAULT

1.2. 方框滤波实例

方框滤波函数使用的卷积核

1.3. 代码实例

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

using namespace cv;

int main() {

    Mat src = imread("../pics/pig.jpg");

    namedWindow("原图");
    imshow("原图", src);

    Mat dst;

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

    namedWindow("方框滤波");
    imshow("方框滤波", dst);

    waitKey(0);
}

二、 均值滤波(blur函数)

2.1. 原理

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

均值滤波封装在一个名为blur的函数中:
void blur( InputArray src, OutputArray dst,
           Size ksize, Point anchor = Point(-1,-1),
           int borderType = BORDER_DEFAULT );
均值滤波的核:
均值滤波的核

2.2. 实例

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

using namespace cv;

int main() {

    Mat src = imread("../pics/pig.jpg");

    namedWindow("原图");
    imshow("原图", src);

    Mat dst;

    // 均值滤波
    blur(src, dst, Size(10, 10));

    namedWindow("均值滤波");
    imshow("均值滤波", dst);

    waitKey(0);
}

2.3. 缺陷

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

三、 高斯滤波(GaussianBlur函数)

3.1. 原理

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

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

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

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

1. 正态分布 --- 一维

正态分布

2. 正态分布 --- 二维

上面的正态分布是一维的,图像都是二维的,所以我们需要二维的正态分布。


二维正态分布

3.2. 函数推导

3.2.1 一维函数推导:

正态分布的密度函数叫做“高斯函数”(Gaussian function)。
正态分布也成为高斯分布,二位正态分布也成为二维高斯分布、
一维高斯分布(正态分布)公式

一维高斯函数
对于任意的实数a,b,c,是以著名数学家Carl Friedrich Gauss的名字命名的。高斯的一维图是特征对称“bell curve”形状,a是曲线尖峰的高度,b是尖峰中心的坐标,c称为标准方差,表征的是bell钟状的宽度。
一维高斯函数

高斯函数广泛应用于统计学领域,用于表述正态分布,在信号处理领域,用于定义高斯滤波器,在图像处理领域,二维高斯核函数常用于高斯模糊Gaussian Blur,在数学领域,主要是用于解决热力方程和扩散方程,以及定义Weiertrass Transform。

当函数积分面积为1时,是我们的常用的正态分布,使用积分求出面积为1时,各个参数大小:

从上图可以看出,高斯函数是一个指数函数,其log函数是对数凹二次函数

高斯函数的积分是误差函数error function,尽管如此,其在整个实线上的反常积分能够被精确的计算出来,使用如下的高斯积分


image.png image.png image.png
当且仅当:
image.png

上式积分为1,在这种情况下,高斯是正态分布随机变量的概率密度函数,期望值μ=b,方差delta^2 = c^2,即


image.png

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

3.2.2 二维高斯函数推导:

二维高斯函数,形如:

二维高斯函数
当函数在的X,Y方向上对称时:
对称形式

A是幅值,x。y。是中心点坐标,σx σy是方差,图示如下,A = 1, xo = 0, yo = 0, σx = σy = 1


二维高斯函数图像

该函数各向同性,其曲线是草帽状的对称图,该曲线对整个覆盖面积求积分为1。高斯滤波的思路就是:对高斯函数进行离散化,以离散点上的高斯函数值为权值,对我们采集到的灰度矩阵的每个像素点做一定范围邻域内的加权平均,即可有效消除高斯噪声。

四、 中值滤波

高斯模糊(高斯滤波)的原理与算法 - lsh呵呵的专栏 - CSDN博客
https://blog.csdn.net/nima1994/article/details/79776802

高斯函数及其各阶导数 - 文森vincent - 博客园 http://www.cnblogs.com/vincent2012/archive/2012/08/29/2662907.html

高斯函数的详细分析 - ZuckGogo - CSDN博客 https://blog.csdn.net/jorg_zhao/article/details/52687448

图像滤波之高斯滤波介绍 - 淇淇宝贝 - 博客园 https://www.cnblogs.com/qiqibaby/p/5289977.html

3.3 高斯滤波离散化算法实现

可以发现很多教材以及网上的资料都描述高斯滤波的原理是采用高斯算子对图像进行卷积运算。其实在各个算法库如Matlab、OpenCV等,在实现的时候,就是采用一个矩阵模板进行加权运算,拿图像的八连通区域来说,中间点的像素值就等于八连通区的像素值的均值,这样达到平滑的效果,该模板我们常成为高斯核。

根据上述分析可知,高斯核是整个求解的关键。很显然,它是通过二维高斯函数计算得来的。这里给出离散高斯核矩阵的计算公式。
离散的高斯卷积核H: (2k+1)×(2k+1)维,其元素计算方法为:


离散的高斯卷积核计算公式 离散的高斯卷积核计算公式

其中Sigma为方差,k确定核矩阵的维数,关于这两个取值,在下文进行分析。

与matlab函数运行结果对比

这里对高斯卷积核的矩阵算法进行验证。
1)在matlab中用以下代码可以产生一个3×3的核。

 filter=fspecial('gaussian',3,1);

所产生的核矩阵为:

              filter =
                         0.0751    0.1238   0.0751
                         0.1238    0.2042   0.1238
                         0.0751   0.1238    0.0751

2)同样对于上述的公式,我们取k=1,Sigma=1,即可得到3×3的高斯卷积核如下:


image.png

上文说到,我们进行加权滤波,权系数之和必须为1,上面所求出的高斯滤波核函数同样的必须进行归一化:


image.png
由此可以证明该核函数计算方法的正确性。

openCV中使用的高斯滤波

1. OpenCv中cvSmooth函数的用法

该函数原型为:
void cvSmooth(const CvArr* src, CvArr* dst,
              int smoothtype=CV_GAUSSIAN,
              int param1=3, int param2=0,double param3=0, double param4=0 );

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

void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                   double sigmaX, double sigmaY = 0,
                   int borderType = BORDER_DEFAULT );

3.4 实例

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

using namespace cv;

int main() {

    Mat src = imread("../pics/pig.jpg");

    namedWindow("原图");
    imshow("原图", src);

    Mat dst;

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

    namedWindow("高斯滤波");
    imshow("高斯滤波", dst);

    waitKey(0);
}
核心代码
// 高斯滤波
// sigmaX 和 sigmaY 都是0,就由 ksize.width 和 ksize.height 计算出来
// Size w,h 必须为奇数
GaussianBlur(src, dst, Size(5, 5), 0, 0);

高斯滤波:
opencv学习(二十)之高斯滤波GaussianBlur() - 烟雨博客 - CSDN博客 https://blog.csdn.net/keith_bb/article/details/54412493?fps=1&locationNum=11
opencv源码解析之(4):GaussianBlur() - tornadomeet - 博客园 http://www.cnblogs.com/tornadomeet/archive/2012/03/10/2389617.html


非线性滤波概述

之前的那篇文章里,我们所考虑的滤波器都是线性的,即两个信号之和的响应和他们各自响应之和相等。换句话说,每个像素的输出值是一些输入像素的加权和,线性滤波器易于构造,并且易于从频率响应角度来进行分析。

其实在很多情况下,使用邻域像素的非线性滤波也许会得到更好的效果。比如在噪声是散粒噪声而不是高斯噪声,即图像偶尔会出现很大的值的时候。在这种情况下,用高斯滤波器对图像进行模糊的话,噪声像素是不会被去除的,它们只是转换为更为柔和但仍然可见的散粒。

四、 中值滤波(medianBlur函数)

4.1 原理

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

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

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

椒盐噪声
椒盐噪声是由图像传感器,传输信道,解码处理等产生的黑白相间的亮暗点噪声。椒盐噪声是指两种噪声,一种是盐噪声(salt noise)盐=白色(255),另一种是胡椒噪声(pepper noise),椒=黑色(0)。前者是高灰度噪声,后者属于低灰度噪声。一般两种噪声同时出现,呈现在图像上就是黑白杂点。对于彩色图像,则表现为在单个像素BGR三个通道随机出现的255与0,如下图所示。

中值滤波执行过程:
(1) 按强度值大小排列像素点.
(2) 选择排序像素集的中间值作为点[i,j]的新值.

image.png

一般采用奇数点的邻域来计算中值,但如果像素点数为偶数时,中值就取排序像素中间两点的平均值。

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

3.2 函数讲解

void medianBlur( InputArray src, OutputArray dst,int ksize );

3.3 代码

//-----------------------------------【程序说明】----------------------------------------------
//            说明:【中值滤波medianBlur函数的使用示例程序】
//            开发所用OpenCV版本:2.4.8
//            2014年4月3 日 Create by 浅墨
//------------------------------------------------------------------------------------------------
 
//-----------------------------------【头文件包含部分】---------------------------------------
//     描述:包含程序所依赖的头文件
//----------------------------------------------------------------------------------------------
#include "opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include"opencv2/imgproc/imgproc.hpp"
 
//-----------------------------------【命名空间声明部分】---------------------------------------
//     描述:包含程序所使用的命名空间
//----------------------------------------------------------------------------------------------- 
using namespace cv;
 
//-----------------------------------【main( )函数】--------------------------------------------
//     描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main( )
{
       //载入原图
       Mat image=imread("1.jpg");
 
       //创建窗口
       namedWindow("中值滤波【原图】" );
       namedWindow("中值滤波【效果图】");
 
       //显示原图
       imshow("中值滤波【原图】", image );
 
       //进行中值滤波操作
       Mat out;
       medianBlur( image, out, 7);
 
       //显示效果图
       imshow("中值滤波【效果图】" ,out );
 
       waitKey(0 );    
}
核心代码
 medianBlur( image, out, 7);

五、 双边滤波(Bilateral filter)

5.1 原理

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

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


双边滤波核示意图 高斯核/定义域核 值域核

值域核的就是的双边滤波与高斯滤波的差别,值域核使得边缘信息得保留,只有满足特点值域范围内,才会进行的高斯模糊。

原理还需要补充

Bilateral Filters(双边滤波算法)原理及实现 - 梅子黄时雨 - CSDN博客 https://blog.csdn.net/piaoxuezhong/article/details/78302920

5.2 函数讲解

C++: void bilateralFilter(InputArray src, OutputArraydst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT)

5.3 实例

//-----------------------------------【程序说明】----------------------------------------------
//            说明:【双边滤波bilateralFilter函数的使用示例程序】
//            开发所用OpenCV版本:2.4.8
//            2014年4月3 日 Create by 浅墨
//------------------------------------------------------------------------------------------------
 
//-----------------------------------【头文件包含部分】---------------------------------------
//     描述:包含程序所依赖的头文件
//----------------------------------------------------------------------------------------------
#include "opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include"opencv2/imgproc/imgproc.hpp"
 
//-----------------------------------【命名空间声明部分】---------------------------------------
//     描述:包含程序所使用的命名空间
//----------------------------------------------------------------------------------------------- 
using namespace cv;
 
//-----------------------------------【main( )函数】--------------------------------------------
//     描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main( )
{
       //载入原图
       Mat image=imread("1.jpg");
 
       //创建窗口
       namedWindow("双边滤波【原图】" );
       namedWindow("双边滤波【效果图】");
       namedWindow("高斯滤波【效果图】");
       //显示原图
       imshow("双边滤波【原图】", image );
 
       //进行双边滤波操作
       Mat out;
       bilateralFilter( image, out, 25, 50, 25/2 );
       Mat outgaosi;
       GaussianBlur( image, outgaosi,  Size(25, 25), 25/2, 25/2 );
       //显示效果图
       imshow("双边滤波【效果图】" ,out );
       imshow("高斯滤波【效果图】" ,out );
       waitKey(0 );    
}

核心代码:
       bilateralFilter( image, out, 25, 25*2, 25/2 );

【OpenCV入门教程之八】线性邻域滤波专场:方框滤波、均值滤波与高斯滤波 - 【浅墨的游戏编程Blog】毛星云(浅墨)的专栏 - CSDN博客 https://blog.csdn.net/poem_qianmo/article/details/22745559

【OpenCV入门教程之九】 非线性滤波专场:中值滤波、双边滤波 - 【浅墨的游戏编程Blog】毛星云(浅墨)的专栏 - CSDN博客 https://blog.csdn.net/poem_qianmo/article/details/23184547

opencv各类滤波器详解 - 当你努力到把自己都感动的时候,你离成功就不远了。 - CSDN博客 https://blog.csdn.net/xuhang0910/article/details/47087939

opencv几种常见滤波器使用方法_百度文库 https://wenku.baidu.com/view/f3f49ac5f5335a8103d2207b

写个程序体会各种滤波器效果
https://blog.csdn.net/feitian944/article/details/80287265

滤波器的使用
https://blog.csdn.net/xingchenbingbuyu/article/details/79170764

上一篇下一篇

猜你喜欢

热点阅读