高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器。高斯平滑滤波器对于抑制服从正态分布 的噪声非常有效。
一维零均值高斯函数为: g(x)=exp( -x^2/(2 sigma^2)) (u=0)
详情参见:http://zh.wikipedia.org/wiki/%E6%AD%A3%E6%80%81%E5%88%86%E5%B8%83
正态分布(Normal distribution)又名高斯分布(Gaussian distribution),是一个在数学、物理及工程等领域都非常重要的概率分布,在统计学的许多方面有着重大的影响力。
若随机变量
服从一个位置参数为
、尺度参数为
的概率分布,记为:
则其概率密度函数为
正态分布的数学期望值或期望值
等于位置参数,决定了分布的位置;其
方差的开平方或
标准差等于尺度参数,决定了分布的幅度。
正态分布的概率密度函数曲线呈钟形,因此人们又经常称之为钟形曲线。我们通常所说的标准正态分布是位置参数
, 尺度参数
的正态分布(见右图中绿色曲线)。
概率密度函数 累积分布函数
绿线代表标准正态分布
其中,高斯分布参数Sigma决定了高斯函数的宽度。 对于图像处理来说,常用二维零均值离散高斯函数作平滑滤波器。
高斯函数具有五个重要的性质,这些性质使得它在早期图像处理中特别有用.这些性质表明,高斯平滑滤波器无论在空间域还是在频率域都是十分有效的低通滤波器,且在实际图像处理中得到了工程人员的有效使用.高斯函数具有五个十分重要的性质,它们是:
(1)二维高斯函数具有旋转对称性,即滤波器在各个方向上的平滑程度是相同的.一般来说,一幅图像的边缘方向是事先不知道的,因此,在滤波前是无法确定一个方向上比另一方向上需要更多的平滑.旋转对称性意味着高斯平滑滤波器在后续边缘检测中不会偏向任一方向.
(2)高斯函数是单值函数.这表明,高斯滤波器用像素邻域的加权均值来代替该点的像素值,而每一邻域像素点权值是随该点与中心点的距离单调增减的.这一性质是很重要的,因为边缘是一种图像局部特征,如果平滑运算对离算子中心很远的像素点仍然有很大作用,则平滑运算会使图像失真.
(3)高斯函数的付立叶变换频谱是单瓣的.正如下面所示,这一性质是高斯函数付立叶变换等于高斯函数本身这一事实的直接推论.图像常被不希望的高频信号所污染(噪声和细纹理).而所希望的图像特征(如边缘),既含有低频分量,又含有高频分量.高斯函数付立叶变换的单瓣意味着平滑图像不会被不需要的高频信号所污染,同时保留了大部分所需信号.???
(4)高斯滤波器宽度(决定着平滑程度)是由参数σ表征的,而且σ和平滑程度的关系是非常简单的.σ越大,高斯滤波器的频带就越宽,平滑程度就越好.通过调节平滑程度参数σ,可在图像特征过分模糊(过平滑)与平滑图像中由于噪声和细纹理所引起的过多的不希望突变量(欠平滑)之间取得折衷.
(5)由于高斯函数的可分离性,较大尺寸的高斯滤波器可以得以有效地实现.二维高斯函数卷积可以分两步来进行,首先将图像与一维高斯函数进行卷积,然后将卷积结果与方向垂直的相同一维高斯函数卷积.因此,二维高斯滤波的计算量随滤波模板宽度成线性增长而不是成平方增长.
图像滤波 (转:http://www.baisi.net/viewthread.php?tid=219452)
1 图像滤波的基本概念
图像常常被强度随机信号(也称为噪声)所污染.一些常见的噪声有椒盐(Salt & Pepper)噪声、脉冲噪声、高斯噪声等.椒盐噪声含有随机出现的黑白强度值.而脉冲噪声则只含有随机的白强度值(正脉冲噪声)或黑强度值(负脉冲噪声).与前两者不同,高斯噪声含有强度服从高斯或正态分布的噪声.研究滤波就是为了消除噪声干扰。
图像滤波总体上讲包括空域滤波和频域滤波。频率滤波需要先进行傅立叶变换至频域处理然后再反变换回空间域还原图像,空域滤波是直接对图像的数据做空间变换达到滤波的目的。它是一种邻域运算,即输出图像中任何像素的值都是通过采用一定的算法,根据输入图像中对用像素周围一定邻域内像素的值得来的。如果输出像素是输入像素邻域像素的线性组合则称为线性滤波(例如最常见的均值滤波和高斯滤波),否则为非线性滤波(中值滤波、边缘保持滤波等)。
线性平滑滤波器去除高斯噪声的效果很好,且在大多数情况下,对其它类型的噪声也有很好的效果。线性滤波器使用连续窗函数内像素加权和来实现滤波。特别典型的是,同一模式的权重因子可以作用在每一个窗口内,也就意味着线性滤波器是空间不变的,这样就可以使用卷积模板来实现滤波。如果图像的不同部分使用不同的滤波权重因子,且仍然可以用滤波器完成加权运算,那么线性滤波器就是空间可变的。任何不是像素加权运算的滤波器都属于非线性滤波器.非线性滤波器也可以是空间不变的,也就是说,在图像的任何位置上可以进行相同的运算而不考虑图像位置或空间的变化。
2 图像滤波的计算过程分析
滤波通常是用卷积或者相关来描述,而线性滤波一般是通过卷积来描述的。他们非常类似,但是还是会有不同。下面我们来根据相关和卷积计算过程来体会一下他们的具体区别:
卷积的计算步骤:
(1) 卷积核绕自己的核心元素顺时针旋转180度
(2) 移动卷积核的中心元素,使它位于输入图像待处理像素的正上方
(3) 在旋转后的卷积核中,将输入图像的像素值作为权重相乘
(4) 第三步各结果的和做为该输入像素对应的输出像素
相关的计算步骤:
(1)移动相关核的中心元素,使它位于输入图像待处理像素的正上方
(2)将输入图像的像素值作为权重,乘以相关核
(3)将上面各步得到的结果相加做为输出
可以看出他们的主要区别在于计算卷积的时候,卷积核要先做旋转。而计算相关过程中不需要旋转相关核。
例如: magic(3) =[8 1 6;3 5 7;4 9 2],旋转180度后就成了[2 9 4;7 5 3;6 1 8]
三 高斯平滑滤波器的设计
高斯函数的最佳逼近由二项式展开的系数决定,换句话说,用杨辉三角形(也称Pascal三角形)的第n行作为高斯滤波器的一个具有n个点的一维逼近,例如,五点逼近为:
1 4 6 4 1
它们对应于Pascal三角形的第5行.这一模板被用来在水平方向上平滑图像.在高斯函数可分离性性质中曾指出,二维高斯滤波器能用两个一维高斯滤波器逐次卷积来实现,一个沿水平方向,一个沿垂直方向.实际中,这种运算可以通过使用单个一维高斯模板,对两次卷积之间的图像和最后卷积的结果图像进行转置来完成.
这一技术在模板尺寸N约为10时的滤波效果极好.对较大的滤波器,二项式展开系数对大多数计算机来说都太多.但是,任意大的高斯滤波器都能通过重复使用小高斯滤波器来实现.高斯滤波器的二项式逼近的σ可用高斯函数拟合二项式系数的最小方差来计算.
设计高斯滤波器的另一途径是直接从离散高斯分布中计算模板权值。为了计算方便,一般希望滤波器权值是整数。在模板的一个角点处取一个值,并选择一个K使该角点处值为1。通过这个系数可以使滤波器整数化,由于整数化后的模板权值之和不等于1,为了保证图像的均匀灰度区域不受影响,必须对滤波模板进行权值规范化。
高斯滤波器的采样值或者高斯滤波器的二项式展开系数可以形成离散高斯滤波器.当用离散高斯滤波器进行卷积时,其结果是一个更大的高斯离散滤波器.若一幅图像用N*N离散高斯滤波器进行平滑,接着再用M*M离散高斯滤波器平滑的话,那么平滑结果就和用(N+M-1)*(N+M-1)离散高斯滤波器平滑的结果一样.换言之,在杨辉三角形中用第N行和第M行卷积形成了第N+M-1行.
几个经典的模板例子:
尝试了使用这些滤波器对我们原来的图进行操作, 得到了这样的一组结果:
原图: 3x3 高斯: 5X5高斯:
单纯从效果来看, 两个模板都起到了平滑的作用, 只是程度有深浅的区分. 那么从理论上来说为什么能起到平滑的作用呢? 很显然, 像素的颜色不仅由自身决定了, 同时有其周围的像素加权决定, 客观上减小了和周围像素的差异. 同时这些权重的设定满足了越近权重越大的规律. 从理论来讲, 这些权重的分布满足了著名的所谓高斯分布:
这就是1维的计算公式
这就是2维的计算公式
x, y表示的就是当前点到对应点的距离, 而那些具体的模板就是由这里公式中的一些特例计算而来. 需要说明的是不只有这么一些特例, 从wikipedia可以方便地找到那些复杂的模板比如像:
Sample Gaussian matrix
This is a sample matrix, produced by sampling the Gaussian filter kernel (with σ = 0.84089642) at the midpoints of each pixel and then normalising. Note that the center element (at [4, 4]) has the largest value, decreasing symmetrically as distance from the center increases.
0.00000067 0.00002292 0.00019117 0.00038771 0.00019117 0.00002292 0.00000067
0.00002292 0.00078633 0.00655965 0.01330373 0.00655965 0.00078633 0.00002292
0.00019117 0.00655965 0.05472157 0.11098164 0.05472157 0.00655965 0.00019117
0.00038771 0.01330373 0.11098164 0.22508352 0.11098164 0.01330373 0.00038771
0.00019117 0.00655965 0.05472157 0.11098164 0.05472157 0.00655965 0.00019117
0.00002292 0.00078633 0.00655965 0.01330373 0.00655965 0.00078633 0.00002292
0.00000067 0.00002292 0.00019117 0.00038771 0.00019117 0.00002292 0.00000067
四 使用高斯滤波器进行图像的平滑
生成高斯核
/*************************************************************************
*
* \函数名称:
* MakeGauss()
*
* \输入参数:
* double sigma - 高斯函数的标准差
* double **pdKernel - 指向高斯数据数组的指针
* int *pnWindowSize - 数据的长度
*
* \返回值:
* 无
*
* \说明:
* 这个函数可以生成一个一维的高斯函数的数字数据,理论上高斯数据的长度应
* 该是无限长的,但是为了计算的简单和速度,实际的高斯数据只能是有限长的
* pnWindowSize就是数据长度
*
*************************************************************************
*/
void MakeGauss(double sigma, double **pdKernel, int *pnWindowSize)
{
// 循环控制变量
int i ;
// 数组的中心点
int nCenter;
// 数组的某一点到中心点的距离
double dDis ;
double PI = 3.14159;
// 中间变量
double dValue;
double dSum ;
dSum = 0 ;
// 数组长度,根据概率论的知识,选取[-3*sigma, 3*sigma]以内的数据。
// 这些数据会覆盖绝大部分的滤波系数
*pnWindowSize = 1 + 2 * ceil(3 * sigma);
// 中心
nCenter = (*pnWindowSize) / 2;
// 分配内存
*pdKernel = new double[*pnWindowSize] ;
for(i=0; i< (*pnWindowSize); i++)
{
dDis = (double)(i - nCenter);
dValue = exp(-(1/2)*dDis*dDis/(sigma*sigma)) / (sqrt(2 * PI) * sigma );
(*pdKernel)[i] = dValue ;
dSum += dValue;
}
// 归一化
for(i=0; i<(*pnWindowSize) ; i++)
{
(*pdKernel)[i] /= dSum;
}
}
高斯滤波
/*************************************************************************
*
* \函数名称:
* GaussianSmooth()
*
* \输入参数:
* unsigned char * pUnchImg - 指向图象数据的指针
* int nWidth - 图象数据宽度
* int nHeight - 图象数据高度
* double dSigma - 高斯函数的标准差
* unsigned char * pUnchSmthdImg - 指向经过平滑之后的图象数据
*
* \返回值:
* 无
*
* \说明:
* 为了抑止噪声,采用高斯滤波对图象进行滤波,滤波先对x方向进行,然后对
* y方向进行。
*
*************************************************************************
*/
void GaussianSmooth(unsigned char *pUnchImg, int nWidth, int nHeight,
double sigma, unsigned char * pUnchSmthdImg)
{
// 循环控制变量
int y;
int x;
int i;
// 高斯滤波器的数组长度
int nWindowSize;
// 窗口长度的1/2
int nHalfLen;
// 一维高斯数据滤波器
double *pdKernel ;
// 高斯系数与图象数据的点乘
double dDotMul ;
// 高斯滤波系数的总和
double dWeightSum ;
// 中间变量
double * pdTmp ;
// 分配内存
pdTmp = new double[nWidth*nHeight];
// 产生一维高斯数据滤波器
// MakeGauss(sigma, &dKernel, &nWindowSize);
MakeGauss(sigma, &pdKernel, &nWindowSize) ;
// MakeGauss返回窗口的长度,利用此变量计算窗口的半长
nHalfLen = nWindowSize / 2;
// x方向进行滤波
for(y=0; y<nHeight; y++)
{
for(x=0; x<nWidth; x++)
{
dDotMul = 0;
dWeightSum = 0;
for(i=(-nHalfLen); i<=nHalfLen; i++)
{
// 判断是否在图象内部
if( (i+x) >= 0 && (i+x) < nWidth )
{
dDotMul += (double)pUnchImg[y*nWidth + (i+x)] * pdKernel[nHalfLen+i];
dWeightSum += pdKernel[nHalfLen+i];
}
}
pdTmp[y*nWidth + x] = dDotMul/dWeightSum ;
}
}
// y方向进行滤波
for(x=0; x<nWidth; x++)
{
for(y=0; y<nHeight; y++)
{
dDotMul = 0;
dWeightSum = 0;
for(i=(-nHalfLen); i<=nHalfLen; i++)
{
// 判断是否在图象内部
if( (i+y) >= 0 && (i+y) < nHeight )
{
dDotMul += (double)pdTmp[(y+i)*nWidth + x] * pdKernel[nHalfLen+i];
dWeightSum += pdKernel[nHalfLen+i];
}
}
pUnchSmthdImg[y*nWidth + x] = (unsigned char)(int)dDotMul/dWeightSum ;
}
}
// 释放内存
delete []pdKernel;
pdKernel = NULL ;
delete []pdTmp;
pdTmp = NULL;
}