码迷,mamicode.com
首页 > 其他好文 > 详细

图像编程学习笔记8——图像的平滑(去噪)

时间:2014-05-01 06:49:28      阅读:397      评论:0      收藏:0      [点我收藏+]

标签:com   http   style   blog   class   div   img   c   code   log   t   

第一种方法:高斯模版

以下文字内容copy于<<数字图像处理编程入门>>,code为自己实现,是win32控制台程序。

先举个例子说明一下什么是平滑(smoothing),如下面两幅图所示:可以看到,图3.2比图3.1柔和一些(也模糊一些)。是不是觉得很神奇?其实实现起来很简单。我们将原图中的每一点的灰度和它周围八个点的灰度相加,然后除以9,作为新图中对应点的灰度,就能实现上面的效果。

mamicode.com,码迷

这么做并非瞎蒙,而是有其道理的。大概想一想,也很容易明白。举个例子,就象和面一样,先在中间加点水,然后不断把周围的面和进来,搅拌几次,面就均匀了。

用信号处理的理论来解释,这种做法实现的是一种简单的低通滤波器(low pass filter)。哇,好深奥呀!不要紧,这些理论的内容并不多,而且知道一些理论也是很有好处的。在灰度连续变化的图象中,如果出现了与相邻象素的灰度相差很大的点,比如说一片暗区中突然出现了一个亮点,人眼能很容易觉察到。就象看老电影时,由于胶片太旧,屏幕上经常会出现一些亮斑。这种情况被认为是一种噪声。灰度突变在频域中代表了一种高频分量,低通滤波器的作用就是滤掉高频分量,从而达到减少图象噪声的目的。

为了方便地叙述上面所说的“将原图中的每一点的灰度和它周围八个点的灰度相加,然后除以9,作为新图中对应点的灰度”这一操作,我们采用如下的表示方法:

mamicode.com,码迷(3.1)

这种表示方法有点象矩阵,我们称其为模板(template)。中间的黑点表示中心元素,即,用哪个元素做为处理后的元素。例如[2. 1]表示将自身的2倍加上右边的元素作为新值,而[2 1.]表示将自身加上左边元素的2倍作为新值。

通常,模板不允许移出边界,所以结果图象会比原图小,例如模板是mamicode.com,码迷,原图是mamicode.com,码迷,经过模板操作后的图象为mamicode.com,码迷;其中数字代表灰度,x表示边界上无法进行模板操作的点,通常的做法是复制原图的灰度,不进行任何处理。

模板操作实现了一种邻域运算(NeighborhoodOperation),即某个象素点的结果灰度不仅和该象素灰度有关,而且和其邻域点的值有关。在以后介绍的细化算法中,我们还将接触到邻域运算。模板运算的数学涵义是一种卷积(或互相关)运算,你不需要知道卷积的确切含义,只要有这么一个概念就可以了。

模板运算在图象处理中经常要用到,可以看出,它是一项非常耗时的运算。以

                                                                                        mamicode.com,码迷(3.2)

为例,每个象素完成一次模板操作要用9个乘法、8个加法、1个除法。对于一幅n×n(宽度×高度)的图象,就是9n2个乘法,8n2个加法和n2个除法,算法复杂度为O(n2),这对于大图象来说,是非常可怕的。所以,一般常用的模板并不大,如3×3,4×4。有很多专用的图象处理系统,用硬件来完成模板运算,大大提高了速度。另外,可以设法将二维模板运算转换成一维模板运算,对速度的提高也是非常可观的。例如,(3.2)式可以分解成一个水平模板和一个垂直模板,即,

mamicode.com,码迷

(3.3)

我们来验证一下。

设图象为 mamicode.com,码迷,经过(3.2)式处理后变为mamicode.com,码迷,经过(3.3)式处理后变为mamicode.com,码迷,两者完全一样。如果计算时不考虑周围一圈的象素,前者做了4×(9个乘法,8个加法,1个除法),共36个乘法,32个加法,4个除法;后者做了4×(3个乘法,2个加法)+4×(3个乘法,2个加法)+4个除法,共24个乘法,16个加法,4个除法,运算简化了不少,如果是大图,效率的提高将是非常客观的。

平滑模板的思想是通过将一点和周围8个点作平均,从而去除突然变化的点,滤掉噪声,其代价是图象有一定程度的模糊。上面提到的模板(3.1),就是一种平滑模板,称之为Box模板。Box模板虽然考虑了邻域点的作用,但并没有考虑各点位置的影响,对于所有的9个点都一视同仁,所以平滑的效果并不理想。实际上我们可以想象,离某点越近的点对该点的影响应该越大,为此,我们引入了加权系数,将原来的模板改造成mamicode.com,码迷,可以看出,距离越近的点,加权系数越大。

新的模板也是一个常用的平滑模板,称为高斯(Gauss)模板。为什么叫这个名字,这是因为这个模板是通过采样2维高斯函数得到的。

设图象为 mamicode.com,码迷,分别用两种平滑模板处理(周围一圈象素直接从原图拷贝)。采用Box模板的结果为mamicode.com,码迷,采用高斯模板的结果为mamicode.com,码迷

可以看到,原图中出现噪声的区域是第2行第2列和第3行第2列,灰度从2一下子跳到了6,用Box模板处理后,灰度从3.11跳到4.33;用高斯模板处理后,灰度从3.跳到4.56,都缓和了跳变的幅度,从这一点上看,两者都达到了平滑的目的。但是,原图中的第3,第4行总的来说,灰度值是比较高的,经模板1处理后,第3行第2列元素的灰度变成了4.33,与第3,第4行的总体灰度相比偏小,另外,原图中第3行第2列元素的灰度为6,第3行第3列元素的灰度为4,变换后,后者4.56反而比前者4.33大了。而采用高斯模板没有出现这些问题,究其原因,就是因为它考虑了位置的影响。

举个实际的例子:下图中,从左到右分别是原图,用高斯模板处理的图,用Box模板处理的图,可以看出,采用高斯模板,在实现平滑效果的同时,要比Box模板清晰一些。

mamicode.com,码迷

功能实现函数代码:

 

[cpp] view plaincopy
 
  1. double tem[9] = {1.0,2.0,1.0,2.0,4.0,2.0,1.0,2.0,1.0};  
  2. void smooth()  
  3. {  
  4.     int height = bmpInfoHeader.biHeight;     
  5.     int width = bmpInfoHeader.biWidth;    
  6.     int imgSize = bmpInfoHeader.biSizeImage;  
  7.     int lineByte = (width * 8 +31) / 32 * 4;  //每行像素所占字节数  
  8.     //处理是基于原图的,所以原图的数据不能改变,用pNewBmpData存储改变之后的数据  
  9.     memcpy(pNewBmpData,pBmpData,imgSize);   //把原图数据复制给pNewBmpData  
  10.     double sum;  
  11.     for(int i = 1; i < height - 1; i++ )  
  12.     {  
  13.         for(int j = 1; j < width - 1; j++ )  
  14.         {  
  15.             sum = 0;    //清零  
  16.             sum += (double)(*(pBmpData + (i-1) * lineByte + j - 1)) * tem[0];   //该点左下角  
  17.             sum += (double)(*(pBmpData + (i-1) * lineByte + j)) * tem[1];       //下  
  18.             sum += (double)(*(pBmpData + (i-1) * lineByte + j + 1)) * tem[2];  //右下  
  19.             sum += (double)(*(pBmpData + i * lineByte + j - 1)) * tem[3];  //左  
  20.             sum += (double)(*(pBmpData + i * lineByte + j)) * tem[4];  //该点位置  
  21.             sum += (double)(*(pBmpData + i * lineByte + j + 1)) * tem[5];  //右  
  22.             sum += (double)(*(pBmpData + (i+1) * lineByte + j - 1)) * tem[6];  //左上  
  23.             sum += (double)(*(pBmpData + (i+1) * lineByte + j)) * tem[7];   //上  
  24.             sum += (double)(*(pBmpData + (i+1) * lineByte + j + 1)) * tem[8];  //右上  
  25.             *(pNewBmpData + i * lineByte + j) = (unsigned char)(sum / 16.0);     
  26.         }  
  27.     }  
  28. }  

第二种方法:中值滤波

 

中值滤波也是一种典型的低通滤波器,它的目的是保护图象边缘的同时去除噪声。所谓中值滤波,是指把以某点(x,y)为中心的小窗口内的所有象素的灰度按从大到小的顺序排列,将中间值作为(x,y)处的灰度值(若窗口中有偶数个象素,则取两个中间值的平均)。中值滤波是如何去除噪声的呢?举个例子就很容易明白了。

mamicode.com,码迷

图中数字代表该处的灰度。可以看出原图中间的6和周围的灰度相差很大,是一个噪声点。经过3×1窗口(即水平3个象素取中间值)的中值滤波,得到右边那幅图,可以看出,噪声点被去除了。

下面将中值滤波和上面介绍的两种平滑模板作个比较,看看中值滤波有什么特点。我们以一维模板为例,只考虑水平方向,大小为3×1(宽×高)。Box模板为 mamicode.com,码迷,高斯模板为mamicode.com,码迷 

先考察第一幅图:

mamicode.com,码迷

从原图中不难看出左边区域灰度值低,右边区域灰度值高,中间有一条明显的边界,这一类图象称之为“step”(就象灰度上了个台阶)。应用平滑模板后,图象平滑了,但是也使边界模糊了。应用中值滤波,就能很好地保持原来的边界。所以说,中值滤波的特点是保护图象边缘的同时去除噪声。

再看第二幅图:

mamicode.com,码迷

不难看出,原图中有很多噪声点(灰度为正代表灰度值高的点,灰度为负代表灰度值低的点),而且是杂乱无章,随机分布的。这也是一类很典型的图,称之为高斯噪声。经过Box平滑,噪声的程度有所下降。Gauss模板对付高斯噪声非常有效。而中值滤波对于高斯噪声则无能为力。

最后看第三幅图:

mamicode.com,码迷

从原图中不难看出,中间的灰度要比两边高许多。这也是一类很典型的图,称之为脉冲 (impulse)。可见,中值滤波对脉冲噪声非常有效。

综合以上三类图,不难得出下面的结论:中值滤波容易去除孤立点,线的噪声同时保持图象的边缘;它能很好的去除二值噪声,但对高斯噪声无能为力。要注意的是,当窗口内噪声点的个数大于窗口宽度的一半时,中值滤波的效果不好。这是很显然的。

CODE:

 

[cpp] view plaincopy
 
    1. /** 
    2. * 函数名: medianFilter 
    3. * 功  能: 对图像进行水平中值滤波处理 
    4. */  
    5. void medianFilter()  
    6. {  
    7.     int height = bmpInfoHeader.biHeight;     
    8.     int width = bmpInfoHeader.biWidth;    
    9.     int imgSize = bmpInfoHeader.biSizeImage;  
    10.     int lineByte = (width * 8 +31) / 32 * 4;  //每行像素所占字节数  
    11.     //处理是基于原图的,所以原图的数据不能改变,用pNewBmpData存储改变之后的数据  
    12.     memcpy(pNewBmpData,pBmpData,imgSize);   //把原图数据复制给pNewBmpData  
    13.     unsigned char g[3];   //要取的三个点  
    14.     //注意边界点不处理,所以i从1到高度-2,j类似  
    15.     for(int i = 1; i < height - 1; i++ )  
    16.     {  
    17.         for(int j = 1; j < width - 1; j++ )  
    18.         {  
    19.             g[0] = *(pBmpData + i * lineByte + j - 1);  
    20.             g[1] = *(pBmpData + i * lineByte + j);  
    21.             g[2] = *(pBmpData + i * lineByte + j + 1);  
    22.             sort(g,g+3);   //排序  
    23.             *(pNewBmpData + i * lineByte + j) = g[1];  
    24.         }  
    25.     }  
    26. }  

图像编程学习笔记8——图像的平滑(去噪),码迷,mamicode.com

图像编程学习笔记8——图像的平滑(去噪)

标签:com   http   style   blog   class   div   img   c   code   log   t   

原文地址:http://www.cnblogs.com/lidabo/p/3701999.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!