📄 chap04.htm
字号:
lang=EN-US>(b+w)/2</span><span style='font-family:宋体;"Times New Roman";"Times New Roman"'>,对应</span><span
lang=EN-US>256</span><span style='font-family:宋体;
"Times New Roman"'>级灰度,</span><span lang=EN-US>b=0,w=255,t=127.5</span><span
style='font-family:宋体;"Times New Roman"'>。设原图中象素的灰度为</span><span lang=EN-US>g</span><span
style='font-family:宋体;"Times New Roman"'>,误差值为</span><span lang=EN-US>e</span><span style='font-family:
宋体;"Times New Roman"'>,则新图中对应象素的值用如下的方法得到:</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>if g > t then</span></p>
<p style='line-height:18.0pt'><span
style='font-family:宋体;"Times New Roman"'>打白点</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>e=g-w</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>else </span></p>
<p style='line-height:18.0pt'><span
style='font-family:宋体;"Times New Roman"'>打黑点</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>e=g-b</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>3/8 </span><span style='font-family:宋体;
"Times New Roman"'>×</span><span lang=EN-US> e </span><span
style='font-family:宋体;"Times New Roman"'>加到右边的象素</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>3/8 </span><span style='font-family:宋体;
"Times New Roman"'>×</span><span lang=EN-US> e </span><span
style='font-family:宋体;"Times New Roman"'>加到下边的象素</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>1/4 </span><span style='font-family:宋体;
"Times New Roman"'>×</span><span lang=EN-US> e </span><span
style='font-family:宋体;"Times New Roman"'>加到右下方的象素</span></p>
<p style='line-height:18.0pt'><span
style='font-family:宋体;"Times New Roman"'>算法的意思很明白:以</span><span lang=EN-US>256</span><span
style='font-family:宋体;"Times New Roman"'>级灰度为例,假设一个点的灰度为</span><span lang=EN-US>130</span><span
style='font-family:宋体;"Times New Roman"'>,在灰度图中应该是一个灰点。由于一般图象中灰度是连续变化的,相邻象素的灰度值很可能与本象素非常接近,所以该点及周围应该是一片灰色区域。在新图中,</span><span
lang=EN-US>130</span><span style='font-family:宋体;
"Times New Roman"'>大于</span><span lang=EN-US>128</span><span
style='font-family:宋体;"Times New Roman"'>,所以打了白点,但</span><span lang=EN-US>130</span><span
style='font-family:宋体;"Times New Roman"'>离真正的白点</span><span lang=EN-US>255</span><span
style='font-family:宋体;"Times New Roman"'>还差的比较远,误差</span><span lang=EN-US>e=130-255=-125</span><span
style='font-family:宋体;"Times New Roman"'>比较大。,将</span><span lang=EN-US>3/8</span><span
style='font-family:宋体;"Times New Roman"'>×</span><span lang=EN-US>(-125)</span><span
style='font-family:宋体;"Times New Roman"'>加到相邻象素后,使得相邻象素的值接近</span><span lang=EN-US>0</span><span
style='font-family:宋体;"Times New Roman"'>而打黑点。下一次,</span><span lang=EN-US>e</span><span
style='font-family:宋体;"Times New Roman"'>又变成正的,使得相邻象素的相邻象素打白点,这样一白一黑一白,表现出来刚好就是灰色。如果不传递误差,就是一片白色了。再举个例子,如果一个点的灰度为</span><span
lang=EN-US>250</span><span style='font-family:宋体;
"Times New Roman"'>,在灰度图中应该是一个白点,该点及周围应该是一片白色区域。在新图中,虽然</span><span
lang=EN-US>e=-5</span><span style='font-family:宋体;
"Times New Roman"'>也是负的,但其值很小,对相邻象素的影响不大,所以还是能够打出一片白色区域来。这样就验证了算法的正确性。其它的情况你可以自己推敲。图</span><span
lang=EN-US>4.7</span><span style='font-family:宋体;
"Times New Roman"'>是利用</span><span lang=EN-US>Floyd-Steinberg</span><span
style='font-family:宋体;"Times New Roman"'>算法抖动生成的图。</span></p>
<p class=a style='line-height:18.0pt'><span lang=EN-US> <img width=409 height=259
src="chap04.files/image014.gif" v:shapes="_x0000_i1035"> </span></p>
<p align=center style='text-align:center;line-height:18.0pt'><b><span
style='font-family:宋体;"Times New Roman"'>图</span>4.7 </b><b><span
style='font-family:宋体;"Times New Roman"'>利用</span><span lang=EN-US>Floyd-Steinberg</span></b><b><span
style='font-family:宋体;"Times New Roman"'>算法抖动生成的图</span><span lang=EN-US></span></b></p>
<p style='line-height:18.0pt'><span
style='font-family:宋体;"Times New Roman"'>下面我们给出</span><span lang=EN-US>Floyd-Steinberg</span><span
style='font-family:宋体;"Times New Roman"'>算法的源代码。有一点要说明,我们原来介绍的程序都是先开一个</span><span lang=EN-US>char</span><span
style='font-family:宋体;"Times New Roman"'>类型的缓冲区,用来存储新图数据,但在这个算法中,因为</span><span lang=EN-US>e</span><span
style='font-family:宋体;"Times New Roman"'>有可能是负数,为了防止得到的值超出</span><span lang=EN-US>char</span><span
style='font-family:宋体;"Times New Roman"'>能表示的范围,我们使用了一个</span><span lang=EN-US>int</span><span
style='font-family:宋体;"Times New Roman"'>类型的缓冲区存储新值。另外,当按从左到右,从上到下的顺序处理象素时,处理过的象素以后不会再用到了,所以用这个</span><span
lang=EN-US>int</span><span style='font-family:宋体;
"Times New Roman"'>类型的缓冲区存储新值是可行的。全部象素处理完后,再将这些值拷贝到</span><span
lang=EN-US>char</span><span style='font-family:宋体;
"Times New Roman"'>类型的缓冲区去。</span></p>
<p style='line-height:18.0pt'><span lang=EN-US>BOOL Steinberg(HWND hWnd)</span></p>
<p style='line-height:18.0pt'><span lang=EN-US>{</span></p>
<p style='line-height:18.0pt'>DWORD
OffBits,BufSize,IntBufSize;</p>
<p style='line-height:18.0pt'>LPBITMAPINFOHEADER lpImgData;</p>
<p style='line-height:18.0pt'>HLOCAL
hTempImgData;</p>
<p style='line-height:18.0pt'>LPBITMAPINFOHEADER lpTempImgData;</p>
<p style='line-height:18.0pt'>LPSTR
lpPtr;</p>
<p style='line-height:18.0pt'>LPSTR
lpTempPtr;</p>
<p style='line-height:18.0pt'>HDC
hDc;</p>
<p style='line-height:18.0pt'>HFILE
hf;</p>
<p style='line-height:18.0pt'>LONG
x,y;</p>
<p style='line-height:18.0pt'>unsigned char
num;</p>
<p style='line-height:18.0pt'>float
e,f;</p>
<p style='line-height:18.0pt'>HLOCAL
hIntBuf;</p>
<p style='line-height:18.0pt'>int
*lpIntBuf,*lpIntPtr;</p>
<p style='line-height:18.0pt'>int
tempnum;</p>
<p style='line-height:18.0pt'><span
lang=EN-US>//OffBits</span><span style='font-family:宋体;"Times New Roman";"Times New Roman"'>为</span><span
lang=EN-US>BITMAPINFOHEADER</span><span style='font-family:宋体;"Times New Roman";"Times New Roman"'>结构长度加调色板的大小</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>BufSize=OffBits+bi.biHeight*LineBytes;//</span><span
style='font-family:宋体;"Times New Roman"'>要开的缓冲区的大小</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL)</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>{</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>MessageBox(hWnd,"Error alloc memory!","Error Message",MB_OK|</span></p>
<p style='line-height:
18.0pt'><span lang=EN-US>MB_ICONEXCLAMATION);</span></p>
<p style='line-height:
18.0pt'><span lang=EN-US>return FALSE;</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>}</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>IntBufSize=(DWORD)bi.biHeight*LineBytes*sizeof(int); if((hIntBuf=LocalAlloc(LHND,IntBufSize))==NULL)
//int </span><span style='font-family:宋体;
"Times New Roman"'>类型的缓冲区</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>{</span></p>
<p style='line-height:
18.0pt'><span lang=EN-US>MessageBox(hWnd,"Error alloc memory!","Error
Message",MB_OK|</span></p>
<p style='line-height:
18.0pt'><span lang=EN-US>MB_ICONEXCLAMATION);</span></p>
<p style='line-height:
18.0pt'><span lang=EN-US>LocalFree(hTempImgData);</span></p>
<p style='line-height:
18.0pt'><span lang=EN-US>return FALSE;</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>}</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>lpIntBuf=(int *)LocalLock(hIntBuf);</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>//</span><span style='font-family:宋体;
"Times New Roman"'>拷贝头信息</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>memcpy(lpTempImgData,lpImgData,OffBits);</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>//</span><span style='font-family:宋体;
"Times New Roman"'>将图象数据拷贝到</span><span lang=EN-US>int</span><span
style='font-family:宋体;"Times New Roman"'>类型的缓冲区中</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>for(y=0;y<bi.biHeight;y++){</span></p>
<p style='line-height:
18.0pt'><span lang=EN-US>lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes);</span></p>
<p style='line-height:
18.0pt'><span lang=EN-US>lpIntPtr=(int *)lpIntBuf+(bi.biHeight-1-y)*LineBytes;</span></p>
<p style='line-height:
18.0pt'><span lang=EN-US>for(x=0;x<bi.biWidth;x++)</span></p>
<p style='line-height:18.0pt'><span>
</span>*(lpIntPtr++)=(unsigned char)*(lpPtr++);</p>
<p style='line-height:18.0pt'><span
lang=EN-US>}</span></p>
<p style='line-height:18.0pt'><span
lang=EN-US>for(y=0;y<bi.biHeight;y++){</span></p>
<p style='line-height:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -