opencv学习(7)图像的各种滤波函数的介绍

图像的滤波目的有两个:
一是抽出图像的特征作为图像识别的特征模式;
另一个是为适应图像处理的要求,消除图像数字化时所混入的噪声;
1、图像的平滑处理:
平滑滤波是指低频增强的空间滤波技术。主要目的是模糊和消除噪音;

2、常用的5种图像平滑处理操作方法:
1)方框滤波——boxFilter函数
2)均值滤波——Blur函数
3)高斯滤波——GaussianBlur函数
4)中值滤波——medianBlur函数
5)双边滤波——bilateralFilter函数

前三种都属于线性滤波,后两种属于非线性滤波;
滤波和模糊:滤波是将信号中特定波段频率滤除的操作,是抑制和防止干扰的一项重要措施。模糊是滤波的一种。高斯滤波是指用高斯函数作为滤波函数的滤波操作。高斯模糊就是高斯低通滤波。

1)方框滤波——boxFilter函数
函数原型:

void boxFilter(InputArray src,OutputArray dst, int ddepth, Size ksize, Point anchor=Point(-1,-1), boolnormalize=true, int borderType=BORDER_DEFAULT )  

参数详解:
第一个参数:InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。该函数对通道是独立处理的,且可以处理任意通道数的图片,但需要注意,待处理的图片深度应该为CV_8U, CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
第二个参数:OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
第三个参数:int类型的ddepth,输出图像的深度,-1代表使用原图深度,即src.depth()。
第四个参数:Size类型(对Size类型稍后有讲解)的ksize,内核的大小。一般这样写Size( w,h )来表示内核的大小( 其中,w 为像素宽度, h为像素高度)。Size(3,3)就表示3x3的核大小,Size(5,5)就表示5x5的核大小
第五个参数:Point类型的anchor,表示锚点(即被平滑的那个点),注意他有默认值Point(-1,-1)。如果这个点坐标是负值的话,就表示取核的中心为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心。
第六个参数:bool类型的normalize,默认值为true,一个标识符,表示内核是否被其区域归一化(normalized)了。
第七个参数:int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT,我们一般不去管它。

2)均值滤波——Blur函数

函数原型:

C++: void blur(InputArray src, OutputArraydst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT )  

第一个参数:InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。该函数对通道是独立处理的,且可以处理任意通道数的图片,但需要注意,待处理的图片深度应该为CV_8U, CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
第二个参数:OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。比如可以用Mat::Clone,以源图片为模板,来初始化得到如假包换的目标图。
第三个参数:Size类型(对Size类型稍后有讲解)的ksize,内核的大小。一般这样写Size( w,h )来表示内核的大小( 其中,w 为像素宽度, h为像素高度)。Size(3,3)就表示3x3的核大小,Size(5,5)就表示5x5的核大小
第四个参数:Point类型的anchor,表示锚点(即被平滑的那个点),注意他有默认值Point(-1,-1)。如果这个点坐标是负值的话,就表示取核的中心为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心。
第五个参数:int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT,我们一般不去管它。

3)高斯滤波——GaussianBlur函数
原型:

C++: void GaussianBlur(InputArray src,OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, intborderType=BORDER_DEFAULT )  

第一个参数:InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。它可以是单独的任意通道数的图片,但需要注意,图片深度应该为CV_8U,CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
第二个参数:OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。比如可以用Mat::Clone,以源图片为模板,来初始化得到如假包换的目标图。
第三个参数:Size类型的ksize高斯内核的大小。其中ksize.width和ksize.height可以不同,但他们都必须为正数和奇数。或者,它们可以是零的,它们都是由sigma计算而来。
第四个参数:double类型的sigmaX,表示高斯核函数在X方向的的标准偏差。
第五个参数:double类型的sigmaY,表示高斯核函数在Y方向的的标准偏差。若sigmaY为零,就将它设为sigmaX,如果sigmaX和sigmaY都是0,那么就由ksize.width和ksize.height计算出来。
为了结果的正确性着想,最好是把第三个参数Size,第四个参数sigmaX和第五个参数sigmaY全部指定到。
第六个参数:int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT,我们一般不去管它。

