图像处理 高斯函数

2018-06-24 14:22:51 zhanghm1995 阅读数 4211
高斯函数广泛应用于统计学领域,用于表述正态分布,在信号处理领域,用于定义高斯滤波器,在图像处理领域,二维高斯核函数常用于高斯模糊,在数学领域,主要用于解决热力方程和扩散方程。


正态分布与高斯函数

高斯函数其实是一族函数,而满足正态分布的高斯函数如下所示

其为正态分布随机变量的概率密度函数,满足积分为1的特性。
理论上能够证明假设把很多小作用加起来看做一个变量,那么这个变量服从正态分布。
为了理解正态分布,需要补充一点概率论的知识:
有几种不同的方法用来说明一个随机变量,最直观的方法是概率密度函数,这样的方法可以表示随机变量每一个取值有多大的可能性;累积分布函数是一种概率上更加清楚的表示方法。



二维高斯函数

相比于一维高斯函数,二维高斯函数在计算机视觉领域用处广泛,利用0均值的二维高斯函数,可以生成高斯卷积核,用于图像处理中的高斯滤波,实现高斯模糊的效果,有效去除高斯噪声。

二维高斯函数的表达式和形状如下所示,为一个立体“钟状图”。



2018-09-03 14:49:49 qinglongzhan 阅读数 43785

摘要

    论文中遇到很重要的一个元素就是高斯核函数,但是必须要分析出高斯函数的各种潜在属性,本文首先参考相关材料给出高斯核函数的基础,然后使用matlab自动保存不同参数下的高斯核函数的变化gif动图,同时分享出源代码,这样也便于后续的论文写作。

高斯函数的基础

2.1 一维高斯函数

高斯函数,Gaussian Function, 也简称为Gaussian,一维形式如下:

对于任意的实数a,b,c,是以著名数学家Carl Friedrich Gauss的名字命名的。高斯的一维图是特征对称“bell curve”形状,a是曲线尖峰的高度,b是尖峰中心的坐标,c称为标准方差,表征的是bell钟状的宽度。

高斯函数广泛应用于统计学领域,用于表述正态分布,在信号处理领域,用于定义高斯滤波器,在图像处理领域,二维高斯核函数常用于高斯模糊Gaussian Blur,在数学领域,主要是用于解决热力方程和扩散方程,以及定义Weiertrass Transform。

从上图可以看出,高斯函数是一个指数函数,其log函数是对数凹二次函数 whose logarithm a concave quadratic function。

高斯函数的积分是误差函数error function,尽管如此,其在整个实线上的反常积分能够被精确的计算出来,使用如下的高斯积分

同理可得

当且仅当

上式积分为1,在这种情况下,高斯是正态分布随机变量的概率密度函数,期望值μ=b,方差delta^2 = c^2,即

 

2.2 二维高斯函数

    二维高斯函数,形如

A是幅值,x。y。是中心点坐标,σσy是方差,图示如下,A = 1, xo = 0, yo = 0, σx = σy = 1

 

2.3 高斯函数分析

这一节使用matlab直观的查看高斯函数,在实际编程应用中,高斯函数中的参数有

ksize 高斯函数的大小

sigma 高斯函数的方差

center 高斯函数尖峰中心点坐标

bias 高斯函数尖峰中心点的偏移量,用于控制截断高斯函数

为了方便直观的观察高斯函数参数改变而结果也不一样,下面的代码实现了参数的自动递增,并且将所有的结果图保存为gif图像,首先贴出完整代码:

 function mainfunc()  
% 测试高斯函数,递增的方法实现高斯函数参数的改变对整个高斯函数的影响,  
% 并自动保存为gif格式输出。  
% created by zhao.buaa 2016.09.28  
  
%% 保存gif动画  
item = 10;      % 迭代次数  
dt = 1;             % 步长大小  
ksize =20;      % 高斯大小  
sigma = 2;      % 方差大小  
% filename = ['ksize-' num2str(ksize) '--' num2str(ksize+dt*item) '-sigma-' num2str(sigma) '.gif']; %必须预先建立gif文件  
filename = ['ksize-' num2str(ksize)  '-sigma-' num2str(sigma) '--' num2str(sigma+dt*item) '.gif']; %必须预先建立gif文件  
  
% main loop  
for i = 1:item  
    center  = round(ksize/2);          % 中心点  
    bias       = ksize*10/10;              % 偏移中心点量  
    ksigma = ksigma(ksize, sigma, center, bias);    % 构建核函数  
    tname  = ['ksize-' num2str(ksize) '-sigma-' num2str(sigma) '-center-' num2str(center)];  
    figure(i), mesh(ksigma), title(tname);  
    %设置固定的x-y-z坐标范围,便于观察,axis([xmin xmax ymin ymax zmin zmax])  
    axis([0 ksize 0 ksize 0 0.008]);  view([0, 90]);% 改变可视角度     
    % ksize 递增  
%     ksize = ksize + 10;  
    % sigma 递增  
    sigma = sigma + dt;       
      
    % 自动保存为gif图像  
    frame = getframe(i);  
    im = frame2im(frame);  
    [I,map] = rgb2ind(im,256);  
    if i==1  
        imwrite(I,map,filename,'gif','Loopcount',inf, 'DelayTime',0.4);  
    else  
        imwrite(I,map,filename,'gif','WriteMode','append','DelayTime',0.4);  
    end  
end;  
  
close all;  
  
  
%% 截断高斯核函数,截断的程度取决于参数bias  
function ksigma = ksigma(ksize, sigma, center,bias)  
%ksize = 80;    sigma = 15;  
ksigma=fspecial('gaussian',ksize, sigma);   % 构建高斯函数  
[m, n] =size(ksigma);  
for i = 1:m  
    for j = 1:n  
        if(  (i<center-bias)||(i>center+bias)||(j<center-bias)||(j>center+bias)  )  
            ksigma(i,j) = 0;  
        end;  
    end;  
end;  


结果图:

固定ksize为20,sigma从1-9,固定center在高斯中间,并且bias偏移量为整个半径,即原始高斯函数。

随着sigma的增大,整个高斯函数的尖峰逐渐减小,整体也变的更加平缓,则对图像的平滑效果越来越明显。

保持参数不变,对上述高斯函数进行截断,即truncated gaussian function,bias的大小为ksize*3/10,则结果如下图:

truncated gaussian function的作用主要是对超过一定区域的原始图像信息不再考虑,这就保证在更加合理的利用靠近高斯函数中心点的周围像素,同时还可以改变高斯函数的中心坐标,如下图:

为了便于观察截断的效果,改变了可视角度。

高斯核函数卷积

    论文中使用gaussian与feature map做卷积,目前的结果来看,要做到随着到边界的距离改变高斯函数的截断参数,因为图像的边缘如果使用原始高斯函数,就会在边界地方出现特别低的一圈,原因也很简单,高斯函数在与原始图像进行高斯卷积的时候,图像边缘外为0计算的,那么如何解决边缘问题呢?

先看一段代码:

[plain] view plain copy

  1. % 截断高斯核函数  
  2. ksize = 40; ksigma=fspecial('gaussian',  ksize, 6);  
  3. [m, n] =size(ksigma);  
  4. for i = 1:m  
  5.     for j = 1:n  
  6.         if( i<25 )  
  7.            ksigma(i,j) = 0;  
  8.         end;  
  9.     end;  
  10. end;  
  11. figure, mesh(ksigma);  

在i,即row上对高斯核函数进行截断,bias为半径大小,则如图6

并且对下图7进行卷积,

首先卷积核为原始未截断高斯核函数,则结果如图8

可以看出,在图像边缘处的卷积结果出现不想预见的结果,边缘处的值出现大幅度减少的情况,这是高斯核函数在边缘处将图像外的部分当成0计算的结果,因此,需要对高斯核函数进行针对性的截断处理,但是前提是要掌握bias的规律,下面就详细分析。

如果使用图6的高斯核函数与图7做卷积操作,则如图9:

可以看出,相比较于图8,与高斯核函数相对应的部分出现了变化,也就是说:

[plain] view plain copy

  1. if( i<25 )  
  2.    ksigma(i,j) = 0;  
  3. end;  

