⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 第4章 图象的半影调和抖动技术.htm

📁 介绍了图像的半影调和抖动技术的原理和数学基础.
💻 HTM
📖 第 1 页 / 共 5 页
字号:
</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>for(y=0;y&lt;bi.biHeight;y++){</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
</SPAN>//lpPtr<SPAN style="FONT-FAMILY: 宋体">为指向原图位图数据的指针</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
</SPAN>lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes);</P>
<P style="LINE-HEIGHT: 18pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
</SPAN>//lpTempPtr<SPAN style="FONT-FAMILY: 宋体">为指向新图位图数据的指针</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
</SPAN>lpTempPtr=(char *)lpTempImgData+(BufSize-LineBytes-y*LineBytes);</P>
<P style="LINE-HEIGHT: 18pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
</SPAN>for(x=0;x&lt;bi.biWidth;x++){</P>
<P 
style="LINE-HEIGHT: 18pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
</SPAN>num=(unsigned char)*lpPtr++;</P>
<P 
style="LINE-HEIGHT: 18pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
</SPAN>if ( (num&gt;&gt;2) &gt; BayerPattern[y&amp;7][x&amp;7]) //<SPAN 
style="FONT-FAMILY: 宋体">右移两位后做比较</SPAN></P>
<P 
style="LINE-HEIGHT: 18pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
</SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *(lpTempPtr++)=(unsigned char)255; 
//<SPAN style="FONT-FAMILY: 宋体">打白点</SPAN></P>
<P 
style="LINE-HEIGHT: 18pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
</SPAN>else *(lpTempPtr++)=(unsigned char)0; //<SPAN 
style="FONT-FAMILY: 宋体">打黑点</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}</P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>}</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>if(hBitmap!=NULL)</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN>&nbsp;&nbsp;&nbsp; 
</SPAN>DeleteObject(hBitmap);</P>
<P style="LINE-HEIGHT: 18pt">hDc=GetDC(hWnd);&nbsp;&nbsp;&nbsp; </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>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("c:\\limbm3.bmp",0);</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN 
lang=EN-US>_lwrite(hf,(LPSTR)&amp;bf,sizeof(BITMAPFILEHEADER)); </SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN 
lang=EN-US>_lwrite(hf,(LPSTR)lpTempImgData,BufSize);</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>_lclose(hf);</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>ReleaseDC(hWnd,hDc);</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN 
lang=EN-US>LocalUnlock(hTempImgData);</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN 
lang=EN-US>LocalFree(hTempImgData);</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>GlobalUnlock(hImgData);</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>return TRUE;</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>}</SPAN><SPAN lang=EN-US 
style="FONT-SIZE: 9pt"></SPAN></P>
<H2><SPAN lang=EN-US>4.2</SPAN> <SPAN lang=EN-US></SPAN><A 
name=_Toc486331879></A><A name=_Toc486332879></A><A name=_Toc486338988></A><A 
name=_Toc454810853></A><A 
name=_Toc454856627><SPAN><SPAN>抖动法</SPAN></SPAN></A></H2>
<P style="LINE-HEIGHT: 18pt"><SPAN 
style="FONT-FAMILY: 宋体">让我们考虑更坏的情况:即使使用了图案化技术,仍然得不到要求的灰度级别。举例说明:假设有一幅</SPAN><SPAN 
lang=EN-US>600</SPAN><SPAN style="FONT-FAMILY: 宋体">×</SPAN><SPAN 
lang=EN-US>450</SPAN><SPAN style="FONT-FAMILY: 宋体">×</SPAN><SPAN 
lang=EN-US>8bit</SPAN><SPAN style="FONT-FAMILY: 宋体">的灰度图,当用分辨率为</SPAN><SPAN 
lang=EN-US>300dpi</SPAN><SPAN style="FONT-FAMILY: 宋体">×</SPAN><SPAN 
lang=EN-US>300dpi</SPAN><SPAN style="FONT-FAMILY: 宋体">的激光打印机将其打印到</SPAN><SPAN 
lang=EN-US>8</SPAN><SPAN style="FONT-FAMILY: 宋体">×</SPAN><SPAN 
lang=EN-US>6</SPAN><SPAN style="FONT-FAMILY: 宋体">英寸的纸上时,每个象素可以用</SPAN><SPAN 
lang=EN-US>(2400/600)</SPAN><SPAN style="FONT-FAMILY: 宋体">×</SPAN><SPAN 
lang=EN-US>(1800/450)=4</SPAN><SPAN style="FONT-FAMILY: 宋体">×</SPAN><SPAN 
lang=EN-US>4</SPAN><SPAN style="FONT-FAMILY: 宋体">个点大小的图案来表示,最多能表示</SPAN><SPAN 
lang=EN-US>17</SPAN><SPAN style="FONT-FAMILY: 宋体">级灰度,无法满足</SPAN><SPAN 
lang=EN-US>256</SPAN><SPAN style="FONT-FAMILY: 宋体">级灰度的要求。可有两种解决方案:</SPAN><SPAN 
lang=EN-US>(1)</SPAN><SPAN style="FONT-FAMILY: 宋体">减小图象尺寸,由</SPAN><SPAN 
lang=EN-US>600</SPAN><SPAN style="FONT-FAMILY: 宋体">×</SPAN><SPAN 
lang=EN-US>450</SPAN><SPAN style="FONT-FAMILY: 宋体">变为</SPAN><SPAN 
lang=EN-US>150</SPAN><SPAN style="FONT-FAMILY: 宋体">×</SPAN><SPAN 
lang=EN-US>113</SPAN><SPAN style="FONT-FAMILY: 宋体">;</SPAN><SPAN 
lang=EN-US>(2)</SPAN><SPAN style="FONT-FAMILY: 宋体">降低图象灰度级,由</SPAN><SPAN 
lang=EN-US>256</SPAN><SPAN style="FONT-FAMILY: 宋体">级变成</SPAN><SPAN 
lang=EN-US>16</SPAN><SPAN 
style="FONT-FAMILY: 宋体">级。这两种方案都不理想。这时,我们就可以采用“抖动法”</SPAN><SPAN 
lang=EN-US>(dithering)</SPAN><SPAN 
style="FONT-FAMILY: 宋体">的技术来解决这个问题。其实刚才给出的算法就是一种抖动算法,称为规则抖动</SPAN><SPAN 
lang=EN-US>(regular dithering)</SPAN><SPAN 
style="FONT-FAMILY: 宋体">。规则抖动的优点是算法简单;缺点是图案化有时很明显,这是因为取模运算虽然引入了随机成分,但还是有规律的。另外,点之间进行比较时,只要比标准图案上点的值大就打白点,这种做法并不理想,因为,如果当标准图案点的灰度值本身就很小,而图象中点的灰度只比它大一点儿时,图象中的点更接近黑色,而不是白色。一种更好的方法是将这个误差传播到邻近的象素。</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN style="FONT-FAMILY: 宋体">下面介绍的</SPAN><SPAN 
lang=EN-US>Floyd-Steinberg</SPAN><SPAN 
style="FONT-FAMILY: 宋体">算法就采用了这种方案。</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN 
style="FONT-FAMILY: 宋体">假设灰度级别的范围从</SPAN><SPAN lang=EN-US>b(black)</SPAN><SPAN 
style="FONT-FAMILY: 宋体">到</SPAN><SPAN lang=EN-US>w(white)</SPAN><SPAN 
style="FONT-FAMILY: 宋体">,中间值</SPAN><SPAN lang=EN-US>t</SPAN><SPAN 
style="FONT-FAMILY: 宋体">为</SPAN><SPAN lang=EN-US>(b+w)/2</SPAN><SPAN 
style="FONT-FAMILY: 宋体">,对应</SPAN><SPAN lang=EN-US>256</SPAN><SPAN 
style="FONT-FAMILY: 宋体">级灰度,</SPAN><SPAN 
lang=EN-US>b=0,w=255,t=127.5</SPAN><SPAN 
style="FONT-FAMILY: 宋体">。设原图中象素的灰度为</SPAN><SPAN lang=EN-US>g</SPAN><SPAN 
style="FONT-FAMILY: 宋体">,误差值为</SPAN><SPAN lang=EN-US>e</SPAN><SPAN 
style="FONT-FAMILY: 宋体">,则新图中对应象素的值用如下的方法得到:</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>if g &gt; t then</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN style="FONT-FAMILY: 宋体">打白点</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>e=g-w</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>else </SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN style="FONT-FAMILY: 宋体">打黑点</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>e=g-b</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>3/8 </SPAN><SPAN 
style="FONT-FAMILY: 宋体">×</SPAN><SPAN lang=EN-US> e </SPAN><SPAN 
style="FONT-FAMILY: 宋体">加到右边的象素</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>3/8 </SPAN><SPAN 
style="FONT-FAMILY: 宋体">×</SPAN><SPAN lang=EN-US> e </SPAN><SPAN 
style="FONT-FAMILY: 宋体">加到下边的象素</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>1/4 </SPAN><SPAN 
style="FONT-FAMILY: 宋体">×</SPAN><SPAN lang=EN-US> e </SPAN><SPAN 
style="FONT-FAMILY: 宋体">加到右下方的象素</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN 
style="FONT-FAMILY: 宋体">算法的意思很明白:以</SPAN><SPAN lang=EN-US>256</SPAN><SPAN 
style="FONT-FAMILY: 宋体">级灰度为例,假设一个点的灰度为</SPAN><SPAN lang=EN-US>130</SPAN><SPAN 
style="FONT-FAMILY: 宋体">,在灰度图中应该是一个灰点。由于一般图象中灰度是连续变化的,相邻象素的灰度值很可能与本象素非常接近,所以该点及周围应该是一片灰色区域。在新图中,</SPAN><SPAN 
lang=EN-US>130</SPAN><SPAN style="FONT-FAMILY: 宋体">大于</SPAN><SPAN 
lang=EN-US>128</SPAN><SPAN style="FONT-FAMILY: 宋体">,所以打了白点,但</SPAN><SPAN 
lang=EN-US>130</SPAN><SPAN style="FONT-FAMILY: 宋体">离真正的白点</SPAN><SPAN 
lang=EN-US>255</SPAN><SPAN style="FONT-FAMILY: 宋体">还差的比较远,误差</SPAN><SPAN 
lang=EN-US>e=130-255=-125</SPAN><SPAN style="FONT-FAMILY: 宋体">比较大。,将</SPAN><SPAN 
lang=EN-US>3/8</SPAN><SPAN style="FONT-FAMILY: 宋体">×</SPAN><SPAN 
lang=EN-US>(-125)</SPAN><SPAN 
style="FONT-FAMILY: 宋体">加到相邻象素后,使得相邻象素的值接近</SPAN><SPAN lang=EN-US>0</SPAN><SPAN 
style="FONT-FAMILY: 宋体">而打黑点。下一次,</SPAN><SPAN lang=EN-US>e</SPAN><SPAN 
style="FONT-FAMILY: 宋体">又变成正的,使得相邻象素的相邻象素打白点,这样一白一黑一白,表现出来刚好就是灰色。如果不传递误差,就是一片白色了。再举个例子,如果一个点的灰度为</SPAN><SPAN 
lang=EN-US>250</SPAN><SPAN 
style="FONT-FAMILY: 宋体">,在灰度图中应该是一个白点,该点及周围应该是一片白色区域。在新图中,虽然</SPAN><SPAN 
lang=EN-US>e=-5</SPAN><SPAN 
style="FONT-FAMILY: 宋体">也是负的,但其值很小,对相邻象素的影响不大,所以还是能够打出一片白色区域来。这样就验证了算法的正确性。其它的情况你可以自己推敲。图</SPAN><SPAN 
lang=EN-US>4.7</SPAN><SPAN style="FONT-FAMILY: 宋体">是利用</SPAN><SPAN 
lang=EN-US>Floyd-Steinberg</SPAN><SPAN 
style="FONT-FAMILY: 宋体">算法抖动生成的图。</SPAN></P>
<P class=a style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US><IMG height=259 
src="第4章 图象的半影调和抖动技术.files/image014.gif" width=409 v:shapes="_x0000_i1035"> 
</SPAN></P>
<P style="LINE-HEIGHT: 18pt; TEXT-ALIGN: center" align=center><B><SPAN 
style="FONT-FAMILY: 宋体">图</SPAN>4.7&nbsp;&nbsp;&nbsp;&nbsp; </B><B><SPAN 
style="FONT-FAMILY: 宋体">利用</SPAN><SPAN 
lang=EN-US>Floyd-Steinberg</SPAN></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>Floyd-Steinberg</SPAN><SPAN 
style="FONT-FAMILY: 宋体">算法的源代码。有一点要说明,我们原来介绍的程序都是先开一个</SPAN><SPAN 
lang=EN-US>char</SPAN><SPAN 
style="FONT-FAMILY: 宋体">类型的缓冲区,用来存储新图数据,但在这个算法中,因为</SPAN><SPAN 
lang=EN-US>e</SPAN><SPAN style="FONT-FAMILY: 宋体">有可能是负数,为了防止得到的值超出</SPAN><SPAN 
lang=EN-US>char</SPAN><SPAN style="FONT-FAMILY: 宋体">能表示的范围,我们使用了一个</SPAN><SPAN 
lang=EN-US>int</SPAN><SPAN 
style="FONT-FAMILY: 宋体">类型的缓冲区存储新值。另外,当按从左到右,从上到下的顺序处理象素时,处理过的象素以后不会再用到了,所以用这个</SPAN><SPAN 
lang=EN-US>int</SPAN><SPAN 
style="FONT-FAMILY: 宋体">类型的缓冲区存储新值是可行的。全部象素处理完后,再将这些值拷贝到</SPAN><SPAN 
lang=EN-US>char</SPAN><SPAN style="FONT-FAMILY: 宋体">类型的缓冲区去。</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>BOOL Steinberg(HWND 
hWnd)</SPAN></P>
<P style="LINE-HEIGHT: 18pt"><SPAN lang=EN-US>{</SPAN></P>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -