• OpenCV 之 图像平滑


    1  图像平滑

      图像平滑,一种图像空间滤波方法 (低通滤波),可对图像进行去噪 或 模糊化 (blurring)

      以 3X3 的滤波器为例 (即 a=b=1),则矩阵 Mx 和 Mf 对应的元素乘积之和,就是 g(x, y)

      其中,$ M_x = egin{bmatrix} w(-1,-1) & w(-1,0) & w(-1,1) \ w(0,-1) & w(0,0) & w(1,1) \ w(1,-1) & w(1,0) & w(1,1) \ end{bmatrix} qquad M_f = egin{bmatrix} f(x-1,y-1) & f(x-1,y) & f(x-1,y+1) \ f(x,y-1) & f(x,y) & f(x+1,y+1) \ f(x+1,y-1) & f(x+1,y) & f(x+1,y+1) \ end{bmatrix}$

    2  OpenCV 函数

      OpenCV 中主要有四个函数,分别是盒式滤波 (box),高斯滤波 (Gaussian),中值滤波 (median),双边滤波 (bilateral)

    2.1  盒式滤波

     2.1.1 boxFilter

     输出图像的任一像素灰度值,等于其所有邻域像素灰度值的平均值

      模糊化核为,$ K = alpha egin{bmatrix}  1 & 1 & ... & 1 & 1 \ 1 & 1 & ... & 1 & 1 \ : & : & ... & & & \ 1 & 1 & ... & 1 & 1 end{bmatrix} $  其中,$alpha = egin{cases} frac{1}{ksize.width * ksize.height} & ext{when normalize = true} \  1 & ext{otherwise} \ end{cases} $

    void cv::boxFilter (     
        InputArray   src, // 输入图像
        OutputArray  dst, // 输出图像
        int    ddepth,      // 输出图像深度,-1 表示等于 src.depth()
        Size   ksize,       // 模糊化核 (kernel) 的大小
        Point  anchor = Point(-1,-1),       // 锚点位置,缺省值表示 anchor 位于模糊核的正中心
        bool   normalize = true,            // 是否归一化处理
        int    borderType = BORDER_DEFAULT  // 边界模式
    )

    2.1.2  blur

      取 ddepth = -1,normalize = true,则可由 boxFilter 得到模糊化函数 (blur)

    boxFilter( src, dst, -1, ksize, anchor, true, borderType );

      blur 本质上是一个输入和输出图像深度 (ddepth) 相同,并且做归一化处理的盒式滤波器

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

    2.2  中值滤波

      中值滤波最为简单,常用来消除椒盐噪声。输出图像 g (x, y)  的像素值,等于以输入图像 f (x, y) 为中心点的邻域像素 (ksize x ksize) 平均值

    void cv::medianBlur ( 
        InputArray   src,
        OutputArray  dst,
        int  ksize   // 滤波器孔径大小,一般为奇数且大于 1,比如 3, 5, 7, ...
    )     

    2.3  高斯滤波

      高斯滤波最为有用,它是根据当前像素和邻域像素之间,空间距离的不同,计算得出一个高斯核 (邻域像素的加权系数),

      然后,高斯核从左至右、从上到下遍历输入图像,与输入图像的像素值求卷积和,得到输出图像的各个像素值

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

      无须理会公式的复杂,只需要记住一点即可:邻域像素距离当前像素越远 (saptial space),则其相应的加权系数越小

      为了便于直观理解,可看下面这个一维高斯核,推而广之将 G(x) 曲线以 x=0 这条轴为中心线,旋转360度可想象其二维高斯核

       

    void cv::GaussianBlur ( 
        InputArray   src, 
        OutputArray  dst,
        Size    ksize,       // 高斯核的大小
        double  sigmaX,      // 高斯核在x方向的标准差
        double  sigmaY = 0,  // 高斯核在y方向的标准差,缺省为 0,表示 sigmaY = sigmaX
        int     borderType = BORDER_DEFAULT 
    )  

      注意: 高斯核的大小 Size(width, height),w 和 h 二者不必相同但必须都是奇数,若都设为 0,则从 sigma 自动计算得出

    2.4  双边滤波

      上面三种方法都是低通滤波,因此在消除噪声的同时,也常会将边缘信息模糊化。双边滤波和高斯滤波类似,但是它将邻域像素的加权系数分为两部分,

      第一部分与高斯滤波的完全相同,第二部分则考虑当前像素和邻域像素之间灰度值的差异,从而在消除噪声的基础上,也较好的保留了图像的边缘信息

    void cv::bilateralFilter (
        InputArray    src,
        OutputArray   dst,
        int     d,    // 像素邻域直径,若为非正值,则从 sigmaSpace 自动计算得出
        double  sigmaColor,  // 颜色空间的标注方差
        double  sigmaSpace,  // 坐标空间的标准方差
        int     borderType = BORDER_DEFAULT 
    )

       注意 1)  双边滤波相比以上三种滤波方法,其处理速度很慢,因此,一般建议取 d=5 用于实时图像处理,d=9 适合于非实时的图像领域

       注意 2)  sigmaColor 和 sigmaSpace 可取相同值,一般在 10 ~ 150 之间,小于 10,则没什么效果,大于 150,则效果太强烈,看起来明显“卡通化”

    3  代码示例

    3.1 OpenCV

      OpenCV 中的示例,通过逐渐增大像素邻域的大小 Size(w, h),将上述滤波过程动态化,非常形象的展示了邻域大小对滤波效果的影响

      代码摘抄

      1 /**
      2  * file Smoothing.cpp
      3  * brief Sample code for simple filters
      4  * author OpenCV team
      5  */
      6 #include <iostream>
      7 #include <vector>
      8 
      9 #include "opencv2/imgproc/imgproc.hpp"
     10 #include "opencv2/imgcodecs.hpp"
     11 #include "opencv2/highgui/highgui.hpp"
     12 #include "opencv2/features2d/features2d.hpp"
     13 
     14 using namespace std;
     15 using namespace cv;
     16 
     17 /// Global Variables
     18 int DELAY_CAPTION = 1500;
     19 int DELAY_BLUR = 100;
     20 int MAX_KERNEL_LENGTH = 31;
     21 
     22 Mat src; Mat dst;
     23 char window_name[] = "Smoothing Demo";
     24 
     25 /// Function headers
     26 int display_caption( const char* caption );
     27 int display_dst( int delay );
     28 
     29 
     30 /**
     31  * function main
     32  */
     33 int main( void )
     34 {
     35   namedWindow( window_name, WINDOW_AUTOSIZE );
     36 
     37   /// Load the source image
     38   src = imread( "../data/lena.jpg", 1 );
     39 
     40   if( display_caption( "Original Image" ) != 0 ) { return 0; }
     41 
     42   dst = src.clone();
     43   if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; }
     44 
     45 
     46   /// Applying Homogeneous blur
     47   if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; }
     48 
     49   for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
     50       { blur( src, dst, Size( i, i ), Point(-1,-1) );
     51         if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
     52 
     53 
     54   /// Applying Gaussian blur
     55   if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; }
     56 
     57   for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
     58       { GaussianBlur( src, dst, Size( i, i ), 0, 0 );
     59         if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
     60 
     61 
     62   /// Applying Median blur
     63   if( display_caption( "Median Blur" ) != 0 ) { return 0; }
     64 
     65   for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
     66       { medianBlur ( src, dst, i );
     67         if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
     68 
     69 
     70   /// Applying Bilateral Filter
     71   if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; }
     72 
     73   for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
     74       { bilateralFilter ( src, dst, i, i*2, i/2 );
     75         if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
     76 
     77   /// Wait until user press a key
     78   display_caption( "End: Press a key!" );
     79 
     80   waitKey(0);
     81 
     82   return 0;
     83 }
     84 
     85 /**
     86  * @function display_caption
     87  */
     88 int display_caption( const char* caption )
     89 {
     90   dst = Mat::zeros( src.size(), src.type() );
     91   putText( dst, caption,
     92            Point( src.cols/4, src.rows/2),
     93            FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );
     94 
     95   imshow( window_name, dst );
     96   int c = waitKey( DELAY_CAPTION );
     97   if( c >= 0 ) { return -1; }
     98   return 0;
     99 }
    100 
    101 /**
    102  * @function display_dst
    103  */
    104 int display_dst( int delay )
    105 {
    106   imshow( window_name, dst );
    107   int c = waitKey ( delay );
    108   if( c >= 0 ) { return -1; }
    109   return 0;
    110 }
    View Code

    3.2  滤波对比

      实际中,可直接调用以上四个滤波函数,代码如下:

     1 #include "opencv2/imgproc/imgproc.hpp"
     2 #include "opencv2/highgui/highgui.hpp"
     3 
     4 using namespace cv;
     5 
     6 int main()
     7 {
     8     Mat src = imread("E:/smooth/bird.jpg");
     9     if(src.empty()) {
    10         return -1;
    11     }
    12     imshow("original", src);
    13 
    14     Mat dst;
    15 
    16     blur(src, dst, Size(3,3));
    17     imshow("blur", dst);
    18 
    19     medianBlur(src,dst,3);
    20     imshow("medianBlur",dst);
    21 
    22     GaussianBlur(src,dst,Size(3,3),0);
    23     imshow("GaussianBlur",dst);
    24 
    25     bilateralFilter(src,dst,9,50,50);
    26     imshow("bilateralFilter",dst);
    27 
    28     waitKey(0);
    29 }
    

      四种滤波方法的效果图,如下所示:

     

    参考资料

     <Digital Image Processing> 3rd, chapter 3

     <Learning OpenCV3>

     OpenCV Tutorials Image Processing (imgproc module) Smoothing Images

     图像卷积与滤波的一些知识点,zouxy09

  • 相关阅读:
    汽车加油问题--贪心算法
    区间相交问题---贪心算法
    算法-动态规划-数字三角问题
    jar转成exe
    kafka zookeeper学习(2) 测试kafka与zookeeper环境
    kafka zookeeper学习(1) windows搭建kafka与zookeeper环境
    java调用linux系统命令
    linux hg(mercurial)入门
    redis集群构建过程 linux windows
    Java JTextArea不能实时刷新的问题
  • 原文地址:https://www.cnblogs.com/xinxue/p/5436286.html
Copyright © 2020-2023  润新知