[图像处理] 高斯模糊的C++实现(Gaussian Blur)

程序完成时间:  2017/2/21

      事实上,写下这篇博文的时候,距离完成这个小程序已经两个月了。现在才跑过来填个坑儿。

参考文献:

          [1] Wiki百科:https://en.wikipedia.org/wiki/Gaussian_blur

          [2] 博客文章: http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html

实现效果截图:(图一为原图、图二为模糊结果。分割线用以调整处理区域)

          我的二女神!!西野七濑Nishino Nanase!!(づ ̄ 3 ̄)づ

                   

                   

高斯模糊原理

       The Gaussian blur is a type of image-blurring filter that uses a Gaussian function (which also expresses the normal distribution in statistics) for calculating the transformation to apply to each pixel in the image. The equation of a Gaussian function in one dimension is:

       高斯模糊是一种图像模糊过滤器,通过使用高斯函数(在统计学中也被称为正态分布)来计算应用到图像中每个像素的变换关系(事实上是矩阵Matrix)。一维的高斯函数的表达式为:

       

         in two dimensions, it is the product of two such Gaussians, one in each dimension:

    在二维情况下,他是两个这样的高斯函数的积分,表达式如下:

    

      where x is the distance from the origin in the horizontal axis, y is the distance from the origin in the vertical axis, and σ is the standard deviation of the Gaussian distribution. When applied in two dimensions, this formula produces a surface whose contours are concentric circles with a Gaussian distribution from the center point. Values from this distribution are used to build a convolutionmatrix which is applied to the original image. Each pixel's new value is set to a weighted average of that pixel's neighborhood. The original pixel's value receives the heaviest weight (having the highest Gaussian value) and neighboring pixels receive smaller weights as their distance to the original pixel increases.

      这里,x是在水平方向上与图像原点(图像左上角)的距离,y是在竖直方向上与图像原点的距离,σ是高斯分布的标准差。当在二维情况下时,这个公式表现为一个轮廓由多个同心圆围绕一个中轴线组成的曲面(如下图)。这个分布的数值被用于构建作用在原始图像上的卷积矩阵。每个像素的新值被设置为临近的矩形区域像素的加权平均(权值来自于前面提到的的卷积矩阵)。某像素的原始值具有最高的权重(拥有一个最大的高斯函数值)并且临近像素的权值随着与该中心像素的距离的增加而减小。

    二维高斯分布的示意图如下(来源:WikiPedia)

    

高斯模糊的C++实现:

1. 设定初始值

        高斯模糊的卷积矩阵半径:r(即每个点的新值是由一个宽高均为2r+1的矩形区域的加权平均得出)

        标准差σ : sigma(取卷积矩阵半径r的1/3为宜)

        下图为一个r=1的卷积矩阵,该矩阵可以通过二维的高斯函数带入,并将权值归一化求得。

        

2. 边界处理函数: int edge(int, int, int)

        之所以引入这个函数,是因为在高斯模糊中,每个点的新值都是由临近的矩形区域的平均值得出,但是若矩形区域超出图像范围,则会产生黑边。为了消除这一影响,我们采用对称的方法,将矩形的超出部分用内部的对应点代替。

int Image::edge(int x, int i, int w)
{
    // x为中心位置, i为偏移量,w为宽度
    int inx = x+i;
    if(inx<0 || inx>=w)
        return x-i;
}

3. 高斯函数处理

       这种方法非常简单,不做赘述,因为我想把更多的篇幅放在后面的高斯函数的优化版本中。

       在这里,我们只需要对每一个点都进行一次计算:用上述的卷积矩阵的每个数值分别与该点周围的相应矩形区域的像素值相乘,求出加权平均即可。但是每个点都需要进行(2r+1)*(2r+1)次运算,对于一个较大的图像来说,这种平方级的运算时间是难以忍受的。

4. 我们实际采用的高斯模糊的优化版本!!

    下面,我想重点谈一下关于高斯函数的优化!!

    在Wiki百科中有下面一段话:

      In practice, it is best to take advantage of the Gaussian blur’s separable property by dividing the process into two passes. In the first pass, a one-dimensional kernel is used to blur the image in only the horizontal or vertical direction. In the second pass, the same one-dimensional kernel is used to blur in the remaining direction. The resulting effect is the same as convolving with a two-dimensional kernel in a single pass, but requires fewer calculations.     

       ”在实际应用中,一种更好的方式为:对图像在两个独立的一维空间分别进行计算。在第一次处理中,应用一个一维的高斯函数得到的线性空间对图像在水平方向进行一次模糊。在第二次处理中,同样的一维线性空间对图像在竖直方向进行一次模糊。通过这种方式得到的结果可以达到与使用二维卷积空间处理的同样效果,但是却大大节省了计算时间”

         显然,通过这种方式,每个点只需要进行2*(2r+1)次计算即可,时间复杂度降低了一个幂。


初始化线性权重空间的代码:

// 一维高斯函数
double Image::gaussFunc1D(int x)
{
    double A = 1/(sigma*sqrt(2*3.141592653));
    double index = -1.0*(x*x)/(2*sigma*sigma);

    return A*exp(index);
}

// 获取线性的权值空间
QImage Image::getKernal(double* weight)
{ 
    weight= new double[2*r+1];
    double sum=0;

    // 获取权值空间weight[]
    for(int i=0; i<2*r+1;i++)
    {
        weight[i] = gaussFunc1D(i-radius);
        sum+=weight[i];
    }
    // 归一化
    for(int i=0; i<2*radius+1;i++)
    {
        weight[i]/=sum;
    }
}
进行两个方向的高斯模糊获得最终图像代码(Qt):

// 获取最终的模糊图像
QImage Image::getBlurImage()
{ 
    // 原图为 originImg
    QImage originImg(......);
    // 第一个方向处理的图像为tmpImg
    QImage tmpImg(.......);
    // 经过第二次处理的最终结果newImg
    QImage newImg(.......);
    
    // 在横向进行一次相加
    for(int y=0;y<originImg.height();y++)
    {
        for(int x=0;x<originImg.width();x++)
        {
            double red=0,green=0,blue=0;
            for(int i=-r; i<=r; i++)
            {
                // 边界处理后的对应的权值矩阵实际值
                int inx = edge(x,i,width());

                QColor rgb = QColor(originImgpixel(inx,y));
                red+=rgb.red()*weight[r+i];
                green+=rgb.green()*weight[r+i];
                blue+=rgb.blue()*weight[r+i];
            }
            tmpImg.setPixel(x,y,qRgb(red,green,blue));
        }
    }
    // 在纵方向对第一次的结果重新进行一次
    for(int y=0;y<tmpImg.height();y++)
    {
        for(int x=0;x<tmpImg.width();x++)
        {
            double red=0,green=0,blue=0;
            for(int i=-r; i<=r; i++)
            {
                int iny = edge(y,i,height());

                QColor rgb = QColor(tmpImg.pixel(x,iny));
                red+=rgb.red()*weight[r+i];
                green+=rgb.green()*weight[r+i];
                blue+=rgb.blue()*weight[r+i];
            }
            newImg.setPixel(x,y,qRgb(red,green,blue));
        }
    }
    return newImg;
}


GaussianBlur是C语言中常用的图像处理算法之一,主要用于对图像进行模糊处理。该算法的基本思想是对图像中的每个像素点进行高斯滤波,使其周围的像素点产生一定的模糊效果,从而达到图像模糊的效果。 具体实现方法如下: 1. 首先需要定义一个高斯卷积核,该卷积核是一个二维的数组,其中每个元素的值表示该位置的权重,即离该位置越近的像素点权重越大,离该位置越远的像素点权重越小。通常情况下,高斯卷积核的大小为3x3或5x5。 2. 对于图像中的每个像素点,将该点周围的像素点根据高斯卷积核进行加权平均。具体来说,可以将该像素点的周围一定范围内的像素点与高斯卷积核进行卷积,然后将卷积结果作为该像素点的新值。这个范围称为卷积窗口大小,一般情况下为3x3或5x5。 3. 重复以上步骤,直到对图像中所有像素点都进行了处理。 4. 最终得到的图像就是经过高斯模糊处理后的图像。 需要注意的是,高斯卷积核的大小和卷积窗口大小会影响到最终的模糊效果,不同的值会产生不同的效果。同时,高斯滤波还可以通过调整卷积核中每个元素的权重来实现不同的效果,比如增强边缘等。 总之,高斯模糊图像处理中常用的技术之一,可以用于美化图像、去除噪声等。在C语言中,可以通过调用相应的图像处理库来实现高斯模糊的功能。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值