图像处理之高斯滤波的几种实现方式

基本概念

        在图像处理中,高斯滤波一般用高斯模板。除此之外,还有递归高斯滤波、FFT法、重复卷积法等。

1、直接卷积法

图像处理之高斯滤波的几种实现方式_第1张图片

2、重复卷积法

图像处理之高斯滤波的几种实现方式_第2张图片
图像处理之高斯滤波的几种实现方式_第3张图片

3、FFT实现法

        原理很简单out = IFFT2(FFT(in)*FFT(h)),其中in是输入图像,h为卷积核,out是平滑后图像。

4、递归实现法

        文献《Recursive implementation of the Gaussian filter》提出该方法,其产生一个IIR滤波器,比上面三种方法都快,其运行时间与σ无关。推导过程大致是,将高斯公式g(t)的傅里叶变换G(w)进行泰勒公式展开,阶数到6取近似,将其拉普拉斯变换G(s),在变换到z域时,用前后差分技术代替双线性法。最终结论如下。
图像处理之高斯滤波的几种实现方式_第4张图片
图像处理之高斯滤波的几种实现方式_第5张图片
图像处理之高斯滤波的几种实现方式_第6张图片
q的选择如下
图像处理之高斯滤波的几种实现方式_第7张图片
以上可以认为串行方式,还有并行方式,详细见文献《Recursively implementing the Gaussian and its derivatives》,在ITK中, itkRecursiveGaussianImageFilter实现了该算法。

示例演示

        对图像进行高斯滤波而言,假设滤波器半径为r,我们常用的高斯模板则对于图像每个像素的算法复杂度是O(r^2)。高斯滤波器的kernel是可分离的(separable),也就是说,可以将2D的高斯kernel分解为两个1D的kernel,先沿x方向对图像进行1D高斯kernel的卷积,然后沿y方向对图像进行1D的高斯kernel卷积,最后的结果和使用一个2D高斯kernel对图像卷积效果是一样的。这样一来,针对每个像素,滤波器的算法复杂度降为O(r)。下面实现递归高斯滤波法,即上面第四种方法。完整工程代码。

/**********************************************************************

Copyright (c) Mr.Bin. All rights reserved.
For more information visit: http://blog.csdn.net/webzhuce

**********************************************************************/
#include 
using namespace cv;

typedef struct
{
    int    N;
    float  sigma;
    double B;
    double b[4];
} GaussCoefs;

/*
* Calculate the coefficients for the recursive filter algorithm
* Fast Computation of gaussian blurring.
*/
void ComputeGaussCoefs(GaussCoefs *c, float 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
    */
    float q = 0, q2 = 0, q3 = 0;
    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;
    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;
}

void RecursiveGausssmooth(float *in, float *out, int size, int rowstride, GaussCoefs *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
    */
    int i, n, bufsize;
    float *w1, *w2;

    /* forward pass */
    bufsize = size + 3;
    size -= 1;
    w1 = new float[bufsize];
    w2 = new float[bufsize];
    w1[0] = in[0];
    w1[1] = in[0];
    w1[2] = in[0];
    for (i = 0, n = 3; i <= size; i++, n++)
    {
        w1[n] = (float)(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] = (float)(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]));
    }

    delete[] w1;
    delete[] w2;
}

/*
@function: 2D gauss filter
*/
void RecursiveGausssmooth2D(const Mat &src, Mat &dst, float sigma = 1.0f)
{
    GaussCoefs c;
    ComputeGaussCoefs(&c, sigma);
    const int height = src.rows;
    const int width = src.cols;
    if (src.channels() == 1)
    {
        Mat srccopy;
        src.convertTo(srccopy, CV_32FC1);
        Mat dstcopy;
        src.convertTo(dstcopy, CV_32FC1);
        float* srcdata = srccopy.ptr<float>(0);
        float* dstdata = dstcopy.ptr<float>(0);
        for (int y = 0; y < height; y++)
        {
            RecursiveGausssmooth(srcdata + y * width, dstdata + y * width, width, 1, &c);
        }
        for (int x = 0; x < width; x++)
        {
            RecursiveGausssmooth(dstdata + x, dstdata + x, height, width, &c);
        }
        dstcopy.convertTo(dst, src.type());
    }
    else if (src.channels() == 3)
    {
        Mat srccopy;
        src.convertTo(srccopy, CV_32FC3);
        Mat dstcopy;
        src.convertTo(dstcopy, CV_32FC3);
        for (int y = 0; y < height; y++)
        {
			float* srcrowdata = srccopy.ptr<float>(y);
			float* dstrowdata = dstcopy.ptr<float>(y);
            RecursiveGausssmooth(srcrowdata, dstrowdata, width, 3, &c);
            RecursiveGausssmooth(srcrowdata + 1, dstrowdata + 1, width, 3, &c);
            RecursiveGausssmooth(srcrowdata + 2, dstrowdata + 2, width, 3, &c);
        }
		float* srcdata = srccopy.ptr<float>(0);
		float* dstdata = dstcopy.ptr<float>(0);
		for (int x = 0; x < width; x++)
		{
			RecursiveGausssmooth(dstdata + x * 3, dstdata + x * 3, height, width * 3, &c);
			RecursiveGausssmooth(dstdata + x * 3 + 1, dstdata + x * 3 + 1, height, width * 3, &c);
			RecursiveGausssmooth(dstdata + x * 3 + 2, dstdata + x * 3 + 2, height, width * 3, &c);
		}
        dstcopy.convertTo(dst, src.type());
    }
    else
        return;
}

int main(int argc, char *argv[])
{
    Mat src = imread("../RecursiveGaussian/lena.bmp", 1);
    imshow("original", src);

    Mat dst;
    RecursiveGausssmooth2D(src, dst);
    imshow(" RecursiveGaussSmooth", dst);

	Mat dstImage;
	GaussianBlur(src, dstImage, Size(5, 5), 2, 2);
	imshow("GaussSmooth", dstImage);

    waitKey(0);
    return EXIT_SUCCESS;
}

运行结果

图像处理之高斯滤波的几种实现方式_第8张图片

你可能感兴趣的:(图像处理(OpenCV))