zoukankan      html  css  js  c++  java
  • 【 imgproc 模块. 图像处理】图像平滑处理

    
    

    一、图像平滑

       本教程中,图像平滑处理主要有归一化块滤波器(Normalized Box Filter)、高斯滤波器(Gaussian Filter)、中值滤波器(Median Filter)、双边滤波器(Bilatera Filter)。

    二、归一化快滤波器(Normalized Box Filter)

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

     

    核如下:

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

     void blur(InputArray src, OutputArray dst, 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: 输出图像,深度和类型与输入图像一致 

        . Size ksize: 滤波模板kernel的尺寸,一般使用Size(w, h)来指定,如Size(3,3) 

        . Point anchor=Point(-1, -1): 字面意思是锚点,也就是处理的像素位于kernel的什么位置,默认值为(-1, -1)即位于kernel中心点,如果没有特殊需要则不需要更改 

        . int borderType=BORDER_DEFAULT: 用于推断图像外部像素的某种边界模式,有默认值BORDER_DEFAULT

    三、高斯滤波器(Gaussian Filter)

    • 最有用的滤波器 (尽管不是最快的)。 高斯滤波是将输入数组的每一个像素点与 高斯内核 卷积将卷积和当作输出像素值。

     

        1维高斯函数:

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

          假设图像是1维的,那么观察上图,不难发现中间像素的加权系数是最大的, 周边像素的加权系数随着它们远离中间像素的距离增大而逐渐减小。

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

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

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

      API:

    void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                                    double sigmaX, double sigmaY = 0,
                                    int borderType = BORDER_DEFAULT );

    四、中值滤波器(Median Filter)

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

         API:

    void medianBlur( InputArray src, OutputArray dst, int ksize );

    五、双边滤波器

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

              详细的解释可以查看 链接

         API:

    void bilateralFilter( InputArray src, OutputArray dst, int d,
                                       double sigmaColor, double sigmaSpace,
                                       int borderType = BORDER_DEFAULT );

    六、opencv例程

    #include "stdafx.h"
    
    /**
    * file Smoothing.cpp
    * brief Sample code for simple filters
    * author OpenCV team
    */
    
    #include <iostream>
    #include "opencv2/imgproc.hpp"
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    
    using namespace std;
    using namespace cv;
    
    /// Global Variables  全局变量
    int DELAY_CAPTION = 1500;//窗口延时,各个平滑模式切换的时间间隔
    int DELAY_BLUR = 100;//同一个滤波模式下 改变核大小时的时间间隔
    int MAX_KERNEL_LENGTH = 31;//核大小不超过31   正奇数
    
    Mat src; Mat dst;
    char window_name[] = "Smoothing Demo";
    
    /// Function headers
    int display_caption(const char* caption);
    int display_dst(int delay);
    
    
    /**
    * function main
    */
    int main(int argc, char ** argv)
    {
        namedWindow(window_name, WINDOW_AUTOSIZE); 
    
        /// Load the source image
        const char* filename = argc >= 2 ? argv[1] : "lena512color.tiff";
        /*argc,argv 用命令行编译程序时有用。
    主函数main中变量(int argc,char *argv[ ])的含义
    有些编译器允许将main()的返回类型声明为void,这已不再是合法的C++
    main(int argc, char *argv[ ], char **env)才是UNIX和Linux中的标准写法。
    argc: 整数,用来统计你运行程序时送给main函数的命令行参数的个数
    * argv[ ]: 指针数组,用来存放指向你的字符串参数的指针,每一个元素指向一个参数
    argv[0] 指向程序运行的全路径名
    argv[1] 指向在DOS命令行中执行程序名后的第一个字符串
    argv[2] 指向执行程序名后的第二个字符串
    ...
    argv[argc]为NULL。*/
    
        src = imread(filename, IMREAD_COLOR);
        if (src.empty())
        {
            /* if(img.empty())return -1; //是否加载成功
               if(!img.data)return -1;   //判断是否有数据*/
            printf(" Error opening image
    ");
            return -1;
        }
    
        if (display_caption("Original Image") != 0)
        {
            return 0;
        }
    
        dst = src.clone();
        /*clone 跟copyto的区别
         roi=src.clone();    //1
         src.copyTo(roi);    //2
    语句1:不管roi在之前有没有分配内存,clone都会为其分配新内存。如果roi指向某图像img的某个rect,此语句并不能实现对img(rect)的操作,clone分配新内存后,roi不再指向img(rect).
    语句2:如果roi在之前未分配内存,copyTo会为其分配新内存,若roi已分配内存,copyTo不再为其分配。
         结束:copyTo才是实现图像roi操作的途径啊。。。
    */
        if (display_dst(DELAY_CAPTION) != 0)
        {
            return 0;
        }
    
        /// Applying Homogeneous blur
        if (display_caption("Homogeneous Blur") != 0)
        {
            return 0;
        }
    
        //![blur]
        for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
        {
            blur(src, dst, Size(i, i), Point(-1, -1));
            /*参数:
    
    src:原图像。dst:目标图像。ksize:定义滤波器的大小。如Size(3,3)。
    anchor:指定锚点位置(被平滑点), 如果是负值,取核的中心为锚点。可省略
    borderType:推断边缘像素,一般取默认值BORDER_DEFAULT。可省略
    例:
    blur(src,dst,Size(3,3));*/
            if (display_dst(DELAY_BLUR) != 0)
            {
                return 0;
            }
        }
        //![blur]
    
        /// Applying Gaussian blur
        if (display_caption("Gaussian Blur") != 0)
        {
            return 0;
        }
    
        //![gaussianblur]
        /*参数:
        OpenCV2函数 GaussianBlur 执行高斯平滑,高斯滤波是将输入数组的每一个像素点与 高斯内核 卷积,将卷积和当作输出像素值。
        void GaussianBlur( const Mat& src, Mat& dst, Size ksize,double sigmaX, double sigmaY=0,int borderType=BORDER_DEFAULT );
        参数:
        sigmaX:x方向的标准方差。可设置为0让系统自动计算。
        sigmaY:y方向的标准方差。可设置为0让系统自动计算。
        例:
        GaussianBlur(src,dst,Size(9,9),0,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;
            }
        }
        //![gaussianblur]
    
        /// Applying Median blur
        if (display_caption("Median Blur") != 0)
        {
            return 0;
        }
    
        //![medianblur]
        /*OpenCV2函数 medianBlur 执行中值滤波操作,中值滤波将图像的每个像素用邻域 
        (以当前像素为中心的正方形区域)像素的 中值 代替 。*/
        for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
        {
            medianBlur(src, dst, i);
            if (display_dst(DELAY_BLUR) != 0)
            {
                return 0;
            }
        }
        //![medianblur]
    
        /// Applying Bilateral Filter
        if (display_caption("Bilateral Blur") != 0)
        {
            return 0;
        }
    
        //![bilateralfilter]
        /*OpenCV2函数 bilateralFilter 执行双边滤波操作,类似于高斯滤波器,双边滤波器也给每一个邻域像素分配一个加权系数。 这些加权系数包含两个部分, 第一部分加权方式与高斯滤波一样,第二部分的权重则取决于该邻域像素与当前像素的灰度差值。
    void bilateralFilter( const Mat& src, Mat& dst, int d,double sigmaColor, double sigmaSpace,int borderType=BORDER_DEFAULT );
    参数:
    d:像素的邻域直径。
    sigmaColor:颜色空间的标准方差.
    sigmaSpace:坐标空间的标准方差(像素单位).
    例:
    bilateralFilter ( src, dst, i, i*2, i/2 );*/
        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;
            }
        }
        //![bilateralfilter]
    
        /// Done
        display_caption("Done!");
    
        return 0;
    }
    
    /**
    * @function display_caption
    */
    int display_caption(const char* caption)
    {
        dst = Mat::zeros(src.size(), src.type());
        putText(dst, caption,
            Point(src.cols / 4, src.rows / 2),
            FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255));
    /*第一个参数是:需要写字的原图像,
    第二个:需要写的内容,string类型的;
    第三个:需要写的内容的左下角的坐标
    第五个:字体大小
    第六个:颜色
    第七个:字体的厚度
    第八个:默认8*/
    
        return display_dst(DELAY_CAPTION);
    }
    
    /**
    * @function display_dst
    */
    int display_dst(int delay)
    {
        imshow(window_name, dst);
        int c = waitKey(delay);
        if (c >= 0) { return -1; }
        return 0;
    }

    归ww一化块滤波器 (Normalized Box Filter)

    One day,I will say "I did it"
  • 相关阅读:
    如何轻松的把图片导入execl表格中
    把Execl表格中的数据获取出来保存到数据库中
    zookeeper系列之:独立模式部署zookeeper服务
    zookeeper系列之:zookeeper简介浅谈
    spark-shell启动spark报错
    大数据Hadoop学习之搭建hadoop平台(2.2)
    hbase系列之:独立模式部署hbase
    hbase系列之:初识hbase
    大数据Hadoop学习之搭建Hadoop平台(2.1)
    大数据Hadoop学习之了解Hadoop(1)
  • 原文地址:https://www.cnblogs.com/Vince-Wu/p/10070646.html
Copyright © 2011-2022 走看看