靠近边缘的时候,改变 i 或 j 的值,即可保证边缘处的平滑处理。但是这样改变高斯核函数,使用matlab不是很好解决这个问题,还是使用将待处理图像边缘向外部扩展bias的大小,与标准高斯核函数做卷积,再将超过原始图像大小的部分剪切掉,目前来看在使用matlab中imfilter函数做卷积运算最合适且最简单的处理方法了,先写在这里,此部分并不是论文中的核心部分,只是数值运算的技巧性编程方法。

设计图像处理

深入地探讨高斯滤波与图像处理的关联,包括参数的影响、参数的选取、高斯模板的形成以及自行编程实现高斯滤波的效果与openCV函数实现效果比对。

说道“sigma表示的是标准差,如果标准差比较小,这是就相当于图像点运算,则平滑效果不明显;反之,标准差比较大,则相当于平均模板,比较模糊”,那么这么说可能很多人包括一开始的我并不是很理解,这是为什么呢,那么我们需要从高斯函数谈起:
                                               

这样一个高斯函数的概率分布密度如下图所示:


                             

我们要理解好这个图,横轴表示可能得取值x,竖轴表示概率分布密度F(x),那么不难理解这样一个曲线与x轴围成的图形面积为1。sigma(标准差)决定了这个图形的宽度,我给出下述结论:sigma越大,则图形越宽,尖峰越小,图形较为平缓;sigma越小,则图形越窄,越集中,中间部分也就越尖,图形变化比较剧烈。这其实很好理解,如果sigma也就是标准差越大,则表示该密度分布一定比较分散,由于面积为1,于是尖峰部分减小,宽度越宽(分布越分散);同理,当sigma越小时,说明密度分布较为集中,于是尖峰越尖,宽度越窄!

理解好上述结论之后,那么(一)中的结论当然也就顺理成章了,sigma越大,分布越分散,各部分比重差别不大,于是生成的模板各元素值差别不大,类似于平均模板;sigma越小,分布越集中,中间部分所占比重远远高于其他部分,反映到高斯模板上就是中心元素值远远大于其他元素值,于是自然而然就相当于中间值得点运算。

程序也可以验证如下:

窗口尺寸:3*3      sigma = 0.1

窗口尺寸:3*3      sigma = 0.8

 窗口尺寸:3*3      sigma = 2

接着,我们来重点讨论下高斯模板,在初学高斯滤波的时候,用得最多的也是最经典的一个3*3模板就是                                       

[1  2  1  ]

[ 2  4  2 ]

[1  2  1]

