opencv学习笔记(十七)——线性滤波

图像线性滤波:

  • 图像滤波:指尽量在保存图像细节特征的条件下对目标图像的噪声进行抑制。
  • 图像滤波的目的:一是抽出对象的特征作为图像识别的特征模式;二是消除图像中混入的噪声。
  • 图像滤波的要求:一是不能损坏图像的轮廓及边缘等重要信息;二是使图像清晰视觉效果好。
  • 滤波和模糊的区别:拿高斯滤波来举例:滤波一般可以分为高通滤波和低通滤波,对于高斯低通滤波就会产生模糊效果,如果对于高斯高通滤波就会产生锐化的效果。所以通常是:高斯滤波就是指使用高斯函数进行滤波;高斯模糊就是指低通滤波。
  • 线性过滤器:即两个信号之和的响应和它们各自响应之和相等,换句话说,每个像素的输出值是一些输入像素的加权和,使用乘积和的计算,例如:R = w1z1 + w2z2 + … + wnzn
    高通:边缘增强、边缘提取
    低通:钝化图像、去除噪音
    带通:删除特定频率、增强中很少用

方框滤波(boxfilter)

方框滤波的原理:

方框滤波的核表示如下:
opencv学习笔记(十七)——线性滤波_第1张图片
这里写图片描述
h代表该点的像素值
hsize代表滤波核
这里的normalize默认为ture,normalize为ture时,方框滤波其实就是均值滤波了
假设滤波核大小为3*3的的,锚点坐标为(x,y),则在目标图像上对应(x,y)这点的像素值为:
h = (f(x-1,y-1) + f(x,y-1)+ f(x+1,y-1) + f(x-1,y) + f(x,y) + f(x+1,y) + f(x-1,y+1) + f(x,y+1) + f(x+1,y+1))/(3*3)

Boxfilter函数API介绍:

C++: 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()。
  • 第五个参数,Point类型的anchor,表示锚点(即被平滑的那个点),注意他有默认值Point(-1,-1)。如果这个点坐标是负值的话,就表示取核的中心为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心。
  • 第七个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT。

使用实例:

#include

using namespace cv;

int main()
{
    cv::Mat srcimage = cv::imread("test.png");

    cv::namedWindow("源图像");
    cv::namedWindow("滤波后");
    std::cout << std::endl;
    std::cout << std::endl;
    std::cout << std::endl;
    //show the source image
    cv::imshow("源图像", srcimage);

    cv::Mat dstimage;
    cv::boxFilter(srcimage, dstimage,-1, cv::Size(3,3));
    cv::imshow("滤波后", dstimage);
    cv::waitKey(0);
    return 0;

}

可以使用这种方式查看图像对应的像素值:

    for (int y = 0; y < srcimage.rows; y++)
    {
        for (int x = 0; x < srcimage.cols; x++)
        {
            std::cout << (int)(srcimage.at(y, x)[0]) << " " << (int)(srcimage.at(y, x)[1]) << " " << (int)(srcimage.at(y, x)[2]) << ",";
        }
        std::cout << std::endl;
    }

但是这里涉及一个边界填充的问题,边上进行滤波的时候,会有边界填充的,如果使用的是BORDER_REFLECT_101,就需要使用对称法,也就是以最边缘像素为轴对称,不能简单地由源图像按公式推输出图像,

均值滤波(Blur)

介绍:

缺陷:不能很好得保存图像的细节,去噪的同时会破坏图像的细节从而使图像模糊,不能很好地去噪。

均值滤波的原理介绍:

opencv学习笔记(十七)——线性滤波_第2张图片
它的原理就是在求均值,对滤波核所对应的所有元素的像素值进行求和再求出均值,再将这个均值赋值给锚点所对应像素作为该像素的值。

均值滤波函数(Blur函数)的API介绍:

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,我们一般不去管它。

使用实例:

#include<opencv2/opencv.hpp>

void main3()
{
    cv::Mat srcimage = cv::imread("腐蚀_膨胀.png");

    cv::namedWindow("源图像");
    cv::imshow("源图像", srcimage);
    cv::namedWindow("均值滤波");

    cv::Mat dstimage;

    cv::blur(srcimage, dstimage, cv::Size(15, 15));
    cv::imshow("均值滤波", dstimage);
    cv::waitKey(0);
}

高斯滤波(GaussianBlur)

介绍:

高斯滤波是一种线性平滑滤波,可以消除高斯噪声,广泛应用于图像处理减噪过程。

高斯滤波的原理:

高斯滤波就是每个像素点的值都是由其本身和邻域内的其他像素值经过加权平均后得到的。
高斯函数具有五个重要的性质,这些性质使得它在早期图像处理中特别有用.这些性质表明,高斯平滑滤波器无论在空间域还是在频率域都是十分有效的低通滤波器,且在实际图像处理中得到了工程人员的有效使用.高斯函数具有五个十分重要的性质,它们是:
(1)二维高斯函数具有旋转对称性,即滤波器在各个方向上的平滑程度是相同的.一般来说,一幅图像的边缘方向是事先不知道的,因此,在滤波前是无法确定一个方向上比另一方向上需要更多的平滑.旋转对称性意味着高斯平滑滤波器在后续边缘检测中不会偏向任一方向.
(2)高斯函数是单值函数.这表明,高斯滤波器用像素邻域的加权均值来代替该点的像素值,而每一邻域像素点权值是随该点与中心点的距离单调增减的.这一性质是很重要的,因为边缘是一种图像局部特征,如果平滑运算对离算子中心很远的像素点仍然有很大作用,则平滑运算会使图像失真.
(3)高斯函数的付立叶变换频谱是单瓣的.正如下面所示,这一性质是高斯函数付立叶变换等于高斯函数本身这一事实的直接推论.图像常被不希望的高频信号所污染(噪声和细纹理).而所希望的图像特征(如边缘),既含有低频分量,又含有高频分量.高斯函数付立叶变换的单瓣意味着平滑图像不会被不需要的高频信号所污染,同时保留了大部分所需信号.
(4)高斯滤波器宽度(决定着平滑程度)是由参数σ表征的,而且σ和平滑程度的关系是非常简单的.σ越大,高斯滤波器的频带就越宽,平滑程度就越好.通过调节平滑程度参数σ,可在图像特征过分模糊(过平滑)与平滑图像中由于噪声和细纹理所引起的过多的不希望突变量(欠平滑)之间取得折衷.
(5)由于高斯函数的可分离性,大高斯滤波器可以得以有效地实现.二维高斯函数卷积可以分两步来进行,首先将图像与一维高斯函数进行卷积,然后将卷积结果与方向垂直的相同一维高斯函数卷积.因此,二维高斯滤波的计算量随滤波模板宽度成线性增长而不是成平方增长.

高斯滤波函数(GaussianBlur函数):

  • 第一个参数,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/opencv.hpp>

void mian()
{
    cv::Mat srcimage = cv::imread("腐蚀_膨胀.png");

    cv::namedWindow("srcimage");
    cv::namedWindow("dstimage");      

    cv::imshow("srcimage", srcimage);

    cv::Mat dstimage;

    cv::GaussianBlur(srcimage, dstimage, cv::Size(5, 5), 0, 0);

    cv::imshow("dstimage", dstimage);

    cv::waitKey(0);
}

综合实例

#include

cv::Mat g_srcImage, g_dstImage1, g_dstImage2, g_dstImage3;
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 *);

void main4()
{
    g_srcImage = cv::imread("腐蚀_膨胀.png");
    if (!g_srcImage.data)
        std::cout << "图片加载失败!" << std::endl;
    g_dstImage1 = g_srcImage.clone();
    g_dstImage2 = g_srcImage.clone();
    g_dstImage3 = g_srcImage.clone();

    cv::namedWindow("源图像");
    cv::imshow("源图像", g_srcImage);

    /******************** Boxfilter ***********************/
    cv::namedWindow("BoxFilter");
    //创建滑块条
    cv::createTrackbar("内核值:", "BoxFilter", &g_nBoxFilterValue, 40, on_BoxFilter);
    on_BoxFilter(g_nBoxFilterValue,0);
    cv::imshow("BoxFilter", g_dstImage1);

    /***********************MeanBlur************************/
    cv::namedWindow("MeanBlur");
    cv::createTrackbar("内核值:", "MeanBlur", &g_nMeanBlurValue, 40, on_MeanBlur);
    on_BoxFilter(g_nMeanBlurValue, 0);
    cv::imshow("MeanBlur", g_dstImage2);

    /*********************GaussianBlur***********************/
    cv::namedWindow("GaussianBlur");
    cv::createTrackbar("内核值:", "GaussianBlur", &g_nGaussianBlurValue, 40, on_GaussianBlur);
    on_GaussianBlur(g_nGaussianBlurValue, 0);
    cv::imshow("GaussianBlur", g_dstImage3);
    while (char(cv::waitKey(1)) != 'q') {};
}

static void on_BoxFilter(int, void *)
{
    cv::boxFilter(g_srcImage, g_dstImage1, -1, cv::Size(g_nBoxFilterValue + 1, g_nBoxFilterValue + 1));
    cv::imshow("BoxFilter", g_dstImage1);
}

static void on_MeanBlur(int, void*)
{
    cv::blur(g_srcImage, g_dstImage2, cv::Size(g_nMeanBlurValue + 1, g_nMeanBlurValue + 1),cv::Point(-1,-1));
    cv::imshow("MeanBlur", g_dstImage2);
}

static void on_GaussianBlur(int, void *)
{
    cv::GaussianBlur(g_srcImage, g_dstImage3, cv::Size(g_nGaussianBlurValue*2 + 1, g_nGaussianBlurValue*2 + 1), 0, 0);
    cv::imshow("GaussianBlur", g_dstImage3);
}

你可能感兴趣的:(opencv)