文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

目标

在本教程中,您将学习如何应用各种线性滤波器以使用OpenCV函数平滑图像,如:

理论

Note

下面的解释属于Richard Szeliski所写的计算机视觉:算法与应用一书和LearningOpenCV

  • 平滑,也称为模糊,是简单且经常使用的图像处理操作。

  • 使用平滑的原因有很多。在本教程中,我们将关注使用平滑以减少噪声(其他用途将在以下教程中看到)。

  • 要执行平滑操作,我们将对图像应用滤波器。最常见类型的滤波器是线性的,其中输出像素值(即 g(i,j))由输入像素值(即f(i+k,j+l))的加权和计算:

    g(i,j) = \sum_{k,l} f(i+k, j+l) h(k,l)

    h(k,l) 称为内核,这只是滤波器的系数。

    它有助于将滤波器可视化为在图像上滑动的系数窗口。

  • 有很多种滤波器,这里我们会提到最常用的那些:

第 1 段(可获 2 积分)

归一化块滤波器

  • 这个过滤器是最简单的! 输出像素值是核窗口内像素值的 均值 ( 所有像素加权系数相等)

  • 核如下:

    K = \dfrac{1}{K_{width} \cdot K_{height}} \begin{bmatrix} 1 & 1 & 1 & ... & 1 \\ 1 & 1 & 1 & ... & 1 \\ . & . & . & ... & 1 \\ . & . & . & ... & 1 \\ 1 & 1 & 1 & ... & 1 \end{bmatrix}

高斯滤波器

  • 可能是最有用的过滤器(虽然不是最快的)。 高斯滤波是通过用高斯内核对输入数组中的每个点进行卷积,然后将它们相加产生输出数组来完成的。

  • 为了使图片更清晰, 还记得1维高斯函数的样子吗?

    ../../../../_images/Smoothing_Tutorial_theory_gaussian_0.jpg

    假设图像是1维的,您可以注意到中间像素的加权系数是最大的, 周边像素的加权系数随着它们远离中间像素的距离增大而逐渐减小。

第 2 段(可获 2 积分)

提示

2维高斯函数可以表达为:

G_{0}(x, y) = A e^{ \dfrac{ -(x - \mu_{x})^{2} }{ 2\sigma^{2}_{x} } + \dfrac{ -(y - \mu_{y})^{2} }{ 2\sigma^{2}_{y} } }

其中\mu 为均值 (峰值对应位置) \sigma 代表标准差 (变量 x 和 变量y各有一个均值,也各有一个标准差))

中值滤波器

中值滤波将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的 中值 代替 。

双边滤波 

  • 前我们了解的滤波器都是为了 平滑 图像, 问题是有些时候这些滤波器不仅仅削弱了噪声, 连带着把边缘也给磨掉了。 为避免这样的情形 (至少在一定程度上 ), 我们可以使用双边滤波。
  • 类似于高斯滤波器,双边滤波器也给每一个邻域像素分配一个加权系数。 这些加权系数包含两个部分, 第一部分加权方式与高斯滤波一样,第二部分的权重则取决于该邻域像素与当前像素的灰度差值。
  • 详细的解释可以查看 连接
第 3 段(可获 2 积分)

代码

  • 这个程序的主要用途:

    • 加载图片
    • 在图片上使用 4 中不同的过滤器进行处理并显示过滤后的结果
  • 可通过这里下载代码

  • 详细代码:

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

using namespace std;
using namespace cv;

/// Global Variables
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;

Mat src; Mat dst;
char window_name[] = "Filter Demo 1";

/// Function headers
int display_caption( char* caption );
int display_dst( int delay );

/**
 * function main
 */
 int main( int argc, char** argv )
 {
   namedWindow( window_name, CV_WINDOW_AUTOSIZE );

   /// Load the source image
   src = imread( "../images/lena.jpg", 1 );

   if( display_caption( "Original Image" ) != 0 ) { return 0; }

   dst = src.clone();
   if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; }

   /// Applying Homogeneous blur
   if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; }

   for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
       { blur( src, dst, Size( i, i ), Point(-1,-1) );
         if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }

    /// Applying Gaussian blur
    if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; }

    for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
        { GaussianBlur( src, dst, Size( i, i ), 0, 0 );
          if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }

     /// Applying Median blur
     if( display_caption( "Median Blur" ) != 0 ) { return 0; }

     for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
         { medianBlur ( src, dst, i );
           if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }

     /// Applying Bilateral Filter
     if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; }

     for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
         { bilateralFilter ( src, dst, i, i*2, i/2 );
           if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }

     /// Wait until user press a key
     display_caption( "End: Press a key!" );

     waitKey(0);
     return 0;
 }

 int display_caption( char* caption )
 {
   dst = Mat::zeros( src.size(), src.type() );
   putText( dst, caption,
            Point( src.cols/4, src.rows/2),
            CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );

   imshow( window_name, dst );
   int c = waitKey( DELAY_CAPTION );
   if( c >= 0 ) { return -1; }
   return 0;
  }

  int display_dst( int delay )
  {
    imshow( window_name, dst );
    int c = waitKey ( delay );
    if( c >= 0 ) { return -1; }
    return 0;
  }
第 4 段(可获 2 积分)

解释

  1. 下面看一看有关平滑的OpenCV函数,其余部分大家已经很熟了

  2. 归一化块滤波器:

    OpenCV函数 blur执行了归一化块平滑操作。

    for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
        { blur( src, dst, Size( i, i ), Point(-1,-1) );
          if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
    

    我们输入4个实参 (详细的解释请参考 Reference):

    • src: 输入图像
    • dst: 输出图像
    • Size( w,h ): 定义内核大小( w 像素宽度, h 像素高度)
    • Point(-1, -1): 指定锚点位置(被平滑点), 如果是负值,取核的中心为锚点。
  3. 高斯滤波器:

    OpenCV函数 GaussianBlur执行高斯平滑 :

    for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
        { GaussianBlur( src, dst, Size( i, i ), 0, 0 );
          if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
    

    我们输入4个实参 (详细的解释请参考 Reference):

    • src:输入图像
    • dst:输出图像
    • Size(w, h): 定义内核的大小(需要考虑的邻域范围)。wh 必须是正奇数,否则将使用  \sigma_{x}\sigma_{y} 参数来计算内核大小。
    • \sigma_{x}: x 方向标准方差, 如果是 0\sigma_{x} 使用内核大小计算得到。
    • \sigma_{y}: y 方向标准方差, 如果是 0 则  \sigma_{y}使用内核大小计算得到。
  4. 中值滤波器:

    OpenCV函数 medianBlur 执行中值滤波操作:

    for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
        { medianBlur ( src, dst, i );
          if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
    

    我们用了3个参数:

    • src: 输入图像
    • dst: 输出图像, 必须与 src 相同类型
    • i: 内核大小 (只需一个值,因为我们使用正方形窗口),必须为奇数。
  5. 双边滤波器

    OpenCV函数 bilateralFilter执行双边滤波操作:

    for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
        { bilateralFilter ( src, dst, i, i*2, i/2 );
          if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
    

    我们使用了5个参数:

    • src:  输入图像
    • dst:输出图像
    • d:像素的邻域直径
    • \sigma_{Color}: 颜色空间的标准方差
    • \sigma_{Space}:坐标空间的标准方差(像素单位)
第 5 段(可获 2 积分)

结果:

  • 此代码打开了 lena.jpg 图片,并显示经过 4 个过滤器过后后的效果。

第 6 段(可获 2 积分)

文章评论