下面是线性滤波的综合事例:

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

using namespace std;  
using namespace cv;  

Mat g_srcImage,g_dstImage1,g_dstImage2,g_dstImage3;//存储图片的Mat类型 
int g_nBoxFilterValue=3;  //方框滤波参数值 
int g_nMeanBlurValue=3;  //均值滤波参数值 
int g_nGaussianBlurValue=3;  //高斯滤波参数值 

//轨迹条的回调函数 
static void on_BoxFilter(int, void *);            //方框滤波 
static void on_MeanBlur(int, void *);           //均值滤波 
static void on_GaussianBlur(int, void *);                    //高斯滤波 

//-----------------------------------【main( )函数】---------------------------------------
int main(  )  
{  
       //改变console字体颜色 
       system("color5E");   

       //载入原图 
       g_srcImage= imread( "1.jpg", 1 );  
       if(!g_srcImage.data ) { printf("Oh,no,读取srcImage错误~!\n"); return false; }  

       //克隆原图到三个Mat类型中 
       g_dstImage1= g_srcImage.clone( );  
       g_dstImage2= g_srcImage.clone( );  
       g_dstImage3= g_srcImage.clone( );  

       //显示原图 
       namedWindow("【<0>原图窗口】", 1);  
       imshow("【<0>原图窗口】",g_srcImage);  


       //=================【<1>方框滤波】================== 
       //创建窗口 
       namedWindow("【<1>方框滤波】", 1);  
       //创建轨迹条 
       createTrackbar("内核值:", "【<1>方框滤波】",&g_nBoxFilterValue, 40,on_BoxFilter );  
       on_MeanBlur(g_nBoxFilterValue,0);  
       imshow("【<1>方框滤波】", g_dstImage1);  

       //=================【<2>均值滤波】================== 
       //创建窗口 
       namedWindow("【<2>均值滤波】", 1);  
       //创建轨迹条 
       createTrackbar("内核值:", "【<2>均值滤波】",&g_nMeanBlurValue, 40,on_MeanBlur );  
       on_MeanBlur(g_nMeanBlurValue,0);  

       //=================【<3>高斯滤波】===================== 
       //创建窗口 
       namedWindow("【<3>高斯滤波】", 1);  
       //创建轨迹条 
       createTrackbar("内核值:", "【<3>高斯滤波】",&g_nGaussianBlurValue, 40,on_GaussianBlur );  
       on_GaussianBlur(g_nGaussianBlurValue,0);  

       //输出一些帮助信息 
       cout<<endl<<"\t嗯。好了,请调整滚动条观察图像效果~\n\n"  
              <<"\t按下“q”键时,程序退出~!\n"  
              <<"\n\n\t\t\t\tby浅墨";  

       //按下“q”键时,程序退出 
       while(char(waitKey(1))!= 'q') {}  

       return 0;  
}  

// 描述:方框滤波操作的回调函数 
static void on_BoxFilter(int, void *)  
{  
       //方框滤波操作 
       boxFilter(g_srcImage, g_dstImage1, -1,Size( g_nBoxFilterValue+1, g_nBoxFilterValue+1));  
       //显示窗口 
       imshow("【<1>方框滤波】", g_dstImage1);  
}  

// 描述:均值滤波操作的回调函数 
static void on_MeanBlur(int, void *)  
{  
       //均值滤波操作 
       blur(g_srcImage, g_dstImage2, Size( g_nMeanBlurValue+1, g_nMeanBlurValue+1),Point(-1,-1));  
       //显示窗口 
       imshow("【<2>均值滤波】", g_dstImage2);  
}  

static void on_GaussianBlur(int, void *)  
{  
       //高斯滤波操作 
       GaussianBlur(g_srcImage, g_dstImage3, Size( g_nGaussianBlurValue*2+1,g_nGaussianBlurValue*2+1 ), 0, 0);  
       //显示窗口 
       imshow("【<3>高斯滤波】", g_dstImage3);  
}  

