Opencv3笔记9——线性滤波

1 线性滤波

1.1 平滑处理

平滑处理(smoothing)也称模糊处理(bluring),常用于减少图像上的噪点或者失真,降低图像分辨率

1.2 图像滤波与滤波器

目的:

  • 抽出对象的特征作为图像识别的特征模式适应图像处理的要求
  • 消除图像数字化混入的噪声

要求:

  • 不能损坏图像的轮廓及边缘等重要的信息
  • 图像清晰视觉效果好
    平滑滤波的目的:
  • 模糊消除噪声
    空间域平滑滤波:简单平均法,就是求邻近像元点的平均亮度值,邻域越大效果越好,但是过大会使边缘信息损失过大。
    滤波器:可以把滤波器想像为一个加权系数的窗口
    常用的方法:
  • 方框滤波:Boxblur函数
  • 均值滤波(邻域平均滤波):Blur函数
  • 高斯滤波:GaussianBlur函数
  • 中值滤波:medianBlur函数
  • 双边滤波:bilateralFilter函数

1.3 线性滤波器

低通滤波器:低频通过
高通滤波器:高频通过
带通滤波器:允许一定的频率通过
带阻滤波器:阻止一定的频率不通过
全通滤波器:频率都通过,仅改变相位
险波滤波器(Band-Stop Filter):阻止一个狭窄频率范围通过

1.4 邻域算子与线性领域滤波

输出像素值 g ( i , j ) 时输入像素值 f ( i + k , j + I ) 的加权和

g ( i , j ) = k , I f ( i + k , j + I ) h ( k , I )

h ( k , I ) 我们称之为==核==,是滤波器的加权系数

g = f h

1.5 方框滤波(box Filter)

void boxFilter(InputArray src,OutputArray dst,int ddepth,Size ksize, Point anchor = Point(-1,-1),boolnormalize = true,int borderType = BORDER_DEFAULT)
  • InputArray类型的src,输入图像,为==CV_8U,CV_16U,CV_16S,CV_32F,CV_64F==之一
  • OutputArray类型的dst,需要和源图片有一样的尺寸和类型
  • int类型的ddepth输出图像的深度,-1表示使用原图的深度
  • Size类型的ksize,内核的大小
  • Point类型的anchor,表示锚点(平滑的点),Point(-1,-1)表示取核的中心为锚点
  • 表示内在是否被其区域归一化
  • 推断图像外部像素的某种边界模式

K = a [ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ]

a = { 1 k s i z e . w i d t h × k s i z e . h e i g h n o r m a l i z e = t u r e 1 n o r m a l i z e = f a l s e

1.6 均值滤波

理论分析

g ( x , y ) = 1 m f ( x , y )

m为模板中包含当前像素在内的像素的个数

缺陷

不能保护图像细节,在图像去噪的同时也破坏图像的细节

blur函数

==作用==:对输入图像src进行均值滤波后用dst输出

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

类型同上

1.7 高斯滤波

理论

其视觉效果就像经过一个半透明屏幕在观察图像,图像的高斯模糊过程就是图像与正态分布做卷积。高斯函数的傅里叶变换就是另一个高斯函数,所以高斯模糊是一个低通滤波操作。

一维零均值高斯函数

G ( x ) = e x 2 2 s i g m a 2

二维高斯函数

G 0 ( x , y ) = A e ( x u x ) 2 2 σ x 2 ( y u y ) 2 2 σ y 2

GaussianBlur函数

void GaussianBlur(InputArray src, OutputArray dst,Size ksize,double sigmaX,double sigmaY = 0,intborderType = BORDER_DEFAULT)
  • double 类型的sigmaX,表示高斯核函数在X方向的标准偏差
  • double类型的sigmaY,表示高斯核函数在Y方向的标准偏差

1.8 Opencv源码

1. boxFilter函数源码

void cv::boxFilter( InputArray _src, OutputArray _dst, int ddepth,
                Size ksize, Point anchor,
                bool normalize, int borderType )
{
    CV_INSTRUMENT_REGION()

    CV_OCL_RUN(_dst.isUMat() &&
               (borderType == BORDER_REPLICATE || borderType == BORDER_CONSTANT ||
                borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101),
               ocl_boxFilter3x3_8UC1(_src, _dst, ddepth, ksize, anchor, borderType, normalize))

    CV_OCL_RUN(_dst.isUMat(), ocl_boxFilter(_src, _dst, ddepth, ksize, anchor, borderType, normalize))

    Mat src = _src.getMat();//复制原图到到临时变量
    int stype = src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
    //处理ddepth小于零的情况
    if( ddepth < 0 )
        ddepth = sdepth;
    _dst.create( src.size(), CV_MAKETYPE(ddepth, cn) );
    Mat dst = _dst.getMat();
    if( borderType != BORDER_CONSTANT && normalize && (borderType & BORDER_ISOLATED) != 0 )
    {
        if( src.rows == 1 )
            ksize.height = 1;
        if( src.cols == 1 )
            ksize.width = 1;
    }

    Point ofs;
    Size wsz(src.cols, src.rows);
    if(!(borderType&BORDER_ISOLATED))
        src.locateROI( wsz, ofs );

    CALL_HAL(boxFilter, cv_hal_boxFilter, src.ptr(), src.step, dst.ptr(), dst.step, src.cols, src.rows, sdepth, ddepth, cn,
             ofs.x, ofs.y, wsz.width - src.cols - ofs.x, wsz.height - src.rows - ofs.y, ksize.width, ksize.height,
             anchor.x, anchor.y, normalize, borderType&~BORDER_ISOLATED);

    CV_OVX_RUN(true,
               openvx_boxfilter(src, dst, ddepth, ksize, anchor, normalize, borderType))

    CV_IPP_RUN_FAST(ipp_boxfilter(src, dst, ksize, anchor, normalize, borderType));

    borderType = (borderType&~BORDER_ISOLATED);

    Ptr<FilterEngine> f = createBoxFilter( src.type(), dst.type(),
                        ksize, anchor, normalize, borderType );

    f->apply( src, dst, wsz, ofs );
}

2. GauusianBlur函数

void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
                   double sigma1, double sigma2,
                   int borderType )
{
    CV_INSTRUMENT_REGION()

    int type = _src.type();
    Size size = _src.size();
    _dst.create( size, type );

    if( (borderType & ~BORDER_ISOLATED) != BORDER_CONSTANT &&
        ((borderType & BORDER_ISOLATED) != 0 || !_src.getMat().isSubmatrix()) )
    {
        if( size.height == 1 )
            ksize.height = 1;
        if( size.width == 1 )
            ksize.width = 1;
    }

    if( ksize.width == 1 && ksize.height == 1 )
    {
        _src.copyTo(_dst);
        return;
    }

    bool useOpenCL = (ocl::isOpenCLActivated() && _dst.isUMat() && _src.dims() <= 2 &&
               ((ksize.width == 3 && ksize.height == 3) ||
               (ksize.width == 5 && ksize.height == 5)) &&
               _src.rows() > ksize.height && _src.cols() > ksize.width);
    (void)useOpenCL;

    int sdepth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);

    if(sdepth == CV_8U && ((borderType & BORDER_ISOLATED) || !_src.getMat().isSubmatrix()))
    {
        std::vector<ufixedpoint16> fkx, fky;
        createGaussianKernels(fkx, fky, type, ksize, sigma1, sigma2);
        Mat src = _src.getMat();
        Mat dst = _dst.getMat();
        if (src.data == dst.data)
            src = src.clone();
        fixedSmoothInvoker<uint8_t, ufixedpoint16> invoker(src.ptr<uint8_t>(), src.step1(), dst.ptr<uint8_t>(), dst.step1(), dst.cols, dst.rows, dst.channels(), &fkx[0], (int)fkx.size(), &fky[0], (int)fky.size(), borderType & ~BORDER_ISOLATED);
        parallel_for_(Range(0, dst.rows), invoker, std::max(1, std::min(getNumThreads(), getNumberOfCPUs())));
        return;
    }


    Mat kx, ky;
    createGaussianKernels(kx, ky, type, ksize, sigma1, sigma2);

    CV_OCL_RUN(useOpenCL, ocl_GaussianBlur_8UC1(_src, _dst, ksize, CV_MAT_DEPTH(type), kx, ky, borderType));

    CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 && (size_t)_src.rows() > kx.total() && (size_t)_src.cols() > kx.total(),
               ocl_sepFilter2D(_src, _dst, sdepth, kx, ky, Point(-1, -1), 0, borderType))

    Mat src = _src.getMat();
    Mat dst = _dst.getMat();

    Point ofs;
    Size wsz(src.cols, src.rows);
    if(!(borderType & BORDER_ISOLATED))
        src.locateROI( wsz, ofs );

    CALL_HAL(gaussianBlur, cv_hal_gaussianBlur, src.ptr(), src.step, dst.ptr(), dst.step, src.cols, src.rows, sdepth, cn,
             ofs.x, ofs.y, wsz.width - src.cols - ofs.x, wsz.height - src.rows - ofs.y, ksize.width, ksize.height,
             sigma1, sigma2, borderType&~BORDER_ISOLATED);

    CV_OVX_RUN(true,
               openvx_gaussianBlur(src, dst, ksize, sigma1, sigma2, borderType))

    CV_IPP_RUN_FAST(ipp_GaussianBlur(src, dst, ksize, sigma1, sigma2, borderType));

    sepFilter2D(src, dst, sdepth, kx, ky, Point(-1, -1), 0, borderType);
}

