请问怎样将一彩色图片,转换为一只用黑白表的图片,要求图像转换后尽量逼真。(300分)

  • 主题发起人 主题发起人 CashChin
  • 开始时间 开始时间
C

CashChin

Unregistered / Unconfirmed
GUEST, unregistred user!
请问怎样将一彩色图片,转换为一只用黑白表的图片,要求图像转换后尽量逼真。
请各位大虾指教。
 
讨论好多阿。
你看这个行不行。
http://www.delphibbs.com/delphibbs/dispq.asp?lid=790267
 
>>尽量逼真!
看来一般的阀值法肯定是不行的了,至于灰度图,原理还是很简单的
即每个象素点重新赋值0.3*r+0.59*b+0.11*b
 
黑白两色并且尽量逼真的话就要用抖动或者误差遗传算法,误差遗传效果最好,
这里给出一个高速的误差遗传算法。
var
p :PByteArray;
x,y,p3 :Integer;
Bmp :TBitmap;
L : integer;
begin
Bmp :=TBitmap.Create;
Bmp.Assign(Image1.Picture.Bitmap);
bmp.pixelformat:=pf24bit;
for y:=0 to Bmp.Height-1 do
begin
p:=Bmp.scanline[y];
L := 0;
for x:=0 to Bmp.Width-1 do
begin
inc(L, (p^[2]*2 + p^[1] * 5 + p^[0]) shr 3);
if L > 128 then
begin
p^[0]:= 255;
dec(L,255);
end
else
p^[0]:=0;
p^[1]:=p^[0];
p^[2]:=p^[1];
inc(integer(p),3);
end;
end;
Image1.Picture.Bitmap.Assign(Bmp);
Bmp.Free;
end;
 
function GrayColor(ACanvas: TCanvas; clr: TColor; Value: integer): TColor;
var
r, g, b, avg: integer;

begin
if Value > 100 then Value := 100;
clr := ColorToRGB(clr);
r := Clr and $000000FF;
g := (Clr and $0000FF00) shr 8;
b := (Clr and $00FF0000) shr 16;

Avg := (r + g + b) div 3;
Avg := Avg + Value;

if Avg > 240 then Avg := 240;

Result := Windows.GetNearestColor(ACanvas.Handle, RGB(Avg, avg, avg));
end;

procedure GrayBitmap(ABitmap: TBitmap; Value: integer);
var
x, y: integer;
LastColor1, LastColor2, Color: TColor;
begin
LastColor1 := 0;
LastColor2 := 0;

for y := 0 to ABitmap.Height do
for x := 0 to ABitmap.Width do
begin
Color := ABitmap.Canvas.Pixels[x, y];
if Color = LastColor1 then
ABitmap.Canvas.Pixels[x, y] := LastColor2
else
begin
LastColor2 := GrayColor(ABitmap.Canvas, Color, Value);
ABitmap.Canvas.Pixels[x, y] := LastColor2;
LastColor1 := Color;
end;
end;
end;
 
你们能否对此详细一点,一定给分
 
[关于规则抖动技术]
  在规则抖动技术中,每一个平面都被分割成单元,每一单元有不同的点模式,然后在纸上平铺这些单元产生图象。一个单元中的像素数(点)决定了单色打印机所能再现的灰度级数。例如,在一个4*4的黑白单元中,我们希望用灰度值64来打印(黑=255;白=0。)我们将用一个阈“筛”来确定哪一个像素要打印,阈“筛”与在织物上印图案所用的丝绸筛很像。它在某些位置允许打印,在某些位置禁止打印。阈“筛”的每一个单元位置都有一个值,其最大允许值为255。为了确定一个具体像素位置是否要打印,我们把要打印的灰度值(在这个例子中灰度值为64)与阈“筛”相应单元位置的值进行比较:如果一个阈“筛”位置的这个值大于或等于要打印的灰度值,相应的单元位置就不打印;如果这个值小于要打印的灰度值,相应的单元位置就要打印。在彩色打印机中,规则抖动过程被分别应用于每一个颜色平面,一个单元中的像素数决定了能够打印的深浅颜色数量。一种颜色的点模式单元中的点越多,这种颜色的深浅层次就越多。
[误差扩散技术]
  规则抖动容易产生有结构的单元模式,人眼能够辨识出来,这就是为什么大多数彩色喷墨打印机制造厂商使用图象扩散筛方法的原因。为了解决这个问题,Lexmark采用图象扩散技术生成更真实的图像。图象扩散技术用于查对每一个点的灰度,就好像它能够用不同灰度打印一样,——当然,实际上这是不可能的,我们实际只能够打印黑色(255)或白色(0)。借助图像误差扩散技术,我们能够确定特定像素位置的实际打印效果。
在上面的黑白单元例子中,要打印的灰度为64。如果在特定像素位置上不打印点,则实际灰度值就是0,或白色,尽管我们希望得到64的灰度值。因此在这个位置上的误差就是64-0,或64。如果有一个点打印在这里,则实际灰度为255,或黑色,虽然我们希望这个位置的灰度为64。在这个位置上的误差因此是64-255,或-199。然后我们把这个计算出来的误差“扩散”到邻近像素(这个过程在驱动器屏幕上称作“Air Brush”过程)。如果误差是负的(即打印了黑点),就减少邻近像素打印黑点的几率;如果误差是正的(即没有打印点),就提高邻近像素打印黑点的几率。因此图象扩散也称作邻近过程。
[灰阶转换算法]请参考:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1268950

[我前面的代码使用说明:]
1。在 Form 上放一个 TImage 控件,里面装一幅真彩色图
2。再放一个按钮,双击,把我上面那段代码黏贴进去。
3。F9运行。

[yanlei的代码有几个问题:]
1)只完成了灰度转化,没有完成黑白二值话,更没有抖动或者误差传递。
且灰度转化算法也是不对的, R、G、B三者的对亮度贡献系数是不同的,
请参阅这方面的文献先。
2)是用 pixels 做的,我们都知道 pixels 的速度慢。scanline比它快无数倍。

 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
1K
DelphiTeacher的专栏
D
I
回复
0
查看
634
import
I
后退
顶部