刚刚介绍的都是线性滤波,即两个信号之和的响应和他们各自响应之和相等。也就是每个像素的输出值是一些输入像素的加权和,线性滤波器易于构造,并且易于从频率响应角度来进行分析。其实在很多情况下,使用邻域像素的非线性滤波也许会得到更好的效果。
中值滤波(Median filter)是一种典型的非线性滤波技术,基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,该方法在去除脉冲噪声、椒盐噪声的同时又能保留图像边缘细节。
中值滤波在一定的条件下可以克服常见线性滤波器如最小均方滤波、方框滤波器、均值滤波等带来的图像细节模糊,而且对滤除脉冲干扰及图像扫描噪声非常有效,也常用于保护边缘信息, 保存边缘的特性使它在不希望出现边缘模糊的场合也很有用,是非常经典的平滑噪声处理方法。
缺点:中值滤波花费的时间是均值滤波的5倍以上。
双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。具有简单、非迭代、局部的特点。
双边滤波器的好处是可以做边缘保存(edge preserving),一般过去用的维纳滤波或者高斯滤波去降噪,都会较明显地模糊边缘,对于高频细节的保护效果并不明显。双边滤波器顾名思义比高斯滤波多了一个高斯方差sigma-d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素值,这样就保证了边缘附近像素值的保存。但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤波。
在双边滤波器中,输出像素的值依赖于邻域像素值的加权值组合:

4)中值滤波——medianBlur函数
medianBlur函数使用中值滤波器来平滑(模糊)处理一张图片,从src输入,而结果从dst输出。
且对于多通道图片,每一个通道都单独进行处理,并且支持就地操作(In-placeoperation)。
原型:

C++: void medianBlur(InputArray src,OutputArray dst, int ksize)  

参数详解:
第一个参数:InputArray类型的src,函数的输入参数,填1、3或者4通道的Mat类型的图像;当ksize为3或者5的时候,图像深度需为CV_8U,CV_16U,或CV_32F其中之一,而对于较大孔径尺寸的图片,它只能是CV_8U。
第二个参数:OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。我们可以用Mat::Clone,以源图片为模板,来初始化得到如假包换的目标图。
第三个参数:int类型的ksize,孔径的线性尺寸(aperture linear size),注意这个参数必须是大于1的奇数,比如:3,5,7,9。

#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 );      
}   

5)双边滤波——bilateralFilter函数
原型:

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

第一个参数:InputArray类型的src,输入图像,即源图像,需要为8位或者浮点型单通道、三通道的图像。
第二个参数:OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
第三个参数:int类型的d,表示在过滤过程中每个像素邻域的直径。如果这个值我们设其为非正数,那么OpenCV会从第五个参数sigmaSpace来计算出它来。
第四个参数:double类型的sigmaColor,颜色空间滤波器的sigma值。这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
第五个参数:double类型的sigmaSpace坐标空间中滤波器的sigma值,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。
第六个参数:int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。

#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;  
       bilateralFilter( image, out, 25, 25*2, 25/2 );  

       //显示效果图 
       imshow("双边滤波【效果图】" ,out );  

       waitKey(0 );      
}  

5种滤波的综合实例:


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

using namespace std;
using namespace cv;

Mat g_srcImage,g_dstImage1,g_dstImage2,g_dstImage3,g_dstImage4,g_dstImage5;
int g_nBoxFilterValue=6;  //方框滤波内核值
int g_nMeanBlurValue=10;  //均值滤波内核值
int g_nGaussianBlurValue=6;  //高斯滤波内核值
int g_nMedianBlurValue=10;  //中值滤波参数值
int g_nBilateralFilterValue=10;  //双边滤波参数值

//轨迹条回调函数
static void on_BoxFilter(int, void *);          //方框滤波器
static void on_MeanBlur(int, void *);           //均值滤波器
static void on_GaussianBlur(int, void *);       //高斯滤波器
static void on_MedianBlur(int, void *);         //中值滤波器
static void on_BilateralFilter(int, void *);    //双边滤波器

