数字图像处理编程---3图象的平滑(去噪声)、锐化
<div style="LAYOUT-GRID-CHAR: none; LAYOUT-GRID-LINE: 15.6pt;"><h1><a name="_Toc486331873"></a><a name="_Toc486332873"></a><a name="_Toc486338982"></a><a name="_Toc454810847"></a><a name="_Toc454856621"><span><span><span lang="EN-US">3</span></span></span></a><span><span> </span></span><span><span><span style="FONT-FAMILY: 黑体;">图象的平滑</span><span lang="EN-US">(</span></span></span><span><span><span style="FONT-FAMILY: 黑体;">去噪声</span><span lang="EN-US">)</span></span></span><span><span><span style="FONT-FAMILY: 黑体;">、锐化</span></span></span></h1><h2><span lang="EN-US">3.1</span> <span lang="EN-US"></span><a name="_Toc486331874"></a><a name="_Toc486332874"></a><a name="_Toc486338983"></a><a name="_Toc454810848"></a><a name="_Toc454856622"><span><span>平滑</span></span></a></h2><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">先举个例子说明一下什么是平滑</span><span lang="EN-US">(smoothing)</span><span style="FONT-FAMILY: 宋体;">,如下面两幅图所示:可以看到,图</span><span lang="EN-US">3.2</span><span style="FONT-FAMILY: 宋体;">比图</span><span lang="EN-US">3.1</span><span style="FONT-FAMILY: 宋体;">柔和一些</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体;">也模糊一些</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体;">。是不是觉得很神奇?其实实现起来很简单。我们将原图中的每一点的灰度和它周围八个点的灰度相加,然后除以</span><span lang="EN-US">9</span><span style="FONT-FAMILY: 宋体;">,作为新图中对应点的灰度,就能实现上面的效果。</span></p><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="Normal" valign="top" width="276"><p class="a" style="LINE-HEIGHT: 18pt;"><span lang="EN-US"><img height="189" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image001.gif" width="170" vshapes="_x0000_i1043" alt=""/> </span></p><p class="a" style="LINE-HEIGHT: 18pt;"><b><span style="FONT-FAMILY: 宋体;">图</span>3.1 </b><b><span style="FONT-FAMILY: 宋体;">原图</span><span lang="EN-US"></span></b></p></td><td class="Normal" valign="top" width="276"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><img height="188" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image003.gif" width="168" vshapes="_x0000_i1042" alt=""/> </span></p><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><b><span style="FONT-FAMILY: 宋体;">图</span>3.2 </b><b><span style="FONT-FAMILY: 宋体;">经过平滑处理后的图</span><span lang="EN-US"></span></b></p></td></tr></tbody></table><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">这么做并非瞎蒙,而是有其道理的。大概想一想,也很容易明白。举个例子,就象和面一样,先在中间加点水,然后不断把周围的面和进来,搅拌几次,面就均匀了。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">用信号处理的理论来解释,这种做法实现的是一种简单的低通滤波器</span><span lang="EN-US">(low pass filter)</span><span style="FONT-FAMILY: 宋体;">。哇,好深奥呀!不要紧,这些理论的内容并不多,而且知道一些理论也是很有好处的。在灰度连续变化的图象中,如果出现了与相邻象素的灰度相差很大的点,比如说一片暗区中突然出现了一个亮点,人眼能很容易觉察到。就象看老电影时,由于胶片太旧,屏幕上经常会出现一些亮斑。这种情况被认为是一种噪声。灰度突变在频域中代表了一种高频分量,低通滤波器的作用就是滤掉高频分量,从而达到减少图象噪声的目的。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">为了方便地叙述上面所说的“将原图中的每一点的灰度和它周围八个点的灰度相加,然后除以</span><span lang="EN-US">9</span><span style="FONT-FAMILY: 宋体;">,作为新图中对应点的灰度”这一操作,我们采用如下的表示方法:</span></p><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><b><span lang="EN-US"><sub><img height="75" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image005.gif" width="92" vshapes="_x0000_i1044" alt=""/> </sub></span></b></p><p align="right" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: right;"><span lang="EN-US">(3.1)<b></b></span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">这种表示方法有点象矩阵,我们称其为模板</span><span lang="EN-US">(template)</span><span style="FONT-FAMILY: 宋体;">。中间的黑点表示中心元素,即,用哪个元素做为处理后的元素。例如</span><span lang="EN-US"></span><span style="FONT-FAMILY: 宋体;">表示将自身的</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体;">倍加上右边的元素作为新值,而</span><span lang="EN-US"></span><span style="FONT-FAMILY: 宋体;">表示将自身加上左边元素的</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体;">倍作为新值。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">通常,模板不允许移出边界,所以结果图象会比原图小,例如模板是</span><span lang="EN-US"><sub> <img height="48" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image007.gif" width="51" vshapes="_x0000_i1045" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">,原图是</span><span lang="EN-US"><sub> <img height="96" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image009.gif" width="119" vshapes="_x0000_i1046" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">,经过模板操作后的图象为</span><span lang="EN-US"><sub> <img height="96" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image011.gif" width="120" vshapes="_x0000_i1047" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">;其中数字代表灰度,</span><span lang="EN-US">x</span><span style="FONT-FAMILY: 宋体;">表示边界上无法进行模板操作的点,通常的做法是复制原图的灰度,不进行任何处理。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">模板操作实现了一种邻域运算</span><span lang="EN-US">(Neighborhood Operation)</span><span style="FONT-FAMILY: 宋体;">,即某个象素点的结果灰度不仅和该象素灰度有关,而且和其邻域点的值有关。在以后介绍的细化算法中,我们还将接触到邻域运算。模板运算的数学涵义是一种卷积</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体;">或互相关</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体;">运算,你不需要知道卷积的确切含义,只要有这么一个概念就可以了。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">模板运算在图象处理中经常要用到,可以看出,它是一项非常耗时的运算。以</span></p><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="75" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image013.gif" width="107" vshapes="_x0000_i1069" alt=""/> </sub></span></p><p align="right" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: right;"><span lang="EN-US">(3.2)</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">为例,每个象素完成一次模板操作要用</span><span lang="EN-US">9</span><span style="FONT-FAMILY: 宋体;">个乘法、</span><span lang="EN-US">8</span><span style="FONT-FAMILY: 宋体;">个加法、</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体;">个除法。对于一幅</span><span lang="EN-US">n</span><span style="FONT-FAMILY: 宋体;">×</span><span lang="EN-US">n(</span><span style="FONT-FAMILY: 宋体;">宽度×高度</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体;">的图象,就是</span><span lang="EN-US">9n<sup>2</sup></span><span style="FONT-FAMILY: 宋体;">个乘法,</span><span lang="EN-US">8n<sup>2</sup></span><span style="FONT-FAMILY: 宋体;">个加法和</span><span lang="EN-US">n<sup>2</sup></span><span style="FONT-FAMILY: 宋体;">个除法,算法复杂度为</span><span lang="EN-US">O(n<sup>2</sup>)</span><span style="FONT-FAMILY: 宋体;">,这对于大图象来说,是非常可怕的。所以,一般常用的模板并不大,如</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">×</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">,</span><span lang="EN-US">4</span><span style="FONT-FAMILY: 宋体;">×</span><span lang="EN-US">4</span><span style="FONT-FAMILY: 宋体;">。有很多专用的图象处理系统,用硬件来完成模板运算,大大提高了速度。另外,可以设法将二维模板运算转换成一维模板运算,对速度的提高也是非常可观的。例如,</span><span lang="EN-US">(3.2)</span><span style="FONT-FAMILY: 宋体;">式可以分解成一个水平模板和一个垂直模板,即,</span></p><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="75" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image014.gif" width="107" vshapes="_x0000_i1070" alt=""/> </sub>=<sub> <img height="41" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image016.gif" width="88" vshapes="_x0000_i1071" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">×</span> <span lang="EN-US"><sub><img height="75" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image018.gif" width="55" vshapes="_x0000_i1072" alt=""/> </sub>=<sub> <img height="75" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image020.gif" width="133" vshapes="_x0000_i1073" alt=""/> </sub></span></p><p align="right" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: right;"><span lang="EN-US">(3.3)</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">我们来验证一下。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">设图象为</span><span lang="EN-US"><sub> <img height="96" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image022.gif" width="96" vshapes="_x0000_i1074" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">,经过</span><span lang="EN-US">(3.2)</span><span style="FONT-FAMILY: 宋体;">式处理后变为</span><span lang="EN-US"><sub> <img height="96" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image024.gif" width="136" vshapes="_x0000_i1075" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">,经过</span><span lang="EN-US">(3.3)</span><span style="FONT-FAMILY: 宋体;">式处理后变为</span><span lang="EN-US"><sub> <img height="96" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image026.gif" width="136" vshapes="_x0000_i1076" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">,两者完全一样。如果计算时不考虑周围一圈的象素,前者做了</span><span lang="EN-US">4</span><span style="FONT-FAMILY: 宋体;">×</span><span lang="EN-US">(9</span><span style="FONT-FAMILY: 宋体;">个乘法,</span><span lang="EN-US">8</span><span style="FONT-FAMILY: 宋体;">个加法,</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体;">个除法</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体;">,共</span><span lang="EN-US">36</span><span style="FONT-FAMILY: 宋体;">个乘法,</span><span lang="EN-US">32</span><span style="FONT-FAMILY: 宋体;">个加法,</span><span lang="EN-US">4</span><span style="FONT-FAMILY: 宋体;">个除法;后者做了</span><span lang="EN-US">4</span><span style="FONT-FAMILY: 宋体;">×</span><span lang="EN-US">(3</span><span style="FONT-FAMILY: 宋体;">个乘法,</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体;">个加法</span><span lang="EN-US">)+4</span><span style="FONT-FAMILY: 宋体;">×</span><span lang="EN-US">(3</span><span style="FONT-FAMILY: 宋体;">个乘法,</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体;">个加法</span><span lang="EN-US">)+4</span><span style="FONT-FAMILY: 宋体;">个除法,共</span><span lang="EN-US">24</span><span style="FONT-FAMILY: 宋体;">个乘法,</span><span lang="EN-US">16</span><span style="FONT-FAMILY: 宋体;">个加法,</span><span lang="EN-US">4</span><span style="FONT-FAMILY: 宋体;">个除法,运算简化了不少,如果是大图,效率的提高将是非常客观的。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">平滑模板的思想是通过将一点和周围</span><span lang="EN-US">8</span><span style="FONT-FAMILY: 宋体;">个点作平均,从而去除突然变化的点,滤掉噪声,其代价是图象有一定程度的模糊。上面提到的模板</span><span lang="EN-US">(3.1)</span><span style="FONT-FAMILY: 宋体;">,就是一种平滑模板,称之为</span><span lang="EN-US">Box</span><span style="FONT-FAMILY: 宋体;">模板。</span><span lang="EN-US">Box</span><span style="FONT-FAMILY: 宋体;">模板虽然考虑了邻域点的作用,但并没有考虑各点位置的影响,对于所有的</span><span lang="EN-US">9</span><span style="FONT-FAMILY: 宋体;">个点都一视同仁,所以平滑的效果并不理想。实际上我们可以想象,离某点越近的点对该点的影响应该越大,为此,我们引入了加权系数,将原来的模板改造成</span><span lang="EN-US"><sub> <img height="75" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image027.gif" width="107" vshapes="_x0000_i1077" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">,可以看出,距离越近的点,加权系数越大。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">新的模板也是一个常用的平滑模板,称为高斯</span><span lang="EN-US">(Gauss)</span><span style="FONT-FAMILY: 宋体;">模板。为什么叫这个名字,这是因为这个模板是通过采样</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体;">维高斯函数得到的。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">设图象为</span><span lang="EN-US"><sub> <img height="96" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image028.gif" width="96" vshapes="_x0000_i1078" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">,分别用两种平滑模板处理</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体;">周围一圈象素直接从原图拷贝</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体;">。采用</span><span lang="EN-US">Box</span><span style="FONT-FAMILY: 宋体;">模板的结果为</span><span lang="EN-US"><sub> <img height="96" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image030.gif" width="135" vshapes="_x0000_i1079" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">,采用高斯模板的结果为</span><span lang="EN-US"><sub> <img height="96" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image032.gif" width="136" vshapes="_x0000_i1080" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">可以看到,原图中出现噪声的区域是第</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体;">行第</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体;">列和第</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">行第</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体;">列,灰度从</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体;">一下子跳到了</span><span lang="EN-US">6</span><span style="FONT-FAMILY: 宋体;">,用</span><span lang="EN-US">Box</span><span style="FONT-FAMILY: 宋体;">模板处理后,灰度从</span><span lang="EN-US">3.11</span><span style="FONT-FAMILY: 宋体;">跳到</span><span lang="EN-US">4.33</span><span style="FONT-FAMILY: 宋体;">;用高斯模板处理后,灰度从</span><span lang="EN-US">3.</span><span style="FONT-FAMILY: 宋体;">跳到</span><span lang="EN-US">4.56,</span><span style="FONT-FAMILY: 宋体;">都缓和了跳变的幅度,从这一点上看,两者都达到了平滑的目的。但是,原图中的第</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">,第</span><span lang="EN-US">4</span><span style="FONT-FAMILY: 宋体;">行总的来说,灰度值是比较高的,经模板</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体;">处理后,第</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">行第</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体;">列元素的灰度变成了</span><span lang="EN-US">4.33</span><span style="FONT-FAMILY: 宋体;">,与第</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">,第</span><span lang="EN-US">4</span><span style="FONT-FAMILY: 宋体;">行的总体灰度相比偏小,另外,原图中第</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">行第</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体;">列元素的灰度为</span><span lang="EN-US">6</span><span style="FONT-FAMILY: 宋体;">,第</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">行第</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">列元素的灰度为</span><span lang="EN-US">4</span><span style="FONT-FAMILY: 宋体;">,变换后,后者</span><span lang="EN-US">4.56</span><span style="FONT-FAMILY: 宋体;">反而比前者</span><span lang="EN-US">4.33</span><span style="FONT-FAMILY: 宋体;">大了。而采用高斯模板没有出现这些问题,究其原因,就是因为它考虑了位置的影响。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">举个实际的例子:下图中,从左到右分别是原图,用高斯模板处理的图,用</span><span lang="EN-US">Box</span><span style="FONT-FAMILY: 宋体;">模板处理的图,可以看出,采用高斯模板,在实现平滑效果的同时,要比</span><span lang="EN-US">Box</span><span style="FONT-FAMILY: 宋体;">模板清晰一些。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">在学习锐化后,我们将给出一个通用的</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">×</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">模板操作的程序。</span></p><p class="a" style="LINE-HEIGHT: 18pt;"><span lang="EN-US"><img height="193" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image033.gif" width="537" vshapes="_x0000_i1039" alt=""/> </span></p><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><b><span style="FONT-FAMILY: 宋体;">图</span>3.3 </b><b><span style="FONT-FAMILY: 宋体;">高斯模板和</span><span lang="EN-US">Box</span></b><b><span style="FONT-FAMILY: 宋体;">模板的对比图</span><span lang="EN-US"></span></b></p><h2><span lang="EN-US">3.2</span> <span lang="EN-US"></span><a name="_Toc486331875"></a><a name="_Toc486332875"></a><a name="_Toc486338984"></a><a name="_Toc454810849"></a><a name="_Toc454856623"><span><span>中值滤波</span></span></a></h2><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">中值滤波也是一种典型的低通滤波器,它的目的是保护图象边缘的同时去除噪声。所谓中值滤波,是指把以某点</span><span lang="EN-US">(x,y)</span><span style="FONT-FAMILY: 宋体;">为中心的小窗口内的所有象素的灰度按从大到小的顺序排列,将中间值作为</span><span lang="EN-US">(x,y)</span><span style="FONT-FAMILY: 宋体;">处的灰度值</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体;">若窗口中有偶数个象素,则取两个中间值的平均</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体;">。中值滤波是如何去除噪声的呢?举个例子就很容易明白了。</span></p><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="Normal" valign="top" width="276"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">原图</span></p></td><td class="Normal" valign="top" width="276"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">处理后的图</span></p></td></tr><tr><td class="Normal" valign="top" width="276"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="141" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image035.gif" width="149" vshapes="_x0000_i1040" alt=""/> </sub></span></p></td><td class="Normal" valign="top" width="276"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="141" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image037.gif" width="104" vshapes="_x0000_i1041" alt=""/> </sub></span></p></td></tr></tbody></table><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">图中数字代表该处的灰度。可以看出原图中间的</span><span lang="EN-US">6</span><span style="FONT-FAMILY: 宋体;">和周围的灰度相差很大,是一个噪声点。经过</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">×</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体;">窗口</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体;">即水平</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">个象素取中间值</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体;">的中值滤波,得到右边那幅图,可以看出,噪声点被去除了。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">下面将中值滤波和上面介绍的两种平滑模板作个比较,看看中值滤波有什么特点。我们以一维模板为例,只考虑水平方向,大小为</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">×</span><span lang="EN-US">1(</span><span style="FONT-FAMILY: 宋体;">宽×高</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体;">。</span><span lang="EN-US">Box</span><span style="FONT-FAMILY: 宋体;">模板为</span><span lang="EN-US"><sub> <img height="41" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image039.gif" width="85" vshapes="_x0000_i1033" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">,高斯模板为</span><span lang="EN-US"><sub> <img height="41" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image041.gif" width="88" vshapes="_x0000_i1034" alt=""/> </sub></span><span style="FONT-FAMILY: 宋体;">。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">先考察第一幅图:</span></p><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="Normal" valign="top" width="141"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">原图</span></p></td><td class="Normal" valign="top" width="137"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">经</span><span lang="EN-US">Box</span><span style="FONT-FAMILY: 宋体;">模板处理后</span></p></td><td class="Normal" valign="top" width="137"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">经</span><span lang="EN-US">Gauss</span><span style="FONT-FAMILY: 宋体;">模板处理后</span></p></td><td class="Normal" valign="top" width="136"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">经中值滤波处理后</span></p></td></tr><tr><td class="Normal" width="141"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="112" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image043.gif" width="127" vshapes="_x0000_i1035" alt=""/> </sub></span></p></td><td class="Normal" width="137"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="155" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image045.gif" width="104" vshapes="_x0000_i1036" alt=""/> </sub></span></p></td><td class="Normal" width="137"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="155" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image047.gif" width="117" vshapes="_x0000_i1037" alt=""/> </sub></span></p></td><td class="Normal" width="136"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="112" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image049.gif" width="84" vshapes="_x0000_i1038" alt=""/> </sub></span></p></td></tr></tbody></table><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">从原图中不难看出左边区域灰度值低,右边区域灰度值高,中间有一条明显的边界</span><span lang="EN-US">,</span><span style="FONT-FAMILY: 宋体;">这一类图象称之为</span><span lang="EN-US">“step”(</span><span style="FONT-FAMILY: 宋体;">就象灰度上了个台阶</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体;">。应用平滑模板后,图象平滑了,但是也使边界模糊了。应用中值滤波,就能很好地保持原来的边界。所以说,中值滤波的特点是保护图象边缘的同时去除噪声。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">再看第二幅图:</span></p><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="Normal" valign="top" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">原图</span></p></td><td class="Normal" valign="top" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">经</span><span lang="EN-US">Box</span><span style="FONT-FAMILY: 宋体;">模板处理后</span></p></td><td class="Normal" valign="top" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">经</span><span lang="EN-US">Gauss</span><span style="FONT-FAMILY: 宋体;">模板处理后</span></p></td><td class="Normal" valign="top" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">经中值滤波处理后</span></p></td></tr><tr><td class="Normal" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="99" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image051.gif" width="159" vshapes="_x0000_i1025" alt=""/> </sub></span></p></td><td class="Normal" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="131" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image053.gif" width="100" vshapes="_x0000_i1026" alt=""/> </sub></span></p></td><td class="Normal" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="93" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image055.gif" width="59" vshapes="_x0000_i1027" alt=""/> </sub></span></p></td><td class="Normal" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="99" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image057.gif" width="91" vshapes="_x0000_i1028" alt=""/> </sub></span></p></td></tr></tbody></table><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">不难看出,原图中有很多噪声点</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体;">灰度为正代表灰度值高的点,灰度为负代表灰度值低的点</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体;">,而且是杂乱无章,随机分布的。这也是一类很典型的图,称之为高斯噪声。经过</span><span lang="EN-US">Box</span><span style="FONT-FAMILY: 宋体;">平滑,噪声的程度有所下降。</span><span lang="EN-US">Gauss</span><span style="FONT-FAMILY: 宋体;">模板对付高斯噪声非常有效。而中值滤波对于高斯噪声则无能为力。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">最后看第三幅图:</span></p><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="Normal" valign="top" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">原图</span></p></td><td class="Normal" valign="top" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">经</span><span lang="EN-US">Box</span><span style="FONT-FAMILY: 宋体;">模板处理后</span></p></td><td class="Normal" valign="top" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">经</span><span lang="EN-US">Gauss</span><span style="FONT-FAMILY: 宋体;">模板处理后</span></p></td><td class="Normal" valign="top" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span style="FONT-FAMILY: 宋体;">经中值滤波处理后</span></p></td></tr><tr><td class="Normal" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="71" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image059.gif" width="105" vshapes="_x0000_i1029" alt=""/> </sub></span></p></td><td class="Normal" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="116" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image061.gif" width="85" vshapes="_x0000_i1030" alt=""/> </sub></span></p></td><td class="Normal" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="116" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image063.gif" width="76" vshapes="_x0000_i1031" alt=""/> </sub></span></p></td><td class="Normal" width="138"><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="71" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image065.gif" width="59" vshapes="_x0000_i1032" alt=""/> </sub></span></p></td></tr></tbody></table><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">从原图中不难看出,中间的灰度要比两边高许多。这也是一类很典型的图,称之为脉冲</span><span lang="EN-US"> (impulse)</span><span style="FONT-FAMILY: 宋体;">。可见,中值滤波对脉冲噪声非常有效。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">综合以上三类图,不难得出下面的结论:中值滤波容易去除孤立点,线的噪声同时保持图象的边缘;它能很好的去除二值噪声,但对高斯噪声无能为力。要注意的是,当窗口内噪声点的个数大于窗口宽度的一半时,中值滤波的效果不好。这是很显然的。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">下面的程序实现了中值滤波,参数</span><span lang="EN-US">Hori</span><span style="FONT-FAMILY: 宋体;">是一个布尔变量,若为真,做水平中值滤波,否则,做垂直中值滤波。</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">BOOL MedianFilter(HWND hWnd,BOOL Hori)</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">{</span></p><p style="LINE-HEIGHT: 18pt;">DWORD OffBits,BufSize;</p><p style="LINE-HEIGHT: 18pt;">LPBITMAPINFOHEADER lpImgData;</p><p style="LINE-HEIGHT: 18pt;">LPSTR lpPtr;</p><p style="LINE-HEIGHT: 18pt;">HLOCAL hTempImgData;</p><p style="LINE-HEIGHT: 18pt;">LPBITMAPINFOHEADER lpTempImgData;</p><p style="LINE-HEIGHT: 18pt;">LPSTR lpTempPtr;</p><p style="LINE-HEIGHT: 18pt;">HDC hDc;</p><p style="LINE-HEIGHT: 18pt;">HFILE hf;</p><p style="LINE-HEIGHT: 18pt;">LONG x,y;</p><p style="LINE-HEIGHT: 18pt;">int g,g1,g2,g3;</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">//OffBits</span><span style="FONT-FAMILY: 宋体;">为</span><span lang="EN-US">BITMAPINFOHEADER</span><span style="FONT-FAMILY: 宋体;">结构长度加调色板的大小</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">BufSize=OffBits+bi.biHeight*LineBytes;//</span><span style="FONT-FAMILY: 宋体;">要开的缓冲区的大小</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL)</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">{</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">MessageBox(hWnd,"Error alloc memory!","Error Message",MB_OK|</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">MB_ICONEXCLAMATION);</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">return FALSE;</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">}</span></p><p style="LINE-HEIGHT: 18pt;">lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData); </p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">//</span><span style="FONT-FAMILY: 宋体;">拷贝头信息及位图数据</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">memcpy(lpTempImgData,lpImgData,BufSize);</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">//</span><span style="FONT-FAMILY: 宋体;">注意边界点不处理,所以</span><span lang="EN-US">y</span><span style="FONT-FAMILY: 宋体;">从</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体;">到高度</span><span lang="EN-US">-2</span><span style="FONT-FAMILY: 宋体;">,</span><span lang="EN-US">x</span><span style="FONT-FAMILY: 宋体;">类似</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">for(y=1;y<bi.biHeight-1;y++)</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>for(x=1;x<bi.biWidth-1;x++){</p><p style="LINE-HEIGHT: 18pt;"><span> </span>lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes)+x;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>lpTempPtr=(char*)lpTempImgData+</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">(BufSize-LineBytes-y*LineBytes)+x;</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>g2=(unsigned char)*(lpPtr);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>if(Hori){ //<span style="FONT-FAMILY: 宋体;">水平方向</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>g1=(unsigned char)*(lpPtr-1); //<span style="FONT-FAMILY: 宋体;">左邻点</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>g3=(unsigned char)*(lpPtr+1); //<span style="FONT-FAMILY: 宋体;">右邻点</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>}</p><p style="LINE-HEIGHT: 18pt;"><span> </span>else{ //<span style="FONT-FAMILY: 宋体;">垂直方向</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span> g1=(unsigned char)*(lpPtr+LineBytes); //<span style="FONT-FAMILY: 宋体;">上邻点</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>g3=(unsigned char)*(lpPtr-LineBytes); //<span style="FONT-FAMILY: 宋体;">下邻点</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>}</p><p style="LINE-HEIGHT: 18pt;"><span> </span>//<span style="FONT-FAMILY: 宋体;">三者取中</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>if(g1>g2){</p><p style="LINE-HEIGHT: 18pt;"><span> </span>if(g2>g3) g=g2;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>else{</p><p style="LINE-HEIGHT: 18pt;"><span> </span>if(g1>g3) g=g3;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>else g=g1;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>}</p><p style="LINE-HEIGHT: 18pt;"><span> </span>}</p><p style="LINE-HEIGHT: 18pt;"><span> </span>else{ //g1<=g2</p><p style="LINE-HEIGHT: 18pt;"><span> </span>if(g1>g3) g=g1;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>else{ </p><p style="LINE-HEIGHT: 18pt;"><span> </span>if(g2>g3) g=g3;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>else g=g2;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>}</p><p style="LINE-HEIGHT: 18pt;"><span> </span>}</p><p style="LINE-HEIGHT: 18pt;"><span> </span>*lpTempPtr=(BYTE)g; //<span style="FONT-FAMILY: 宋体;">存入新的缓冲区内</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>}</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">hDc=GetDC(hWnd);</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span> if(hBitmap!=NULL)</p><p style="LINE-HEIGHT: 18pt;"><span> </span>DeleteObject(hBitmap);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>//<span style="FONT-FAMILY: 宋体;">产生新的位图</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData,</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">(LONG)CBM_INIT,</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">(LPSTR)lpTempImgData+</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">sizeof(BITMAPINFOHEADER)+</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">NumColors*sizeof(RGBQUAD),</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span> (LPBITMAPINFO)lpTempImgData,</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">DIB_RGB_COLORS);</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">if(Hori) //</span><span style="FONT-FAMILY: 宋体;">取不同的结果文件名</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>hf=_lcreat("c:\\hmedian.bmp",0);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>else</p><p style="LINE-HEIGHT: 18pt;"><span> </span>hf=_lcreat("c:\\vmedian.bmp",0);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>_lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER)); </p><p style="LINE-HEIGHT: 18pt;"><span> </span>_lwrite(hf,(LPSTR)lpTempImgData,BufSize);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>_lclose(hf);</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">//</span><span style="FONT-FAMILY: 宋体;">释放内存及资源</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span> ReleaseDC(hWnd,hDc);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>LocalUnlock(hTempImgData);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>LocalFree(hTempImgData);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>GlobalUnlock(hImgData);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>return TRUE;</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">}</span></p><h2><span lang="EN-US">3.3</span> <span lang="EN-US"></span><a name="_Toc486331876"></a><a name="_Toc486332876"></a><a name="_Toc486338985"></a><a name="_Toc454810850"></a><a name="_Toc454856624"><span><span>锐化</span></span></a></h2><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">锐化</span><span lang="EN-US">(sharpening)</span><span style="FONT-FAMILY: 宋体;">和平滑恰恰相反,它是通过增强高频分量来减少图象中的模糊,因此又称为高通滤波</span><span lang="EN-US">(high pass filter)</span><span style="FONT-FAMILY: 宋体;">。锐化处理在增强图象边缘的同时增加了图象的噪声。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">常用的锐化模板是拉普拉斯</span><span lang="EN-US">(Laplacian)</span><span style="FONT-FAMILY: 宋体;">模板</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体;">见</span><span lang="EN-US">(3.4)</span><span style="FONT-FAMILY: 宋体;">式</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体;">,又是个数学家的名字,可见学好数学,走遍天下都不怕。</span></p><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><sub><img height="75" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image067.gif" width="100" vshapes="_x0000_i1081" alt=""/> </sub></span></p><p align="right" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: right;"><span lang="EN-US">(3.4)</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">容易看出拉普拉斯模板的作法:先将自身与周围的</span><span lang="EN-US">8</span><span style="FONT-FAMILY: 宋体;">个象素相减,表示自身与周围象素的差别;再将这个差别加上自身作为新象素的灰度。可见,如果一片暗区出现了一个亮点,那么锐化处理的结果是这个亮点变得更亮,增加了图象的噪声。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">因为图象中的边缘就是那些灰度发生跳变的区域,所以锐化模板在边缘检测中很有用,这一点将在后面详细介绍。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">图</span><span lang="EN-US">3.1</span><span style="FONT-FAMILY: 宋体;">经过拉普拉斯模板处理后,如图</span><span lang="EN-US">3.4</span><span style="FONT-FAMILY: 宋体;">所示</span></p><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><span lang="EN-US"><img height="193" src="mk:@MSITStore:H:\200541352851453.chm::/6.files/image068.gif" width="174" vshapes="_x0000_i1082" alt=""/> </span></p><p align="center" style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center;"><b><span style="FONT-FAMILY: 宋体;">图</span>3.4 </b><b><span style="FONT-FAMILY: 宋体;">锐化</span><span lang="EN-US"></span></b></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">下面给出的程序是一个通用的</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">×</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体;">模板的函数,其中第二参数为模板类型,为如下定义的常量:</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">#define TEMPLATE_SMOOTH_BOX 1 //Box</span><span style="FONT-FAMILY: 宋体;">平滑模板</span></p><p style="LINE-HEIGHT: 18pt;">#define TEMPLATE_SMOOTH_GAUSS 2 //<span style="FONT-FAMILY: 宋体;">高斯平滑模板</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">#define TEMPLATE_SHARPEN_LAPLACIAN 3 //</span><span style="FONT-FAMILY: 宋体;">拉普拉斯锐化模板</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">对应的模板数组如下</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">int Template_Smooth_Box={1,1,1,1,1,1,1,1,1};</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">int Template_Smooth_Gauss={1,2,1,2,4,2,1,2,1};</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">int Template_Sharpen_Laplacian={-1,-1,-1,-1,9,-1,-1,-1,-1};</span><span lang="EN-US" style="FONT-SIZE: 9pt;"></span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">以后我们碰到其它的模板,仍然要用这个函数,所做的操作只是增加一个常量标识,及其对应的模板数组。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">要注意的是,运算后如果出现了大于</span><span lang="EN-US">255</span><span style="FONT-FAMILY: 宋体;">或者小于</span><span lang="EN-US">0</span><span style="FONT-FAMILY: 宋体;">的点,称为溢出,溢出点的处理通常是截断,即大于</span><span lang="EN-US">255</span><span style="FONT-FAMILY: 宋体;">时,令其等于</span><span lang="EN-US">255</span><span style="FONT-FAMILY: 宋体;">;小于</span><span lang="EN-US">0</span><span style="FONT-FAMILY: 宋体;">时,取其绝对值。</span></p><p style="LINE-HEIGHT: 18pt;"><span style="FONT-FAMILY: 宋体;">这段程序和前几章介绍的代码许多地方是很相似的,所以注释简单一些。程序中并没有用到那种分解成两个一维模板的快速算法,你如果有兴趣,可以自己编着试试。</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">BOOL TemplateOperation(HWND hWnd, int TemplateType)</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">{</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>DWORD OffBits,BufSize;</p><p style="LINE-HEIGHT: 18pt;">LPBITMAPINFOHEADER lpImgData;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>LPSTR lpPtr;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>HLOCAL hTempImgData;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>LPBITMAPINFOHEADER lpTempImgData;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>LPSTR lpTempPtr;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>HDC hDc;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>HFILE hf;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>LONG x,y;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>float coef; //<span style="FONT-FAMILY: 宋体;">模板前面所乘的系数</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>int CoefArray; //<span style="FONT-FAMILY: 宋体;">模板数组</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>float TempNum;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>char filename;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>switch(TemplateType){ //<span style="FONT-FAMILY: 宋体;">判断模板类型</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>case TEMPLATE_SMOOTH_BOX: //Box<span style="FONT-FAMILY: 宋体;">平滑模板</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>coef=(float)(1.0/9.0);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>memcpy(CoefArray,Template_Smooth_Box,9*sizeof(int));</p><p style="LINE-HEIGHT: 18pt;"><span> </span>strcpy(filename,"c:\\smbox.bmp"); </p><p style="LINE-HEIGHT: 18pt;"><span> </span>break;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>case TEMPLATE_SMOOTH_GAUSS: //<span style="FONT-FAMILY: 宋体;">高斯平滑模板</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>coef=(float)(1.0/16.0);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>memcpy(CoefArray,Template_Smooth_Gauss,9*sizeof(int));</p><p style="LINE-HEIGHT: 18pt;"><span> </span>strcpy(filename,"c:\\smgauss.bmp");</p><p style="LINE-HEIGHT: 18pt;"><span> </span>break;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>case TEMPLATE_SHARPEN_LAPLACIAN: //<span style="FONT-FAMILY: 宋体;">拉普拉斯锐化模板</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>coef=(float)1.0;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>memcpy(CoefArray,Template_Sharpen_Laplacian,9*sizeof(int));</p><p style="LINE-HEIGHT: 18pt;"><span> </span>strcpy(filename,"c:\\shlaplac.bmp");</p><p style="LINE-HEIGHT: 18pt;"><span> </span>break;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>}</p><p style="LINE-HEIGHT: 18pt;"><span> </span>OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>BufSize=OffBits+bi.biHeight*LineBytes;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL)</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">{</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span> MessageBox(hWnd,"Error alloc memory!","Error Message",MB_OK|</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">MB_ICONEXCLAMATION);</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">return FALSE;</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">}</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span> lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData); </p><p style="LINE-HEIGHT: 18pt;"><span> </span>lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>lpPtr=(char *)lpImgData;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>lpTempPtr=(char *)lpTempImgData;</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">//</span><span style="FONT-FAMILY: 宋体;">先将原图直接拷贝过来,其实主要是拷贝周围一圈的象素</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>memcpy(lpTempPtr,lpPtr,BufSize); </p><p style="LINE-HEIGHT: 18pt;"><span> </span>for(y=1;y<bi.biHeight-1;y++) //<b><span style="FONT-FAMILY: 黑体;">注意<span lang="EN-US">y的范围是从1到bi.biHeight-2</span></span></b></p><p style="LINE-HEIGHT: 18pt;"><span> </span>for(x=1;x<bi.biWidth-1;x++){ //<b><span style="FONT-FAMILY: 黑体;">注意<span lang="EN-US">x的范围是从1到bi.biWidth-2</span></span></b></p><p style="LINE-HEIGHT: 18pt;"><span> </span>lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes)+x;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>lpTempPtr=(char*)lpTempImgData+</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">(BufSize-LineBytes-y*LineBytes)+x;</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">TempNum=(float)((unsigned char)*(lpPtr+LineBytes-1))*</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">CoefArray;</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>TempNum+=(float)((unsigned char)*(lpPtr+LineBytes))*</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">CoefArray;</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>TempNum+=(float)((unsigned char)*(lpPtr+LineBytes+1))*</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">CoefArray;</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>TempNum+=(float)((unsigned char)*(lpPtr-1))*CoefArray;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>TempNum+=(float)((unsigned char)*lpPtr)*CoefArray;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>TempNum+=(float)((unsigned char)*(lpPtr+1))*CoefArray;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>TempNum+=(float)((unsigned char)*(lpPtr-LineBytes-1))*</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">CoefArray;</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>TempNum+=(float)((unsigned char)*(lpPtr-LineBytes))*</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">CoefArray;</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>TempNum+=(float)((unsigned char)*(lpPtr-LineBytes+1))*</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">CoefArray;</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>//<span style="FONT-FAMILY: 宋体;">最后乘以系数</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">TempNum*=coef;</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>//<b><span style="FONT-FAMILY: 黑体;">注意对溢出点的处理</span></b></p><p style="LINE-HEIGHT: 18pt;"><span> </span>if(TempNum>255.0) *lpTempPtr=(BYTE)255;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>else if(TempNum<0.0) </p><p style="LINE-HEIGHT: 18pt;"><span> </span>*lpTempPtr=(unsigned char)fabs(TempNum);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>else *lpTempPtr=(BYTE)TempNum;</p><p style="LINE-HEIGHT: 18pt;"><span> </span>}</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">hDc=GetDC(hWnd);</span></p><p style="LINE-HEIGHT: 18pt;"><span> </span> if(hBitmap!=NULL)</p><p style="LINE-HEIGHT: 18pt;"><span> </span> DeleteObject(hBitmap);</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData,</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">(LONG)CBM_INIT,</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">(LPSTR)lpTempImgData+</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">sizeof(BITMAPINFOHEADER)+</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">NumColors*sizeof(RGBQUAD),</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">(LPBITMAPINFO)lpTempImgData,</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">DIB_RGB_COLORS);</span></p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">hf=_lcreat(filename,0); </span></p><p style="LINE-HEIGHT: 18pt;"><span> </span>_lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER)); </p><p style="LINE-HEIGHT: 18pt;"><span> </span>_lwrite(hf,(LPSTR)lpTempImgData,BufSize);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>_lclose(hf);</p><p style="LINE-HEIGHT: 18pt;"><span> </span> ReleaseDC(hWnd,hDc);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>LocalUnlock(hTempImgData);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>LocalFree(hTempImgData);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>GlobalUnlock(hImgData);</p><p style="LINE-HEIGHT: 18pt;"><span> </span>return TRUE;</p><p style="LINE-HEIGHT: 18pt;"><span lang="EN-US">}</span><span lang="EN-US" style="FONT-SIZE: 9pt;"></span></p></div><div style="DISPLAY: block; FONT-SIZE: 10px; FONT-FAMILY: Verdana, Geneva, Arial;">The University of Southern California does not screen or control the content on this website and thus does not guarantee the accuracy, integrity, or quality of such content. All content on this website is provided by and is the sole responsibility of the person from which such content originated, and such content does not necessarily reflect the opinions of the University administration or the Board of Trustees </div> 顶
页:
[1]