1.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;
    boxFilter(image, out, -1, Size(5, 5));

    //显示效果图
    imshow("均值滤波【效果图】", out);
    waitKey(0);
    return 0;
}

这里写图片描述

均值滤波

//---------------------------【头文件、命名空间】----------
//  描述:包含程序所需要头文件和命名空间
//------------------------------------------------------
#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;
    blur(image, out, -1, Size(7, 7));

    //显示效果图
    imshow("均值滤波【效果图】", out);
    waitKey(0);
    return 0;
}

这里写图片描述

高斯滤波

//---------------------------【头文件、命名空间】----------
//  描述:包含程序所需要头文件和命名空间
//------------------------------------------------------
#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;
    GaussianBlur(image, out, Size(3, 3),0,0);

    //显示效果图
    imshow("高斯滤波【效果图】", out);
    waitKey(0);
    return 0;
}

这里写图片描述

1.10 综合示例

//---------------------------【头文件、命名空间】----------
//  描述:包含程序所需要头文件和命名空间
//------------------------------------------------------
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

//---------------------------【全局变量声明部分】-----------------
//  描述:全局变量声明
//-------------------------------------------------------------

// 存储图片的Mat类型
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 *);   //高斯滤波

//---------------------------【main函数】----------------
//  描述:控制台应用程序入口函数
//------------------------------------------------------
int main()
{
    //改变console字体颜色
    system("color5E");

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


    //复制原图
    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_BoxFilter(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";

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

    waitKey(0);
    return 0;
}

//----------------------------【on_BoxFilter()函数】-------------------
//  描述:方框滤波操作的回调函数
//--------------------------------------------------------------------

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

//----------------------------【on_MeanBlur()函数】-------------------
//  描述:均值滤波操作的回调函数
//--------------------------------------------------------------------

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

//----------------------------【on_GaussianBlur()函数】-------------------
//  描述:高斯滤波操作的回调函数
//--------------------------------------------------------------------

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

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

猜你喜欢

转载自blog.csdn.net/huayunhualuo/article/details/81486836