int main(   )
{
    g_srcImage = imread( "1.png", 1 );
    if( !g_srcImage.data ) { printf("读取srcImage错误~! \n"); return false; }

    //克隆原图到四个Mat类型中
    g_dstImage1 = g_srcImage.clone( );
    g_dstImage2 = g_srcImage.clone( );
    g_dstImage3 = g_srcImage.clone( );
    g_dstImage4 = g_srcImage.clone( );
    g_dstImage5 = g_srcImage.clone( );

    //显示原图
    namedWindow("【<0>原图窗口】", 1);
    imshow("【<0>原图窗口】",g_srcImage);

    //=================【<1>方框滤波】=========================
    //创建窗口
    namedWindow("【<1>方框滤波】", 1);
    //创建轨迹条
    createTrackbar("内核值:", "【<1>方框滤波】",&g_nBoxFilterValue, 50,on_BoxFilter );
    on_MeanBlur(g_nBoxFilterValue,0);
    imshow("【<1>方框滤波】", g_dstImage1);

    //=================【<2>均值滤波】==========================
    //创建窗口
    namedWindow("【<2>均值滤波】", 1);
    //创建轨迹条
    createTrackbar("内核值:", "【<2>均值滤波】",&g_nMeanBlurValue, 50,on_MeanBlur );
    on_MeanBlur(g_nMeanBlurValue,0);

    //=================【<3>高斯滤波】===========================
    //创建窗口
    namedWindow("【<3>高斯滤波】", 1);
    //创建轨迹条
    createTrackbar("内核值:", "【<3>高斯滤波】",&g_nGaussianBlurValue, 50,on_GaussianBlur );
    on_GaussianBlur(g_nGaussianBlurValue,0);

    //=================【<4>中值滤波】===========================
    //创建窗口
    namedWindow("【<4>中值滤波】", 1);
    //创建轨迹条
    createTrackbar("参数值:", "【<4>中值滤波】",&g_nMedianBlurValue, 50,on_MedianBlur );
    on_MedianBlur(g_nMedianBlurValue,0);

    //=================【<5>双边滤波】===========================
    //创建窗口
    namedWindow("【<5>双边滤波】", 1);
    //创建轨迹条
    createTrackbar("参数值:", "【<5>双边滤波】",&g_nBilateralFilterValue, 50,on_BilateralFilter);
    on_BilateralFilter(g_nBilateralFilterValue,0);

    cout<<endl<<"\t运行成功,请调整滚动条观察图像效果~\n\n"<<"\t按下“q”键时,程序退出。\n";
    while(char(waitKey(1)) != 'q') {}
    return 0;
}

static void on_BoxFilter(int, void *)
{
    boxFilter( g_srcImage, g_dstImage1, -1,Size( g_nBoxFilterValue+1, g_nBoxFilterValue+1));
    imshow("【<1>方框滤波】", g_dstImage1);
}

static void on_MeanBlur(int, void *)
{
    blur( g_srcImage, g_dstImage2, Size( g_nMeanBlurValue+1, g_nMeanBlurValue+1), Point(-1,-1));
    imshow("【<2>均值滤波】", g_dstImage2);
}

static void on_GaussianBlur(int, void *)
{
    GaussianBlur( g_srcImage, g_dstImage3, Size( g_nGaussianBlurValue*2+1, g_nGaussianBlurValue*2+1 ), 0, 0);
    imshow("【<3>高斯滤波】", g_dstImage3);
}

static void on_MedianBlur(int, void *)
{
    medianBlur ( g_srcImage, g_dstImage4, g_nMedianBlurValue*2+1 );
    imshow("【<4>中值滤波】", g_dstImage4);
}

static void on_BilateralFilter(int, void *)
{
    bilateralFilter ( g_srcImage, g_dstImage5, g_nBilateralFilterValue, g_nBilateralFilterValue*2, g_nBilateralFilterValue/2 );
    imshow("【<5>双边滤波】", g_dstImage5);
}


你可能感兴趣的:(opencv)