,当时我就很纳闷这个模板是怎么出来的,后来我经过多方查找资料,基本得到了如下的解释:高斯模板实际上也就是模拟高斯函数的特征,具有对称性并且数值由中心向四周不断减小,这个模板刚好符合这样的特性,并且非常简单,容易被大家接受,于是就比较经典!但是这样一个简单的矩阵是远远不能满足我们对图像处理的要求的,我们需要按照自己的要求得到更加精确的模板,那么接下来我们就编程实现自己想要的高斯模板。部分关键函数如下:
double** createG(int iSize, double sigma)
{
 double **guass;
 double sum = 0;
 double x2 = 0;
 double y2 = 0;
 int center = (iSize - 1) / 2;
 guass = new double*[iSize];//注意,double*[k]表示一个有10个元素的指针数组

 for (int i = 0; i < iSize; ++i)
 {
  guass[i] = new double[iSize];
 }
 for (int i = 0; i<iSize; i++)
 {//使用x2,y2降低了运算速度,提高了程序的效率
  x2 = pow(double(i - center), 2);
  for (int j = 0; j<iSize; j++)
  {
   y2 = pow(double(j - center), 2);
   sum += guass[i][j] = exp(-(x2 + y2) / (2 * sigma*sigma));
  }
 }
 if (sum != 0)
 {
  //归一化  
  for (int i = 0; i<iSize; i++)
  {
   for (int j = 0; j<iSize; j++)
   {
    guass[i][j] /= sum;
   }
  }
 }
 return guass;

上述的这个函数就是返回的一个用户想要的高斯模板,其输入参数iSize表示模板大小(这里先只考虑方阵模板),输入参数sigma表示高斯函数标准差,聪明的你应该一眼就看出这个程序实际上就是按照公式根据规定的矩阵大小进行离散化得到相应的数据。纵观整个程序,我觉得最不好理解的是那个参数center,这是个什么参数呢?通过程序可以看出为什么center与iSize呈2center+1的关系呢?而且,为什么x2,y2是那样取值呢?这实际上是模拟的一种距离关系。举个例子来说:

       假设我现在想要使用窗口尺寸为2k+1*2k+1的高斯模板对点进行操作,那么假设这个高斯模板的第一个元素地址记为为(1,1),那么高斯模板中心元素很容易算出为(k,k)。假设现在在计算模板中(i,j)元素值,那么公式中的x2模拟为该点到中心点的距离,即i-k-1(为什么要-1,读者不妨自己自己写个3*3的矩阵,看看(1,1)元素到(2,2)元素是不是要走两步)。但是程序中是没有-1的,这是因为程序中的i是从0开始的!于是这个center参数实际上就是代表的中心点!

运行结果:

我的程序运行的结果:3*3,sigma=1

 Matlab的程序运行的结果:3*3,sigma=1

可以看出,相差无几,这个程序是成功的!

     然后,最重要的部分当然是使用上述高斯模板对图像进行滤波处理得到想要的效果,那么接下来重点论述滤波处理。要理解好高斯滤波,自己写高斯滤波的算法当然是最好的,然后再和openCV的函数进行效果比对,这样,算是对高斯滤波有了比较好的认识和理解了!

     在很多资料上,我们都看到高斯函数的这样一个特性,可分离性,意思是一个二维的高斯函数可以分解成相同的一维高斯函数处理两遍,得到的效果是一样的,但是处理时间却大大缩短了。

    我们可以想到,二维函数直接处理会是这样的:

                  for(int i = 0; i < img->height; ++i)

                         for(int j = 0; j < img->weigth; ++j)

                               {

                                for(int m = 0; m < iSize; ++m)

                                       for(int n= 0; n< iSize; ++n)

                                             {

                                                         ...

                                             }

                               }

       这样的算法复杂度可以看出是为O(height*weigth*iSize^2)

      然而使用分解后的一维函数进行两次处理,程序应当如下:

                    for(int i = 0; i < img->height; ++i)

                         for(int j = 0; j < img->weigth; ++j)

                               {

                                       for(int m = 0; m < iSize; ++m)

                                             {

                                                         ...

                                             }

                               }

                    for(int j = 0; j< img->weigth; ++j)

                         for(int i= 0; i< img->height; ++i)

                               {

                                       for(int m = 0; m < iSize; ++m)

                                             {

                                                         ...

                                             }

                               }

                 这样的算法复杂度为O(2*height*weigth*iSize),比一维处理要少了很多,所以时间对应来说也会快一点。

用后者,我们的关键函数如下:

/*
生成一维高斯模板,水平的和垂直方向上的模板是一样的
输入参数分别是:模板大小,sigma值
输出:一维数组(高斯模板)
*/
double* CreateMuban(int iSize ,double sigma)
{
 double *gauss = new double[iSize];//声明一维模板
 int radius = (iSize - 1) / 2;//这是高斯半径
 double MySigma = 2 * sigma * sigma;
 double value = 0;
 for (int i = 0; i < iSize; i++)
 {//高斯函数前面的常数项因为在归一化的时候将会消去,故这里不重复计算
  gauss[i] = exp(-(i - radius)*(i - radius)/MySigma);
  value = value + gauss[i];
 }
 for (int i = 0; i < iSize; i++)
 {//归一化
  gauss[i] = gauss[i] / value;
 }
 return gauss;
}

//对像素进行操作
IplImage*  operatorImage(IplImage* img, double* Muban, int iSize)
{
 //创建一张新的图片来进行滤波操作
 IplImage* NewImage = cvCreateImage(cvSize(img->width, img->height), 8, 3);
 int radius = (iSize - 1) / 2;
 int r = 0;
 int g = 0;
 int b = 0;
 CvScalar cs;
 //复制图片
 cvCopy(img, NewImage);
 //先对I,也就是垂直方向进行操作
 for (int j = 0; j < NewImage->width; ++j)
 {
  for (int i = 0; i < NewImage->height; ++i)
  {
   //先判断是否是边缘,不是则操作,是则跳过不处理,保持原样
   if (!JudgeEdge(i, NewImage->height, radius))
   {
    for (int k = 0; k < iSize; ++k)
    {
    /* b = b + (int)((double)(NewImage->imageData + (i - radius + k) * NewImage->widthStep)[j * (int)NewImage->nChannels + 0] * Muban[k]);
     g = g + (int)((double)(NewImage->imageData + (i - radius + k) * NewImage->widthStep)[j * (int)NewImage->nChannels + 1] * Muban[k]);
     r = r + (int)((double)(NewImage->imageData + (i - radius + k) * NewImage->widthStep)[j * (int)NewImage->nChannels + 2] * Muban[k]); */

     cs = cvGet2D(NewImage, i - radius + k, j);   //获取像素  
     b = b + (int)((double)cs.val[0] * Muban[k]);
     g = g + (int)((double)cs.val[1] * Muban[k]);
     r = r + (int)((double)cs.val[2] * Muban[k]);

    }
    /*((uchar *)(NewImage->imageData + i * NewImage->widthStep))[j * NewImage->nChannels + 0] = b;   //改变该像素B的颜色分量  
    ((uchar *)(NewImage->imageData + i * NewImage->widthStep))[j * NewImage->nChannels + 1] = g;   //改变该像素G的颜色分量  
    ((uchar *)(NewImage->imageData + i * NewImage->widthStep))[j * NewImage->nChannels + 2] = r;   //改变该像素R的颜色分量  */
    cs = cvGet2D(NewImage, i, j);
    cs.val[0] = b;
    cs.val[1] = g;
    cs.val[2] = r;
    cvSet2D(NewImage, i, j, cs);
    b = 0;
    g = 0;
    r = 0;
   }
  }
 }
 //在对J,也就是水平方向进行操作
 for (int i = 0; i < NewImage->height; ++i)
 {
  for (int j = 0; j < NewImage->width; ++j)
  {
   //先判断是否是边缘,不是则操作,是则跳过不处理,保持原样
   if (!JudgeEdge(j, NewImage->width, radius))
   {
    for (int k = 0; k < iSize; ++k)
    {
     /*b = b + (int)((double)(NewImage->imageData + i * NewImage->widthStep)[(j - radius + k) * (int)NewImage->nChannels + 0] * Muban[k]);
     g = g + (int)((double)(NewImage->imageData + i * NewImage->widthStep)[(j - radius + k) * (int)NewImage->nChannels + 1] * Muban[k]);
     r = r + (int)((double)(NewImage->imageData + i * NewImage->widthStep)[(j - radius + k) * (int)NewImage->nChannels + 2] * Muban[k]);*/

     cs = cvGet2D(NewImage, i, j - radius + k);   //获取像素  
     b = b + (int)((double)cs.val[0] * Muban[k]);
     g = g + (int)((double)cs.val[1] * Muban[k]);
     r = r + (int)((double)cs.val[2] * Muban[k]);

    }
    /*((uchar *)(NewImage->imageData + i * NewImage->widthStep))[j * NewImage->nChannels + 0] = b;   //改变该像素B的颜色分量  
    ((uchar *)(NewImage->imageData + i * NewImage->widthStep))[j * NewImage->nChannels + 1] = g;   //改变该像素G的颜色分量  
    ((uchar *)(NewImage->imageData + i * NewImage->widthStep))[j * NewImage->nChannels + 2] = r;   //改变该像素R的颜色分量*/
    
    cs = cvGet2D(NewImage, i, j);
    cs.val[0] = b;
    cs.val[1] = g;
    cs.val[2] = r;
    cvSet2D(NewImage, i, j, cs);
    b = 0;
    g = 0;
    r = 0;
    //cout << r << " " << g << " " << b << endl;
   }
  }
 }

 return NewImage;
}

实现效果:

 

自己编的程序与openCV函数处理效果并无差别,成功!

 

      最后,对高斯滤波部分进行扩展------自适应高斯滤波。为了达到更好的滤波效果,我们的手法需要更加灵活,往往可以加上一些限制条件进行判断是否需要处理。这一点很想PID控制中的选择积分的方法(具体名字忘了···囧)。这个我将在后面进行适当地尝试!

    

      学习高斯滤波只是一个开始,但是学习其他的图像处理方法诸如此类,我要学会举一反三,而且要实践与理论紧密结合,真正做到知其甚解才好啊!

2012-10-18 20:32:38 lyapple2008 阅读数 16015

高斯函数及其各阶导数

在图像处理中经常要用到高斯函数,高斯滤波是典型的低通滤波,对图像有平滑作用。高斯函数的一阶、二阶导数也可以进行高通滤波,比如canny算子中用到的是高斯函数的一阶导数,LOG算子中用到的是高斯函数的二阶导数。高斯函数的相关公式如下所示:

  一维和二维高斯函数表达式分别为:  

  

  二维高斯函数的一阶偏导数表达式为:

  

  二维高斯函数的二阶偏导数表达式为:

  

   改正后:

  相应地,二维高斯函数的一阶、二阶梯度为: 

  方向梯度为(角度取弧度):

  

  将梯度函数进行离散,可以得到一阶和二阶的梯度算子,使用这些算子与图像进行卷积,可以求取图像的一阶、二阶梯度以及各方向梯度。

 

转自:点击打开链接

 

2012-02-05 14:51:15 jia20003 阅读数 28706

高斯模糊是一种两维的卷积模糊操作,在图像完成高斯模糊相对于均值模糊来说,

计算量会增加,但是高斯模糊可以实现一些特殊效果,特别是在图像噪声(非椒盐

噪声)消去方面,更是有着非常好的效果。一维高斯公式如下:


其中x是制定[-n,n]范围的整数,sigma代表标准方差。通常取值为1.

一维高斯函数Java代码如下:

	private float[] get1DKernalData(int n, float sigma) {
		float sigma22 = 2*sigma*sigma;
		float Pi2 = 2*(float)Math.PI;
		float sqrtSigmaPi2 = (float)Math.sqrt(Pi2) * sigma ;
		int size = 2*n + 1;
		int index = 0;
		float[] kernalData = new float[size];
		for(int i=-n; i<=n; i++) {
			float distance = i*i;
			kernalData[index] = (float)Math.exp((-distance)/sigma22)/sqrtSigmaPi2;
			System.out.println("\t" + kernalData[index]);
			index++;
		}
		return kernalData;
	}

假设输入 n= 1, sigma = 1时,输出的Kernel数据为:

0.24197073, 0.3989423, 0.24197073


两维的高斯分布函数为:


对应的Java实现代码为:

	public float[][] get2DKernalData(int n, float sigma) {
		int size = 2*n +1;
		float sigma22 = 2*sigma*sigma;
		float sigma22PI = (float)Math.PI * sigma22;
		float[][] kernalData = new float[size][size];
		int row = 0;
		for(int i=-n; i<=n; i++) {
			int column = 0;
			for(int j=-n; j<=n; j++) {
				float xDistance = i*i;
				float yDistance = j*j;
				kernalData[row][column] = (float)Math.exp(-(xDistance + yDistance)/sigma22)/sigma22PI;
				column++;
			}
			row++;
		}
		
		for(int i=0; i<size; i++) {
			for(int j=0; j<size; j++) {
				System.out.print("\t" + kernalData[i][j]);
			}
			System.out.println();
			System.out.println("\t ---------------------------");
		}
		return kernalData;
	}

当n=1, sigma=1时对应输出的Kernel数据为:

    0.058549833   0.09653235     0.058549833

    0.09653235     0.15915494     0.09653235

    0.058549833   0.09653235     0.058549833

一个2D高斯分布的图可以表示如下:


高斯过滤在图像处理是一种低通滤波,会除去图像的细节而保持整体不变化,在图像美化和特效

方面,高斯过滤有这很多应用。高斯模糊不同于均值模糊!

 

本文实现完整的高斯模糊算法包括下面几个步骤:

1. 生成高斯操作数即Kernel Data

2. 从图像中读取像素,利用第一步的操作数,完成卷积。

3. 发现图像处理前后的最大像素值peak得出rate

4. 完成归一化操作,返回处理后像素数组


关键程序解析:

利用操作数完成卷积的代码参看以前的Blog文章《图像处理之理解卷积

完成归一化操作的算法非常简单, 主要是利用第三步计算出来的rate

        // normalization
        float rate = inMax/outMax;
        System.out.println("Rate = " + rate);
        for(int row=0; row<height; row++) {
        	for(int col=0; col<width; col++) {
        		index = row * width + col;
        		int rgb1 = tempoutPixels[index];
				int red = (rgb1 >> 16) & 0xff;
				int green = (rgb1 >> 8) & 0xff;
				int blue = rgb1 & 0xff;
				red = (int)(rate * red);
				green = (int)(rate * green);
				blue = (int)(rate * blue);
				outPixels[index] = (rgb1 & 0xff000000) | (red << 16) | (green << 8) | blue;
        	}
        }

高斯模糊效果如下:


 - 左边为原图                                                                                                                                                            - 右边为高斯模糊之后效果,发现皱纹和手部滑了

等等现在还不最cool的效果,高斯模糊之后如果与原图像叠加会出现一种Glow的

效果,好像灯光打在图像上一样,Glow处理之后的运行效果如下:

原图:


实现Glow Filter之后的图像:


实现Glow算法只是高斯模糊输出像素值叠加原来的像素值。

		int index = 0;
		for ( int y = 0; y < height; y++ ) {
			for ( int x = 0; x < width; x++ ) {
				int rgb1 = outPixels[index];
				int r1 = (rgb1 >> 16) & 0xff;
				int g1 = (rgb1 >> 8) & 0xff;
				int b1 = rgb1 & 0xff;

				int rgb2 = inPixels[index];
				int r2 = (rgb2 >> 16) & 0xff;
				int g2 = (rgb2 >> 8) & 0xff;
				int b2 = rgb2 & 0xff;

				r1 = PixelUtils.clamp( (int)(r1 + a * r2) );
				g1 = PixelUtils.clamp( (int)(g1 + a * g2) );
				b1 = PixelUtils.clamp( (int)(b1 + a * b2) );

				inPixels[index] = (rgb1 & 0xff000000) | (r1 << 16) | (g1 << 8) | b1;
				index++;
			}
		}

转载时请注明出处!!,谢谢!
2014-05-21 11:56:21 h_wlyfw 阅读数 12398

1、一维高斯函数:

高斯函数

a表示得到曲线的高度,b是指曲线在x轴的中心,c指width(与半峰全宽有关),图形如下:

高斯函数图形

2、根据一维高斯函数,可以推导得到二维高斯函数:



Matlab二维高斯图


在图形上,正态分布是一种钟形曲线,越接近中心,取值越大,越远离中心,取值越小。
计算平均值的时候,我们只需要将"中心点"作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值。常用作图像平滑操作。

如:通常,图像处理软件会提供"模糊"(blur)滤镜,使图片产生模糊的效果。

"模糊"的算法有很多种,其中有一种叫做"高斯模糊"(Gaussian Blur)。它将正态分布(又名"高斯分布")用于图像处理。

本节介绍"高斯模糊"的算法,你会看到这是一个非常简单易懂的算法。本质上,它是一种数据平滑技术(data smoothing),适用于多个场合,图像处理恰好提供了一个直观的应用实例。

高斯模糊的原理

所谓"模糊",可以理解成每一个像素都取周边像素的平均值。

上图中,2是中间点,周边点都是1。

"中间点"取"周围点"的平均值,就会变成1。在数值上,这是一种"平滑化"。在图形上,就相当于产生"模糊"效果,"中间点"失去细节。

显然,计算平均值时,取值范围越大,"模糊效果"越强烈。

上面分别是原图、模糊半径3像素、模糊半径10像素的效果。模糊半径越大,图像就越模糊。从数值角度看,就是数值越平滑。

接下来的问题就是,既然每个点都要取周边像素的平均值,那么应该如何分配权重呢?

如果使用简单平均,显然不是很合理,因为图像都是连续的,越靠近的点关系越密切,越远离的点关系越疏远。因此,加权平均更合理,距离越近的点权重越大,距离越远的点权重越小。

正态分布的权重

正态分布显然是一种可取的权重分配模式。

在图形上,正态分布是一种钟形曲线,越接近中心,取值越大,越远离中心,取值越小。

计算平均值的时候,我们只需要将"中心点"作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值。

高斯函数

上面的正态分布是一维的,图像都是二维的,所以我们需要二维的正态分布。

正态分布的密度函数叫做"高斯函数"(Gaussian function)。它的一维形式是:

其中,μ是x的均值,σ是x的方差。因为计算平均值的时候,中心点就是原点,所以μ等于0。

根据一维高斯函数,可以推导得到二维高斯函数:

有了这个函数 ,就可以计算每个点的权重了。

权重矩阵

假定中心点的坐标是(0,0),那么距离它最近的8个点的坐标如下:

更远的点以此类推。

为了计算权重矩阵,需要设定σ的值。假定σ=1.5,则模糊半径为1的权重矩阵如下:

这9个点的权重总和等于0.4787147,如果只计算这9个点的加权平均,还必须让它们的权重之和等于1,因此上面9个值还要分别除以0.4787147,得到最终的权重矩阵。

计算高斯模糊

有了权重矩阵,就可以计算高斯模糊的值了。

假设现有9个像素点,灰度值(0-255)如下:

每个点乘以自己的权重值:

得到

将这9个值加起来,就是中心点的高斯模糊的值。

对所有点重复这个过程,就得到了高斯模糊后的图像。如果原图是彩色图片,可以对RGB三个通道分别做高斯模糊。



二、高斯(核)函数简介

1函数的基本概念

所谓径向基函数 (Radial Basis Function 简称 RBF), 就是某种沿径向对称的标量函数。 通常定义为空间中任一点x到某一中心xc之间欧氏距离的单调函数 , 可记作 k(||x-xc||), 其作用往往是局部的 , 即当x远离xc时函数取值很小。最常用的径向基函数是高斯核函数 ,形式为 k(||x-xc||)=exp{- ||x-xc||^2/(2*σ)^2) } 其中xc为核函数中心,σ为函数的宽度参数 , 控制了函数的径向作用范围。

 
高斯函数具有五个重要的性质,这些性质使得它在早期图像处理中特别有用.这些性质表明,高斯平滑滤波器无论在空间域还是在频率域都是十分有效的低通滤波器,且在实际图像处理中得到了工程人员的有效使用.高斯函数具有五个十分重要的性质,它们是:

(1)二维高斯函数具有旋转对称性,即滤波器在各个方向上的平滑程度是相同的.一般来说,一幅图像的边缘方向是事先不知道的,因此,在滤波前是无法确定一个方向上比另一方向上需要更多的平滑.旋转对称性意味着高斯平滑滤波器在后续边缘检测中不会偏向任一方向.
 
(2)高斯函数是单值函数.这表明,高斯滤波器用像素邻域的加权均值来代替该点的像素值,而每一邻域像素点权值是随该点与中心点的距离单调增减的.这一性质是很重要的,因为边缘是一种图像局部特征,如果平滑运算对离算子中心很远的像素点仍然有很大作用,则平滑运算会使图像失真.

(3)高斯函数的付立叶变换频谱是单瓣的.正如下面所示,这一性质是高斯函数付立叶变换等于高斯函数本身这一事实的直接推论.图像常被不希望的高频信号所污染(噪声和细纹理).而所希望的图像特征(如边缘),既含有低频分量,又含有高频分量.高斯函数付立叶变换的单瓣意味着平滑图像不会被不需要的高频信号所污染,同时保留了大部分所需信号.

(4)高斯滤波器宽度(决定着平滑程度)是由参数σ表征的,而且σ和平滑程度的关系是非常简单的.σ越大,高斯滤波器的频带就越宽,平滑程度就越好.通过调节平滑程度参数σ,可在图像特征过分模糊(过平滑)与平滑图像中由于噪声和细纹理所引起的过多的不希望突变量(欠平滑)之间取得折衷.
 

(5)由于高斯函数的可分离性,大高斯滤波器可以得以有效地实现.二维高斯函数卷积可以分两步来进行,首先将图像与一维高斯函数进行卷积,然后将卷积结果与方向垂直的相同一维高斯函数卷积.因此,二维高斯滤波的计算量随滤波模板宽度成线性增长而不是成平方增长.

参考:
http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html

http://www.cnblogs.com/pzxbc/archive/2012/02/14/2351708.html

http://baike.baidu.com/view/1097446.htm?fr=aladdin

Matlab二维高斯图