zoukankan      html  css  js  c++  java
  • 高斯滤波

    高斯滤波器 (Gaussian Filter)

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

    • 还记得1维高斯函数的样子吗?

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

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

    Note

    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 各有一个均值,也各有一个标准差)。

     

    高斯滤波的实现比较简单,opencv和matlab均有函数实现,参看图像处理之滤波器

    这里有一个简单的例子对比:

    #include <opencv2/opencv.hpp>
    #include <vector>
    using namespace std;
    using namespace cv;
    void OpenCv_Gauss_Test()
    {
        Mat src = imread("lena.jpg", 0);
    
        int scale = 1;
        resize(src, src, Size(src.cols * scale, src.rows*scale));
        Mat dst = src.clone();
        cout << src.cols << "*" << src.rows << " " << src.rows * src.cols / 10000 << "M" << endl;
        int ksize = 11;
        GaussianBlur(src, dst, Size(ksize, ksize), 0, 0);
        namedWindow("dstopencv");
        imshow("dstopencv",dst);
    }
    
    void mygausstest()
    {
        Mat src = imread("lena.jpg", 0);
    
        int scale = 1;
        resize(src, src, Size(src.cols * scale, src.rows*scale));
        Mat dst = src.clone();
        cout << src.cols << "*" << src.rows << " " << src.rows * src.cols / 10000 << "M" << endl;
        int ksize = 11;
        int step = ksize / 2;
        int m = src.rows - step * 2 - 1;
        int n = src.cols - step * 2 - 1;
        float sigma = 0.3*((ksize - 1)*0.5 - 1) + 0.8;
        Mat  gausskernel = getGaussianKernel(ksize, sigma, CV_64F);
        Mat showkernel = gausskernel*gausskernel.t();
        for (int i = step + 1; i < m; ++i)
        {
            for (int j = step + 1; j < n; ++j)
            {
                Mat sub =src(Range(i - step, i + step + 1), Range(j - step, j + step + 1));
                sub.convertTo(sub, CV_64F);
                dst.at<uchar>(i, j) = cv::sum(sub.mul(showkernel))[0];
            }
        }
        namedWindow("src");
        namedWindow("dst");
        imshow("src", src);
        imshow("dst", dst);
        waitKey(0);
    }
    
    void main()
    {
        OpenCv_Gauss_Test();
        mygausstest();
    }

    这里主要讨论高斯滤波的优化加速问题。

     

    参考:

    http://blog.csdn.net/app_12062011/article/details/27082049

    http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.html

    http://homepages.inf.ed.ac.uk/rbf/HIPR2/gsmooth.htm

    http://blog.csdn.net/app_12062011/article/details/27082049

    IIR高斯递归滤波器

    http://blog.csdn.net/bluecol/article/details/45584065 (IIR高斯滤波器)

    http://q.cnblogs.com/q/54532/

    http://www.cnblogs.com/Imageshop/archive/2013/01/07/2849782.html

    gimp源码

    /*
     * Calculate the coefficients for the recursive filter algorithm
     * Fast Computation of gaussian blurring.
     */
    static void
    compute_coefs3 (gauss3_coefs *c, gfloat sigma)
    {
      /*
       * Papers:  "Recursive Implementation of the gaussian filter.",
       *          Ian T. Young , Lucas J. Van Vliet, Signal Processing 44, Elsevier 1995.
       * formula: 11b       computation of q
       *          8c        computation of b0..b1
       *          10        alpha is normalization constant B
       */
      gfloat q, q2, q3;
    
      q = 0;
    
      if (sigma >= 2.5)
        {
          q = 0.98711 * sigma - 0.96330;
        }
      else if ((sigma >= 0.5) && (sigma < 2.5))
        {
          q = 3.97156 - 4.14554 * (gfloat) sqrt ((double) 1 - 0.26891 * sigma);
        }
      else
        {
          q = 0.1147705018520355224609375;
        }
    
      q2 = q * q;
      q3 = q * q2;
      c->b[0] = (1.57825+(2.44413*q)+(1.4281 *q2)+(0.422205*q3));
      c->b[1] = (        (2.44413*q)+(2.85619*q2)+(1.26661 *q3));
      c->b[2] = (                   -((1.4281*q2)+(1.26661 *q3)));
      c->b[3] = (                                 (0.422205*q3));
      c->B = 1.0-((c->b[1]+c->b[2]+c->b[3])/c->b[0]);
      c->sigma = sigma;
      c->N = 3;
    }
    
    
    static void
    gausssmooth (gfloat *in, gfloat *out, gint size, gint rowstride, gauss3_coefs *c)
    {
      /*
       * Papers:  "Recursive Implementation of the gaussian filter.",
       *          Ian T. Young , Lucas J. Van Vliet, Signal Processing 44, Elsevier 1995.
       * formula: 9a        forward filter
       *          9b        backward filter
       *          fig7      algorithm
       */
      gint i,n, bufsize;
      gfloat *w1,*w2;
    
      /* forward pass */
      bufsize = size+3;
      size -= 1;
      w1 = (gfloat *) g_try_malloc (bufsize * sizeof (gfloat));
      w2 = (gfloat *) g_try_malloc (bufsize * sizeof (gfloat));
      w1[0] = in[0];
      w1[1] = in[0];
      w1[2] = in[0];
      for ( i = 0 , n=3; i <= size ; i++, n++)
        {
          w1[n] = (gfloat)(c->B*in[i*rowstride] +
                           ((c->b[1]*w1[n-1] +
                             c->b[2]*w1[n-2] +
                             c->b[3]*w1[n-3] ) / c->b[0]));
        }
    
      /* backward pass */
      w2[size+1]= w1[size+3];
      w2[size+2]= w1[size+3];
      w2[size+3]= w1[size+3];
      for (i = size, n = i; i >= 0; i--, n--)
        {
          w2[n]= out[i * rowstride] = (gfloat)(c->B*w1[n] +
                                               ((c->b[1]*w2[n+1] +
                                                 c->b[2]*w2[n+2] +
                                                 c->b[3]*w2[n+3] ) / c->b[0]));
        }
    
      g_free (w1);
      g_free (w2);
    }

    opencv下面实现IIR高斯滤波器

    #include <opencv2/opencv.hpp>
    using namespace cv;
    using namespace std;
    
    #include "Timer.h"
    Timer timer;        //    timer
    double elapsedTime;    //    time in millisecond
    double  avgtime = 0;
    double testnum = 0;
    void timebegin()
    {
        timer.start();
    }
    
    void timeend(string str)
    {
        elapsedTime = timer.getElapsedTimeInMilliSec();
        avgtime += elapsedTime;
        str = str + "time is: ";// %lf ms
    ";
        cout << str << elapsedTime << "ms" << endl;
    }
    
    /****************************************
    *    src        : 原始图像数据                *
    *    dst        : 模糊后图像数据            *
    *    width    : 图像宽                    *
    *    height    : 图像高                    *
    *    sigma    : 高斯参数                    *
    *    chan    : 图像通道数                *
    *****************************************/
    void IMG_GaussBlur(unsigned char* src, unsigned char*& dst, int width, int height, float sigma, int chan)
    {
        int    i = 0;
        int    row = 0;
        int    col = 0;
        int    pos = 0;
        int    channel = 0;
        int    n = 0;
        int    bufsize = 0;
        int size = 0;
        int rowstride = 0;
        int    channelsize = width*height;
    
        if (width > height)
        {
            bufsize = width + 3;
        }
        else
        {
            bufsize = height + 3;
        }
    
        float* w1 = (float *)malloc(bufsize * sizeof (float));
        float *w2 = (float *)malloc(bufsize * sizeof (float));
        float *in = (float *)malloc(channelsize * sizeof (float));
        float *out = (float *)malloc(channelsize * sizeof (float));
    
        //----------------计算高斯核---------------------------------------//
        //compute_coefs3(coef, sigma);    
        float  q = 0;
        float  q2, q3;
        double b[4] = { 0 };
        double B = 0;
        int    N = 3;
    
        if (sigma >= 2.5)
        {
            q = 0.98711 * sigma - 0.96330;
        }
        else if ((sigma >= 0.5) && (sigma < 2.5))
        {
            q = 3.97156 - 4.14554 * (float)sqrt((double)1 - 0.26891 * sigma);
        }
        else
        {
            q = 0.1147705018520355224609375;
        }
    
        q2 = q * q;
        q3 = q * q2;
        b[0] = (1.57825 + (2.44413*q) + (1.4281 *q2) + (0.422205*q3));
        b[1] = ((2.44413*q) + (2.85619*q2) + (1.26661 *q3));
        b[2] = (-((1.4281*q2) + (1.26661 *q3)));
        b[3] = ((0.422205*q3));
        B = 1.0 - ((b[1] + b[2] + b[3]) / b[0]);
        //----------------计算高斯核结束---------------------------------------//
    
        // 处理图像的多个通道
        for (channel = 0; channel < chan; channel++)
        {
            // 获取一个通道的所有像素值
            for (i = 0, pos = channel; i < channelsize; i++, pos += chan)
            {
                /* 0-255 => 1-256 */
                in[i] = (float)(src[pos] + 1.0);
            }
    
            //纵向处理
            for (row = 0; row < height; row++)
            {
                pos = row * width;
                //gausssmooth(in + pos, out + pos, width, 1, &coef);
                size = width;
                rowstride = 1;
                bufsize = size + 3;
                size -= 1;
    
                w1[0] = (in + pos)[0];
                w1[1] = (in + pos)[0];
                w1[2] = (in + pos)[0];
    
                for (i = 0, n = 3; i <= size; i++, n++)
                {
                    w1[n] = (float)(B*(in + pos)[i*rowstride] +
                        ((b[1] * w1[n - 1] +
                        b[2] * w1[n - 2] +
                        b[3] * w1[n - 3]) / b[0]));
                }
    
                /** backward pass */
                w2[size + 1] = w1[size + 3];
                w2[size + 2] = w1[size + 3];
                w2[size + 3] = w1[size + 3];
                for (i = size, n = i; i >= 0; i--, n--)
                {
                    w2[n] = (out + pos)[i * rowstride] = (float)(B*w1[n] +
                        ((b[1] * w2[n + 1] +
                        b[2] * w2[n + 2] +
                        b[3] * w2[n + 3]) / b[0]));
                }
            }
    
            //下面的横向处理直接将数据 out 与 in 对调 省去memcpy
            //memcpy(in,  out, channelsize * sizeof(float));
            //memset(out, 0  , channelsize * sizeof(float));
    
            //横向处理
            for (col = 0; col < width; col++)
            {
                //gausssmooth(out + col, in + col, height, width, &coef);            
                size = height;
                rowstride = width;
                bufsize = size + 3;
                size -= 1;
    
                w1[0] = (out + col)[0];
                w1[1] = (out + col)[0];
                w1[2] = (out + col)[0];
                for (i = 0, n = 3; i <= size; i++, n++)
                {
                    w1[n] = (float)(B*(out + col)[i*rowstride] +
                        ((b[1] * w1[n - 1] +
                        b[2] * w1[n - 2] +
                        b[3] * w1[n - 3]) / b[0]));
                }
    
                w2[size + 1] = w1[size + 3];
                w2[size + 2] = w1[size + 3];
                w2[size + 3] = w1[size + 3];
                for (i = size, n = i; i >= 0; i--, n--)
                {
                    w2[n] = (in + col)[i * rowstride] = (float)(B*w1[n] +
                        ((b[1] * w2[n + 1] +
                        b[2] * w2[n + 2] +
                        b[3] * w2[n + 3]) / b[0]));
                }
            }
    
            //拷贝结果到函数输出指针
            for (i = 0, pos = channel; i < channelsize; i++, pos += chan)
            {
                dst[pos] = in[i] - 1;
            }
        }
    
        free(w1);
        free(w2);
        free(in);
        free(out);
    }
    
    void main()
    {
        Mat src = imread("src.jpg");
        Mat dst1 = src.clone();
        Mat dst2 = src.clone();
        float sigma = 15.0;
        timebegin();
        IMG_GaussBlur(src.data, dst1.data, src.cols, src.rows, sigma, 3);
        timeend("IIR_GAUSS");
    
        int ksize = 71;
        timebegin();
        GaussianBlur(src, dst2, Size(ksize,ksize),0, 0);
        timeend("OPNECV_GAUSS");
    
        //namedWindow("src",0);
        namedWindow("dst1",0);
        namedWindow("dst2",0);
        //imshow("src", src);
        imshow("dst1", dst1);
        imshow("dst2", dst2);
        waitKey(0);
    }

    附加 测试时间的函数代码,这个代码可以在linux以及windows下面通用,也可以参看博文:
    Time.cpp

    //////////////////////////////////////////////////////////////////////////////
    // Timer.cpp
    // =========
    // High Resolution Timer.
    // This timer is able to measure the elapsed time with 1 micro-second accuracy
    // in both Windows, Linux and Unix system 
    //
    //  AUTHOR: Song Ho Ahn (song.ahn@gmail.com)
    // CREATED: 2003-01-13
    // UPDATED: 2006-01-13
    //
    // Copyright (c) 2003 Song Ho Ahn
    //////////////////////////////////////////////////////////////////////////////
    
    #include "Timer.h"
    #include <stdlib.h>
    
    ///////////////////////////////////////////////////////////////////////////////
    // constructor
    ///////////////////////////////////////////////////////////////////////////////
    Timer::Timer()
    {
    #ifdef WIN32
        QueryPerformanceFrequency(&frequency);
        startCount.QuadPart = 0;
        endCount.QuadPart = 0;
    #else
        startCount.tv_sec = startCount.tv_usec = 0;
        endCount.tv_sec = endCount.tv_usec = 0;
    #endif
    
        stopped = 0;
        startTimeInMicroSec = 0;
        endTimeInMicroSec = 0;
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // distructor
    ///////////////////////////////////////////////////////////////////////////////
    Timer::~Timer()
    {
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // start timer.
    // startCount will be set at this point.
    ///////////////////////////////////////////////////////////////////////////////
    void Timer::start()
    {
        stopped = 0; // reset stop flag
    #ifdef WIN32
        QueryPerformanceCounter(&startCount);
    #else
        gettimeofday(&startCount, NULL);
    #endif
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // stop the timer.
    // endCount will be set at this point.
    ///////////////////////////////////////////////////////////////////////////////
    void Timer::stop()
    {
        stopped = 1; // set timer stopped flag
    
    #ifdef WIN32
        QueryPerformanceCounter(&endCount);
    #else
        gettimeofday(&endCount, NULL);
    #endif
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // compute elapsed time in micro-second resolution.
    // other getElapsedTime will call this first, then convert to correspond resolution.
    ///////////////////////////////////////////////////////////////////////////////
    double Timer::getElapsedTimeInMicroSec()
    {
    #ifdef WIN32
        if(!stopped)
            QueryPerformanceCounter(&endCount);
    
        startTimeInMicroSec = startCount.QuadPart * (1000000.0 / frequency.QuadPart);
        endTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart);
    #else
        if(!stopped)
            gettimeofday(&endCount, NULL);
    
        startTimeInMicroSec = (startCount.tv_sec * 1000000.0) + startCount.tv_usec;
        endTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec;
    #endif
    
        return endTimeInMicroSec - startTimeInMicroSec;
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // divide elapsedTimeInMicroSec by 1000
    ///////////////////////////////////////////////////////////////////////////////
    double Timer::getElapsedTimeInMilliSec()
    {
        return this->getElapsedTimeInMicroSec() * 0.001;
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // divide elapsedTimeInMicroSec by 1000000
    ///////////////////////////////////////////////////////////////////////////////
    double Timer::getElapsedTimeInSec()
    {
        return this->getElapsedTimeInMicroSec() * 0.000001;
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // same as getElapsedTimeInSec()
    ///////////////////////////////////////////////////////////////////////////////
    double Timer::getElapsedTime()
    {
        return this->getElapsedTimeInSec();
    }
    //////////////////////////////////////////////////////////////////////////////
    // Timer.h
    // =======
    // High Resolution Timer.
    // This timer is able to measure the elapsed time with 1 micro-second accuracy
    // in both Windows, Linux and Unix system 
    //
    //  AUTHOR: Song Ho Ahn (song.ahn@gmail.com)
    // CREATED: 2003-01-13
    // UPDATED: 2006-01-13
    //
    // Copyright (c) 2003 Song Ho Ahn
    //////////////////////////////////////////////////////////////////////////////
    
    #ifndef TIMER_H_DEF
    #define TIMER_H_DEF
    
    #ifdef WIN32   // Windows system specific
    #include <windows.h>
    #else          // Unix based system specific
    #include <sys/time.h>
    #endif
    
    
    class Timer
    {
    public:
        Timer();                                    // default constructor
        ~Timer();                                   // default destructor
    
        void   start();                             // start timer
        void   stop();                              // stop the timer
        double getElapsedTime();                    // get elapsed time in second
        double getElapsedTimeInSec();               // get elapsed time in second (same as getElapsedTime)
        double getElapsedTimeInMilliSec();          // get elapsed time in milli-second
        double getElapsedTimeInMicroSec();          // get elapsed time in micro-second
    
    
    protected:
    
    
    private:
        double startTimeInMicroSec;                 // starting time in micro-second
        double endTimeInMicroSec;                   // ending time in micro-second
        int    stopped;                             // stop flag 
    #ifdef WIN32
        LARGE_INTEGER frequency;                    // ticks per second
        LARGE_INTEGER startCount;                   //
        LARGE_INTEGER endCount;                     //
    #else
        timeval startCount;                         //
        timeval endCount;                           //
    #endif
    };
    
    #endif // TIMER_H_DEF
  • 相关阅读:
    Oracle 删除某个用户下的所有对象,执行需谨慎
    ORACLE常用性能监控SQL
    mysql千万级大数据SQL查询优化
    qt小例子:实现阿里云物联网设备登录信息计算器
    mqtt协议
    亚马逊物联网平台c-sdk的使用
    esp32-cam开发环境搭建
    qt小例子:实现选值框和滑块同步变化
    在qt5中使用qtmqtt库
    将short类型转换为char类型
  • 原文地址:https://www.cnblogs.com/adong7639/p/4200529.html
Copyright © 2011-2022 走看看