Delphi的图形处理

合集下载

Delphi中改变图片(bitmap)的亮度、对比度、饱和度

Delphi中改变图片(bitmap)的亮度、对比度、饱和度

Delphi中改变图⽚(bitmap)的亮度、对⽐度、饱和度最近在做视频处理相关的⼯作,遇到⼀些图⽚处理的问题,从别处找到解决的代码。

其中对⽐度调节的代码处理结果看起来不太舒服,暂时没时间仔细研究,先放在这⾥。

// 改亮度function ChangeBrightness(bmp: TBitmap; s: Integer): Boolean;varp: PByteArray;x, y: Integer;begintry//24位真彩⾊Bmp.PixelFormat := pf24Bit;bmp.Canvas.Lock;for y := 0 to Bmp.Height - 1 dobeginp := Bmp.scanline[y];for x := 0 to Bmp.Width - 1 dobegin//每个象素点的R、G、B分量进⾏调节beginif s > 0 thenbeginp[x * 3] := Min(255, p[x * 3] + s); //不能越界,限制在0~255p[x * 3 + 1] := Min(255, p[x * 3 + 1] + s);p[x * 3 + 2] := Min(255, p[x * 3 + 2] + s);endelsebeginp[x * 3] := max(0, p[x * 3] + s); //不能越界,限制在-255~0p[x * 3 + 1] := max(0, p[x * 3 + 1] + s);p[x * 3 + 2] := max(0, p[x * 3 + 2] + s);end;end;end;end;bmp.Canvas.Unlock;Result := true;exceptResult := false;end;end;// 改对⽐度function ChangeContrast(bmp: TBitmap; s: Integer): Boolean;constCMid = 128;CMin = 10;CMax = 246;varp: PByteArray;x, y: Integer;begintry//24位真彩⾊Bmp.PixelFormat := pf24Bit;bmp.Canvas.Lock;for y := 0 to Bmp.Height - 1 dobeginp := Bmp.ScanLine[y];for x := 0 to Bmp.Width - 1 dobegin//确定阀值为128if (p[x*3] > CMid) and (p[x*3] <= CMax)and (p[x*3+1] > CMid) and (p[x*3+1] <= CMax)and (p[x*3+2] > CMid) and (p[x*3+2] <= CMax) thenbeginp[x*3] := Min(255, p[x*3] + s * p[x*3] div (p[x*3]+p[x*3+1]+p[x*3+2]));p[x*3+1]:= Min(255, p[x*3+1]+ s * p[x*3+1] div (p[x*3]+p[x*3+1]+p[x*3+2]));p[x*3+2]:= Min(255, p[x*3+2]+ s * p[x*3+2] div (p[x*3]+p[x*3+1]+p[x*3+2]));end;if (p[x*3] > CMin) and (p[x*3] <= CMid)and (p[x*3+1] > CMin) and (p[x*3+1] <= CMid)and (p[x*3+2] > CMin) and (p[x*3+2] <= CMid) thenbeginp[x*3] := Max(0, p[x*3] - s * p[x*3] div (p[x*3]+p[x*3+1]+p[x*3+2]));p[x*3+1]:= Max(0, p[x*3+1]- s * p[x*3+1] div (p[x*3]+p[x*3+1]+p[x*3+2])); p[x*3+2]:= Max(0, p[x*3+2]- s * p[x*3+2] div (p[x*3]+p[x*3+1]+p[x*3+2])); end;end;end;bmp.Canvas.Unlock;Result := true;exceptResult := false;end;end;// 改饱和度function ChangeSaturation(bmp: TBitmap; ValueChange: Integer): Boolean; constCMax = 255;varGrays: array[0..767] of Integer;Alpha: array[0..255] of Word;Gray, x, y: Integer;SrcRGB: PRGBTriple;i: Byte;beginValueChange := ValueChange + 255;for i := 0 to CMax dobeginAlpha[i] := (i * ValueChange) shr 8;end;x := 0;for i := 0 to CMax dobeginGray := i - Alpha[i];Grays[x] := Gray;Inc(x);Grays[x] := Gray;inc(x);Grays[x] := Gray;Inc(x);end;for y := 0 to bmp.Height - 1 dobeginSrcRGB := bmp.ScanLine[y];for x := 0 to bmp.Width - 1 dobeginGray := Grays[SrcRGB.rgbtRed + SrcRGB.rgbtBlue + SrcRGB.rgbtGreen]; if Gray + Alpha[SrcRGB.rgbtRed] > 0 thenSrcRGB.rgbtRed := Min(CMax, Gray + Alpha[SrcRGB.rgbtRed])elseSrcRGB.rgbtRed := 0;if Gray + Alpha[SrcRGB.rgbtGreen] > 0 thenSrcRGB.rgbtGreen := Min(CMax, Gray + Alpha[SrcRGB.rgbtGreen])elseSrcRGB.rgbtGreen := 0;if Gray + Alpha[SrcRGB.rgbtBlue] > 0 thenSrcRGB.rgbtBlue := Min(CMax, Gray + Alpha[SrcRGB.rgbtBlue])elseSrcRGB.rgbtBlue := 0;Inc(SrcRGB);end;end;end;。

Delphi图形图像处理

Delphi图形图像处理

见例子
画矩形
StretchDraw StretchDraw(Const Rect : TRcct : Graphic : TGraphic); 此方法在Rect参数指定的矩形内画一图像。图像 延伸改变大小以适应矩形。 Rectangle Rectangle(X1,y1,x2,y2 : Integer); Rectangle方法在画布上用当前画刷绘制矩形, (x1,y1)是矩形的左上角,(x2,y2)是矩形的右下 角。
三.图像对象概述 3.1. TGraphic对象

TGraphic对象是 TBitmap ,TIcon,Tmetafile对象的基类。 如果知道图像的具体类型( 如位图, 图标 元文件) , 则应将图像贮存在相应类型的 对象中( 如TBitmap,TIcon,Tmetafile), 否则应该使用可贮存任何图像类型的 TPicture对象。

把点连成线


Polygon Polygon(Points : array of TPrint); Polygon方法在画布上绘制一系列的点,各点依 次连成线,最后将首尾两点相接形成一个区域, 并用当前笔刷填充此区域。 Polyline Polyline(Ports : array of TPort); Polyline方法在画布上用当前画笔绘制一系列的 点,各点依次连成线。
Tbrush对象方法


(1)Assign:向另一个对象赋值 (2)Create:创建一个TBrush对象实例。 (3)Destroy:释放一个TBrush对象实例。 (4)OwnHandle:用来确保对更基本的Qbrush 类实例的权限。当需要接受QBrush handle使用 或销毁权限时需要用到这个过程。 (5)ReleaseHandle:用来把TBrush 从 QBrush handle中分离出来,当需要把TBrush handle 给一段程序或一个类时,用到这个函数。

Delphi基本图像处理方法.

Delphi基本图像处理方法.

本文实例汇总了Delphi基本图像处理方法。

分享给大家供大家参考。

具体分析如下: //浮雕 procedureEmboss(SrcBmp,DestBmp:TBitmap;AzimuthChange:integer;overload; var i, j, Gray, Azimuthvalue, R, G, B: integer; SrcRGB, SrcRGB1, SrcRGB2, DestRGB: pRGBTriple; begin for i := 0 to SrcBmp.Height - 1 do begin SrcRGB := SrcBmp.ScanLine[i]; DestRGB := DestBmp.ScanLine[i]; if (AzimuthChange >= -180 and (AzimuthChange < -135 then begin if i > 0 then SrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB; Inc(SrcRGB1; SrcRGB2 := SrcRGB; Inc(SrcRGB2; end else if (AzimuthChange >= -135 and (AzimuthChange < -90 then begin if i > 0 thenSrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB; SrcRGB2 := SrcRGB1; Inc(SrcRGB2; end else if (AzimuthChange >= -90 and (AzimuthChange < -45 then begin if i > 0 then SrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB; SrcRGB2 := SrcRGB1; end else if (AzimuthChange >= -45 and (AzimuthChange < 0 then begin SrcRGB1 := SrcRGB; if i > 0 then SrcRGB2 := SrcBmp.ScanLine[i-1] else SrcRGB2 := SrcRGB; end else if (AzimuthChange >= 0 and (AzimuthChange < 45 then begin SrcRGB2 := SrcRGB; if (i < SrcBmp.Height - 1 then SrcRGB1 := SrcBmp.ScanLine[i+1] else SrcRGB1 := SrcRGB; end else if (AzimuthChange >= 45 and (AzimuthChange < 90 then begin if (i < SrcBmp.Height - 1 then SrcRGB1 := SrcBmp.ScanLine[i+1] else SrcRGB1 := SrcRGB; SrcRGB2 := SrcRGB1; end else if (AzimuthChange >= 90 and (AzimuthChange < 135 then begin if (i < SrcBmp.Height - 1 then SrcRGB1 := SrcBmp.ScanLine[i+1] else SrcRGB1 := SrcRGB; SrcRGB2 := SrcRGB1; Inc(SrcRGB1; end else if (AzimuthChange >= 135 and (AzimuthChange <= 180 then begin if (i < SrcBmp.Height - 1 then SrcRGB2 := SrcBmp.ScanLine[i+1] else SrcRGB2 := SrcRGB; Inc(SrcRGB2; SrcRGB1 := SrcRGB; Inc(SrcRGB1; end; for j := 0 to SrcBmp.Width - 1 do begin if (AzimuthChange >= -180 and (AzimuthChange < -135 then begin Azimuthvalue := AzimuthChange + 180; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed*Azimuthvalue div 45-((SrcRGB2.rgbtRed*(45-Azimuthvalue div45+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen*Azimuthvalue div 45-((SrcRGB2.rgbtGreen*(45-Azimuthvalue div 45+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue*Azimuthvalue div 45-((SrcRGB2.rgbtBlue*(45-Azimuthvalue div 45+78; end else if (AzimuthChange >= -135 and (AzimuthChange < -90 then begin Azimuthvalue := AzimuthChange + 135; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed*Azimuthvalue div 45-((SrcRGB2.rgbtRed*(45-Azimuthvalue div 45+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen*Azimuthvalue div 45-((SrcRGB2.rgbtGreen*(45-Azimuthvalue div 45+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue*Azimuthvalue div 45-((SrcRGB2.rgbtBlue*(45-Azimuthvalue div 45+78; end else if (AzimuthChange >= -90 and (AzimuthChange < -45 then begin if j=1 then Inc(SrcRGB1,-1; Azimuthvalue := AzimuthChange + 90;R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed*Azimuthvalue div 45-((SrcRGB2.rgbtRed*(45-Azimuthvalue div 45+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen*Azimuthvalue div 45-((SrcRGB2.rgbtGreen*(45-Azimuthvalue div 45+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue*Azimuthvalue div 45-((SrcRGB2.rgbtBlue*(45-Azimuthvalue div 45+78; end else if (AzimuthChange >= -45 and (AzimuthChange < 0 then begin if j=1 then begin Inc(SrcRGB1,-1; Inc(SrcRGB2,-1; end; Azimuthvalue := AzimuthChange + 45; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed*Azimuthvalue div 45-((SrcRGB2.rgbtRed*(45-Azimuthvalue div 45+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen*Azimuthvalue div 45-((SrcRGB2.rgbtGreen*(45-Azimuthvalue div 45+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue*Azimuthvalue div 45-((SrcRGB2.rgbtBlue*(45-Azimuthvalue div 45+78; end else if (AzimuthChange >= 0 and (AzimuthChange < 45 then begin if j=1 then begin Inc(SrcRGB1,-1; Inc(SrcRGB2,-1; end; Azimuthvalue := AzimuthChange; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed*Azimuthvalue div 45-((SrcRGB2.rgbtRed*(45-Azimuthvalue div 45+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen*Azimuthvalue div 45-((SrcRGB2.rgbtGreen*(45-Azimuthvalue div 45+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue*Azimuthvalue div 45-((SrcRGB2.rgbtBlue*(45-Azimuthvalue div 45+78; end else if (AzimuthChange >= 45and (AzimuthChange < 90 then begin if j=1 then Inc(SrcRGB2,-1; Azimuthvalue := AzimuthChange - 45; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed*Azimuthvalue div 45-((SrcRGB2.rgbtRed*(45-Azimuthvalue div 45+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen*Azimuthvalue div 45-((SrcRGB2.rgbtGreen*(45-Azimuthvalue div 45+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue*Azimuthvalue div 45-((SrcRGB2.rgbtBlue*(45-Azimuthvalue div 45+78; end else if (AzimuthChange >= 90 and (AzimuthChange < 135 then begin Azimuthvalue := AzimuthChange - 90;R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed*Azimuthvalue div 45-((SrcRGB2.rgbtRed*(45-Azimuthvalue div 45+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen*Azimuthvalue div 45-((SrcRGB2.rgbtGreen*(45-Azimuthvalue div 45+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue*Azimuthvalue div 45-((SrcRGB2.rgbtBlue*(45-Azimuthvalue div 45+78; end else if (AzimuthChange >= 135 and (AzimuthChange <= 180 then begin Azimuthvalue := AzimuthChange - 135;R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed*Azimuthvalue div 45-((SrcRGB2.rgbtRed*(45-Azimuthvalue div 45+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen*Azimuthvalue div 45-((SrcRGB2.rgbtGreen*(45-Azimuthvalue div 45+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue*Azimuthvalue div 45-((SrcRGB2.rgbtBlue*(45-Azimuthvalue div 45+78; end; R:=Min(R,255; R:=Max(R,0; G:=Min(G,255; G:=Max(G,0; B:=Min(B,255; B:=Max(B,0; Gray := (R shr 2 + (R shr 4 + (G shr 1 + (G shr 4 + (B shr 3; DestRGB.rgbtRed:=Gray; DestRGB.rgbtGreen:=Gray; DestRGB.rgbtBlue:=Gray; if (j=-180 and (AzimuthChange<-135 or ((AzimuthChange>=90 and (AzimuthChange<=180 then begin Inc(SrcRGB1; end; if (j=135 and (AzimuthChange<180 or ((AzimuthChange>=-180 and (AzimuthChange<=-90 then begin Inc(SrcRGB2; end;Inc(SrcRGB; Inc(DestRGB; end; end; end; procedureEmboss(Bmp:TBitmap;AzimuthChange:integer;ElevationChange:integer;WeightChange: integer;overload; var DestBmp:TBitmap; begin DestBmp:=TBitmap.Create; DestBmp.Assign(Bmp;Emboss(Bmp,DestBmp,AzimuthChange,ElevationChange,WeightChange;Bmp.Assign(DestBmp; end; //反色 procedure Negative(Bmp:TBitmap; var i, j: Integer; PRGB: pRGBTriple; begin Bmp.PixelFormat:=pf24Bit; for i := 0 to Bmp.Height - 1 do begin PRGB := Bmp.ScanLine[i]; for j := 0 to Bmp.Width - 1 do beginPRGB^.rgbtRed :=not PRGB^.rgbtRed ; PRGB^.rgbtGreen :=not PRGB^.rgbtGreen; PRGB^.rgbtBlue :=not PRGB^.rgbtBlue; Inc(PRGB; end; end; end; //曝光 procedure Exposure(Bmp:TBitmap; var i, j: integer; PRGB: pRGBTriple; beginBmp.PixelFormat:=pf24Bit; for i := 0 to Bmp.Height - 1 do begin PRGB :=Bmp.ScanLine[i]; for j := 0 to Bmp.Width - 1 do begin if PRGB^.rgbtRed<128 then PRGB^.rgbtRed :=not PRGB^.rgbtRed ; if PRGB^.rgbtGreen<128 thenPRGB^.rgbtGreen :=not PRGB^.rgbtGreen; if PRGB^.rgbtBlue<128 thenPRGB^.rgbtBlue :=not PRGB^.rgbtBlue; Inc(PRGB; end; end; end; //模糊 procedure Blur(SrcBmp:TBitmap; var i, j:Integer; SrcRGB:pRGBTriple; SrcNextRGB:pRGBTriple; SrcPreRGB:pRGBTriple; Value:Integer; procedure IncRGB; begin Inc(SrcPreRGB;Inc(SrcRGB; Inc(SrcNextRGB; end; procedure DecRGB; begin Inc(SrcPreRGB,-1;Inc(SrcRGB,-1; Inc(SrcNextRGB,-1; end; begin SrcBmp.PixelFormat:=pf24Bit; for i := 0 to SrcBmp.Height - 1 do begin if i > 0 then SrcPreRGB:=SrcBmp.ScanLine[i-1] else SrcPreRGB := SrcBmp.ScanLine[i]; SrcRGB := SrcBmp.ScanLine[i]; if i <SrcBmp.Height - 1 then SrcNextRGB:=SrcBmp.ScanLine[i+1] elseSrcNextRGB:=SrcBmp.ScanLine[i]; for j := 0 to SrcBmp.Width - 1 do begin if j > 0 then DecRGB; Value:=SrcPreRGB.rgbtRed+SrcRGB.rgbtRed+SrcNextRGB.rgbtRed; if j > 0 then IncRGB;Value:=Value+SrcPreRGB.rgbtRed+SrcRGB.rgbtRed+SrcNextRGB.rgbtRed; if j < SrcBmp.Width - 1 then IncRGB;Value:=(Value+SrcPreRGB.rgbtRed+SrcRGB.rgbtRed+SrcNextRGB.rgbtRed div 9; DecRGB; SrcRGB.rgbtRed:=value;if j > 0 then DecRGB;Value:=SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen; if j > 0 thenIncRGB;Value:=Value+SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen; if j < SrcBmp.Width - 1 then IncRGB;Value:=(Value+SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen div 9; DecRGB; SrcRGB.rgbtGreen:=value; if j > 0 then DecRGB;Value:=SrcPreRGB.rgbtBlue+SrcRGB.rgbtBlue+SrcNextRGB.rgbtBlue; if j > 0 then IncRGB; Value:=Value+SrcPreRGB.rgbtBlue+SrcRGB.rgbtBlue+SrcNextRGB.rgbtBlue; if j < SrcBmp.Width - 1 then IncRGB;Value:=(Value+SrcPreRGB.rgbtBlue+SrcRGB.rgbtBlue+SrcNextRGB.rgbtBlue div 9; DecRGB; SrcRGB.rgbtBlue:=value; IncRGB; end; end; end; //锐化 procedureSharpen(SrcBmp:TBitmap; var i, j: integer; SrcRGB: pRGBTriple; SrcPreRGB: pRGBTriple; Value: integer; begin SrcBmp.PixelFormat:=pf24Bit; for i := 0 to SrcBmp.Height - 1 do begin SrcRGB := SrcBmp.ScanLine[i]; if i > 0 then SrcPreRGB:=SrcBmp.ScanLine[i-1] else SrcPreRGB:=SrcBmp.ScanLine[i]; for j := 0 to SrcBmp.Width - 1 do begin if j = 1 then Dec(SrcPreRGB;Value:=SrcRGB.rgbtRed+(SrcRGB.rgbtRed-SrcPreRGB.rgbtRed div 2;Value:=Max(0,Value; Value:=Min(255,Value; SrcRGB.rgbtRed:=value;Value:=SrcRGB.rgbtGreen+(SrcRGB.rgbtGreen-SrcPreRGB.rgbtGreen div 2;Value:=Max(0,Value; Value:=Min(255,Value; SrcRGB.rgbtGreen:=value;Value:=SrcRGB.rgbtBlue+(SrcRGB.rgbtBlue-SrcPreRGB.rgbtBlue div 2;Value:=Max(0,Value; Value:=Min(255,Value; SrcRGB.rgbtBlue:=value; Inc(SrcRGB; Inc(SrcPreRGB; end; end; end; [图像的旋转和翻转] 以下代码用ScanLine配合指针移动实现,用于24位色! //旋转90度 procedure Rotate90(const Bitmap:TBitmap; var i,j:Integer; rowIn,rowOut:pRGBTriple; Bmp:TBitmap; Width,Height:Integer; begin Bmp:=TBitmap.Create; Bmp.Width := Bitmap.Height; Bmp.Height := Bitmap.Width; Bmp.PixelFormat := pf24bit; Width:=Bitmap.Width-1; Height:=Bitmap.Height-1; for j := 0 to Height do begin rowIn := Bitmap.ScanLine[j]; for i := 0 to Width do beginrowOut := Bmp.ScanLine[i]; Inc(rowOut,Height - j; rowOut^ := rowIn^; Inc(rowIn; end;end; Bitmap.Assign(Bmp; end; //旋转180度 procedure Rotate180(constBitmap:TBitmap; var i,j:Integer; rowIn,rowOut:pRGBTriple; Bmp:TBitmap;Width,Height:Integer; begin Bmp:=TBitmap.Create; Bmp.Width := Bitmap.Width; Bmp.Height := Bitmap.Height; Bmp.PixelFormat := pf24bit; Width:=Bitmap.Width-1; Height:=Bitmap.Height-1; for j := 0 to Height do begin rowIn := Bitmap.ScanLine[j]; for i := 0 to Width do begin rowOut := Bmp.ScanLine[Height - j]; Inc(rowOut,Width - i; rowOut^ := rowIn^; Inc(rowIn; end; end; Bitmap.Assign(Bmp; end; //旋转270度procedure Rotate270(const Bitmap:TBitmap; var i,j:Integer; rowIn,rowOut:pRGBTriple; Bmp:TBitmap; Width,Height:Integer; begin Bmp:=TBitmap.Create; Bmp.Width := Bitmap.Height; Bmp.Height := Bitmap.Width; Bmp.PixelFormat :=pf24bit; Width:=Bitmap.Width-1; Height:=Bitmap.Height-1; for j := 0 to Height do begin rowIn := Bitmap.ScanLine[j]; for i := 0 to Width do begin rowOut :=Bmp.ScanLine[Width - i]; Inc(rowOut,j; rowOut^ := rowIn^; Inc(rowIn; end; end; Bitmap.Assign(Bmp; end; //任意角度 functionRotateBitmap(Bitmap:TBitmap;Angle:Integer;BackColor:TColor:TBitmap; vari,j,iOriginal,jOriginal,CosPoint,SinPoint : integer; RowOriginal,RowRotated : pRGBTriple; SinTheta,CosTheta : Extended; AngleAdd : integer; beginResult:=TBitmap.Create; Result.PixelFormat := pf24bit;Result.Canvas.Brush.Color:=BackColor; Angle:=Angle Mod 360; if Angle<0 then Angle:=360-Abs(Angle; if Angle=0 then Result.Assign(Bitmap else if Angle=90 then begin Result.Assign(Bitmap; Rotate90(Result;//如果是旋转90度,直接调用上面的代码 end else if (Angle>90 and (Angle<180 then begin AngleAdd:=90; Angle:=Angle-AngleAdd; end else if Angle=180 then begin Result.Assign(Bitmap; Rotate180(Result;//如果是旋转180度,直接调用上面的过程 end else if (Angle>180 and (Angle<270 then begin AngleAdd:=180; Angle:=Angle-AngleAdd; end else if Angle=270 then begin Result.Assign(Bitmap; Rotate270(Result;//如果是旋转270度,直接调用上面的过程end else if (Angle>270 and (Angle<360 then begin AngleAdd:=270; Angle:=Angle-AngleAdd; end else AngleAdd:=0; if (Angle>0 and (Angle<90 then begin SinCos((Angle+ AngleAdd * Pi / 180, SinTheta, CosTheta; if (SinTheta * CosTheta < 0 then begin Result.Width := Round(Abs(Bitmap.Width * CosTheta - Bitmap.Height * SinTheta; Result.Height := Round(Abs(Bitmap.Width * SinTheta - Bitmap.Height * CosTheta; end else begin Result.Width := Round(Abs(Bitmap.Width * CosTheta + Bitmap.Height * SinTheta; Result.Height := Round(Abs(Bitmap.Width * SinTheta + Bitmap.Height * CosTheta; end; CosTheta:=Abs(CosTheta; SinTheta:=Abs(SinTheta; if (AngleAdd=0 or (AngleAdd=180 then begin CosPoint:=Round(Bitmap.Height*CosTheta;SinPoint:=Round(Bitmap.Height*SinTheta; end else beginSinPoint:=Round(Bitmap.Width*CosTheta; CosPoint:=Round(Bitmap.Width*SinTheta; end; for j := 0 to Result.Height-1 do begin RowRotated := Result.Scanline[j]; for i := 0 to Result.Width-1 do begin Case AngleAdd of 0: begin jOriginal := Round((j+1*CosTheta-(i+1-SinPoint*SinTheta-1; iOriginal := Round((i+1*CosTheta-(CosPoint-j-1*SinTheta-1; end; 90: begin iOriginal := Round((j+1*SinTheta-(i+1-SinPoint*CosTheta-1; jOriginal := Bitmap.Height-Round((i+1*SinTheta-(CosPoint-j-1*CosTheta; end; 180: begin jOriginal := Bitmap.Height-Round((j+1*CosTheta-(i+1-SinPoint*SinTheta; iOriginal := Bitmap.Width-Round((i+1*CosTheta-(CosPoint-j-1*SinTheta; end; 270: begin iOriginal := Bitmap.Width-Round((j+1*SinTheta-(i+1-SinPoint*CosTheta; jOriginal := Round((i+1*SinTheta-(CosPoint-j-1*CosTheta-1; end; end; if (iOriginal >= 0 and (iOriginal <= Bitmap.Width-1and (jOriginal >= 0 and (jOriginal <=Bitmap.Height-1 then begin RowOriginal := Bitmap.Scanline[jOriginal];Inc(RowOriginal,iOriginal; RowRotated^ := RowOriginal^; Inc(RowRotated; end else begin Inc(RowRotated; end; end; end; end; end; //水平翻转 procedure FlipHorz(const Bitmap:TBitmap; var i,j:Integer; rowIn,rowOut:pRGBTriple; Bmp:TBitmap;Width,Height:Integer; begin Bmp:=TBitmap.Create; Bmp.Width := Bitmap.Width; Bmp.Height := Bitmap.Height; Bmp.PixelFormat := pf24bit; Width:=Bitmap.Width-1; Height:=Bitmap.Height-1; for j := 0 to Height do begin rowIn := Bitmap.ScanLine[j]; for i := 0 to Width do begin rowOut := Bmp.ScanLine[j]; Inc(rowOut,Width - i; rowOut^ := rowIn^; Inc(rowIn; end; end; Bitmap.Assign(Bmp; end; //垂直翻转 procedureFlipVert(const Bitmap:TBitmap; var i,j:Integer; rowIn,rowOut:pRGBTriple;Bmp:TBitmap; Width,Height:Integer; begin Bmp:=TBitmap.Create; Bmp.Width := Bitmap.Height; Bmp.Height := Bitmap.Width; Bmp.PixelFormat := pf24bit;Width:=Bitmap.Width-1; Height:=Bitmap.Height-1; for j := 0 to Height do beginrowIn := Bitmap.ScanLine[j]; for i := 0 to Width do begin rowOut :=Bmp.ScanLine[Height - j]; Inc(rowOut,i; rowOut^ := rowIn^; Inc(rowIn; end; end; Bitmap.Assign(Bmp; end; [亮度、对比度、饱和度的调整] 以下代码用ScanLine配合指针移动实现! function Min(a, b: integer: integer; begin if a < b then result := a else result := b; end; function Max(a, b: integer: integer; begin if a > b then result := a else result := b; end; //亮度调整 procedure BrightnessChange(constSrcBmp,DestBmp:TBitmap;ValueChange:integer; var i, j: integer; SrcRGB, DestRGB: pRGBTriple; begin for i := 0 to SrcBmp.Height - 1 do begin SrcRGB :=SrcBmp.ScanLine[i]; DestRGB := DestBmp.ScanLine[i]; for j := 0 to SrcBmp.Width - 1 do begin if ValueChange > 0 then begin DestRGB.rgbtRed := Min(255, SrcRGB.rgbtRed + ValueChange; DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + ValueChange; DestRGB.rgbtBlue := Min(255, SrcRGB.rgbtBlue + ValueChange; end else begin DestRGB.rgbtRed := Max(0, SrcRGB.rgbtRed + ValueChange; DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen + ValueChange; DestRGB.rgbtBlue := Max(0,SrcRGB.rgbtBlue + ValueChange; end; Inc(SrcRGB; Inc(DestRGB; end; end; end; //对比度调整 procedure ContrastChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer; var i, j: integer; SrcRGB, DestRGB: pRGBTriple; begin for i := 0 to SrcBmp.Height - 1 do begin SrcRGB := SrcBmp.ScanLine[i]; DestRGB := DestBmp.ScanLine[i]; for j := 0 to SrcBmp.Width - 1 do begin if ValueChange>=0 then begin if SrcRGB.rgbtRed >= 128 then DestRGB.rgbtRed := Min(255, SrcRGB.rgbtRed + ValueChange else DestRGB.rgbtRed := Max(0, SrcRGB.rgbtRed - ValueChange; if SrcRGB.rgbtGreen >= 128 then DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + ValueChange else DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen - ValueChange; ifSrcRGB.rgbtBlue >= 128 then DestRGB.rgbtBlue := Min(255, SrcRGB.rgbtBlue + ValueChange else DestRGB.rgbtBlue := Max(0, SrcRGB.rgbtBlue - ValueChange; end else begin if SrcRGB.rgbtRed >= 128 then DestRGB.rgbtRed := Max(128,SrcRGB.rgbtRed + ValueChange else DestRGB.rgbtRed := Min(128, SrcRGB.rgbtRed - ValueChange; if SrcRGB.rgbtGreen >= 128 then DestRGB.rgbtGreen := Max(128, SrcRGB.rgbtGreen + ValueChange else DestRGB.rgbtGreen := Min(128,SrcRGB.rgbtGreen - ValueChange; if SrcRGB.rgbtBlue >= 128 thenDestRGB.rgbtBlue := Max(128, SrcRGB.rgbtBlue + ValueChange elseDestRGB.rgbtBlue := Min(128, SrcRGB.rgbtBlue - ValueChange; end; Inc(SrcRGB; Inc(DestRGB; end; end; end; //饱和度调整 procedure SaturationChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer; var Grays: array[0..767] of Integer; Alpha: array[0..255] of Word; Gray, x, y: Integer; SrcRGB,DestRGB: pRGBTriple; i: Byte; begin ValueChange:=ValueChange+255; for i := 0 to 255 do Alpha[i] := (i * ValueChange Shr 8; x := 0; for i := 0 to 255 do begin Gray := i - Alpha[i]; Grays[x] := Gray; Inc(x; Grays[x] := Gray; Inc(x; Grays[x] := Gray; Inc(x; end; for y := 0 to SrcBmp.Height - 1 do begin SrcRGB := SrcBmp.ScanLine[Y]; DestRGB := DestBmp.ScanLine[Y]; for x := 0 to SrcBmp.Width - 1 do begin Gray :=Grays[SrcRGB.rgbtRed + SrcRGB.rgbtGreen + SrcRGB.rgbtBlue]; if Gray +Alpha[SrcRGB.rgbtRed]>0 then DestRGB.rgbtRed := Min(255,Gray +Alpha[SrcRGB.rgbtRed] else DestRGB.rgbtRed := 0; if Gray +Alpha[SrcRGB.rgbtGreen]>0 then DestRGB.rgbtGreen := Min(255,Gray +Alpha[SrcRGB.rgbtGreen] else DestRGB.rgbtGreen := 0; if Gray +Alpha[SrcRGB.rgbtBlue]>0 then DestRGB.rgbtBlue := Min(255,Gray +Alpha[SrcRGB.rgbtBlue] else DestRGB.rgbtBlue := 0; Inc(SrcRGB; Inc(DestRGB; end; end; end; //RGB调整 procedureRGBChange(SrcBmp,DestBmp:TBitmap;RedChange,GreenChange,BlueChange:integer; var SrcRGB, DestRGB: pRGBTriple; i,j:integer; begin for i := 0 to SrcBmp.Height- 1 dobegin SrcRGB := SrcBmp.ScanLine[i]; DestRGB :=DestBmp.ScanLine[i]; for j := 0 to SrcBmp.Width - 1 do begin if RedChange> 0 then DestRGB.rgbtRed:= Min(255, SrcRGB.rgbtRed + RedChange else DestRGB.rgbtRed := Max(0, SrcRGB.rgbtRed + RedChange; if GreenChange> 0 then DestRGB.rgbtGreen :=Min(255, SrcRGB.rgbtGreen + GreenChange else DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen + GreenChange; if BlueChange> 0 then DestRGB.rgbtBlue :=Min(255, SrcRGB.rgbtBlue + BlueChange else DestRGB.rgbtBlue := Max(0, SrcRGB.rgbtBlue + BlueChange; Inc(SrcRGB; Inc(DestRGB; end; end; end; [颜色调整] //RGB<=>BGR procedure RGB2BGR(const Bitmap:TBitmap; var X: Integer; Y: Integer; PRGB: pRGBTriple; Color: Byte; begin for Y := 0 to (Bitmap.Height - 1 do begin forX := 0 to (Bitmap.Width - 1 do begin Color := PRGB^.rgbtRed; PRGB^.rgbtRed := PRGB^.rgbtBlue; PRGB^.rgbtBlue := Color; Inc(PRGB; end; end end; end; //灰度化(加权 procedure Grayscale(const Bitmap:TBitmap; var X: Integer; Y: Integer; PRGB: pRGBTriple; Gray: Byte; begin for Y := 0 to (Bitmap.Height - 1 do begin PRGB := Bitmap.ScanLine[Y]; for X := 0 to (Bitmap.Width - 1 do begin Gray := (77 * Red + 151 * Green + 28 * Blue shr 8; PRGB^.rgbtRed:=Gray; PRGB^.rgbtGreen:=Gray;PRGB^.rgbtBlue:=Gray; Inc(PRGB; end; end; end; 绘图区-即窗口显示图像的区域,亦可为全屏幕(在全屏幕下绘图的效果比一般窗口下好)中心点-即要绘图区显示的中心点在原始图像的坐标(声明:这个概念特别重要)先说说图像的放大,要放大一张图片,我们一般的做法是直接放大图像,但本文介绍的方法仅放大我们能够看到的部分,放大分两种情况,一种是放大后比绘图区还要小,这种情况没什么好说,当然是显示全部的图像;第二种是放大后的图像比绘图区大,这才是我们今天要讨论的重点话题,这种情况下我们先要确定图像放大后的大小,然后根据“中心点”计算在原始图像的位置和大小,最后把截取的图像放大到绘图区。

由Delphi中的图像灰度化代码看基本图像处理

由Delphi中的图像灰度化代码看基本图像处理

CSDN - 专家门诊 - Delphi 图形处理/多媒体问题推荐 | 保存 | 关闭窗口主题:由Delphi中的图像灰度化代码看基本图像处理~~~作者: ehom (?!)等级:信誉值: 190所属论坛: Delphi 图形处理/多媒体问题点数: 33回复次数: 23发表时间: 2003-02-27 12:48:11Z[基础篇]首先看一段实现24位色图像灰度化转换的代码procedure Grayscale(const Bitmap:TBitmap);varX: Integer;Y: Integer;R,G,B,Gray: Byte;Color: TColor;beginfor Y := 0 to (Bitmap.Height - 1) dobeginfor X := 0 to (Bitmap.Width - 1) dobeginColor := Bitmap.Canvas.Pixels[X,Y];R := Color and $FF;G := (Color and $FF00) shr 8;B := (Color and $FF0000) shr 16;Gray := Trunc(0.3 * R + 0.59 * G + 0.11 * B);Bitmap.Canvas.Pixels[X,Y] := Gray shl 16 or Gray shl 8 or Gray; endendend;{这段代码效率是非常低的,但可以方便我们理解同时一些问题}Delphi的帮助中对TColor已经有了详细的描述,这可以方便我们理解上面的代码!首先看:R := Color and $FF;G := (Color and $FF00) shr 8;B := (Color and $FF0000) shr 16;这是段常见的从TColor中提取三原色的代码,但它是什么意思呢?首先应该知道and是与(.)运算,0.1=0,0.0=0,1.1=1,以取绿色为例:$FF00实际上就是$00FF00,它与一个TColor类型数按位进行与运算后,表示红色和绿色的位都变为了$00,而表示绿色的部分不变(0,1和1进行与运算值都不变),再右移8位,自然就获得了绿色值的8位表示!再获得三原色的值后,就是计算灰度值,0.3 * Red + 0.59 * Green + 0.11 * Blue 这是求加权平均值的公式。

Delphi图像处理之图像二值化

Delphi图像处理之图像二值化

Delphi图像处理之图像⼆值化-----------开发环境D7---效果图-------只提供参考----------------unit开始1unit Unit1;23interface45uses6 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,7 Dialogs, ExtCtrls, StdCtrls, ExtDlgs;89type10 ThresholdValueArray=array of array of Byte ;11 TForm1 = class(TForm)12 Button1: TButton;13 Button2: TButton;14 Image1: TImage;15 Image2: TImage;16 OpenPictureDialog1: TOpenPictureDialog;17 Label1: TLabel;18 Button4: TButton;19 Label2: TLabel;20 EditX: TEdit;21 EditY: TEdit;22 Label3: TLabel;23 Label4: TLabel;24 Label5: TLabel;25 Label6: TLabel;26 Label7: TLabel;27procedure Button1Click(Sender: TObject);28procedure Button2Click(Sender: TObject);29procedure Button4Click(Sender: TObject);30procedure EditXChange(Sender: TObject);31private32function GetThresholdValue(sBmp: TBitmap; sX,sY: Byte): ThresholdValueArray;33function GetThresholdArrayGray(const sArray:ThresholdValueArray; sStartX, sEndX, sStartY, sEndY: word): Byte; 34{ Private declarations }35public36{ Public declarations }37end;3839var40 Form1: TForm1;4142implementation4344{$R *.dfm}4546procedure TForm1.Button1Click(Sender: TObject);47begin48if OpenPictureDialog1.Execute then49begin50 Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);51 Label1.Caption:='图⽚宽x⾼:'+inttostr(Image1.Picture.Width)+'x'+inttostr(Image1.Picture.Height);52end;53end;5455procedure TForm1.Button2Click(Sender: TObject);56const57 vThresholdValue:Byte=128;58var59 vP:PByteArray;60 x,y:Integer;61 vBmp:TBitmap;62 vGray:Integer;63begin64if Image1.Picture.Graphic =nil then65begin66 ShowMessage('没有图⽚!');67 Exit;68end;69 vBmp:=TBitmap.Create;70 vBmp.Assign(Image1.Picture.Bitmap);71 vBmp.PixelFormat:=pf24bit;72for y:=0to vBmp.Height-1do73begin74 vP:=vBmp.ScanLine[y];75for x:=0to vBmp.Width-1do76begin77 vGray:=(77*vP[3*x+2] + 149*vP[3*x+1] + 29*vP[3*x]) shr8;78if vGray>vThresholdValue then79begin80 vP[3*x+2]:=255;81 vP[3*x+1]:=255;82 vP[3*x]:=255;83end84else85begin86 vP[3*x+2]:=0;87 vP[3*x+1]:=0;88 vP[3*x]:=0;89end;90end;91end;92 Image2.Picture.Assign(vBmp);93 vBmp.Free;94end;9596function TForm1.GetThresholdArrayGray(const sArray: ThresholdValueArray; sStartX,97 sEndX, sStartY, sEndY: word): Byte;98var99 vGraySum:DWORD;100 i,j:Word;101begin102 Result:=128;//默认返回128103if sArray=nil then104 Exit;105 vGraySum:=0;106for i:=sStartX-1to sEndX-1do107begin108for j:=sStartY-1to sEndY-1do109begin110 vGraySum:=vGraySum+sArray[i,j];111end;112end;113 Result:=Round(vGraySum/((sEndX-sStartX+1)*(sEndY-sStartY+1)));114end;115116function TForm1.GetThresholdValue(sBmp: TBitmap; sX,117 sY: Byte): ThresholdValueArray;118119var120 i,j,x,y,vGray:Word;121 vLengthX,vLengthY,vModX,vModY:Word;122 vP:PByteArray;123 vBitmapGrayArray:ThresholdValueArray;124 vResultGrayArray:ThresholdValueArray;125begin126 Result:=nil;127if sBmp=nil then128 Exit;129if sX=0then130 sX:=1;131if sY=0then132 sY:=1;133 setlength(vBitmapGrayArray,sBmp.Width);134for i:=0to sBmp.Width-1do135begin136 setlength(vBitmapGrayArray[i],sBmp.Height);137end;138 SetLength(vResultGrayArray,sX);139for i:=0to sX-1do140begin141 SetLength(vResultGrayArray[i],sY);142end;143144for y:=0to sBmp.Height-1do145begin146 vP:=sBmp.ScanLine[y];147for x:=0to sBmp.Width-1do148begin149 vGray:=(77*vP[3*x+2] + 149*vP[3*x+1] + 29*vP[3*x]) shr8;150 vBitmapGrayArray[x,y]:=vGray;151end;152end;153 vLengthX:=sBmp.width div sX;154 vLengthY:=sBmp.Height div sY;155 vModX:=sBmp.width mod sX;156 vMody:=sBmp.Height mod sY;157for i:=0to sX-1do//⼩块158begin159for j:=0to sY-1do//⼩块160begin161if i<>sX-1then162begin163 vResultGrayArray[i,j]:=GetThresholdArrayGray(vBitmapGrayArray,vLengthX*i+1,vLengthX*i+vLengthX,vLengthY*j+1,vLengthY*j+vLengthY);164end165else//最后⼀列166begin167 vResultGrayArray[i,j]:=GetThresholdArrayGray(vBitmapGrayArray,vLengthX*i+1,vLengthX*i+vLengthX+vModX,vLengthY*j+1,vLengthY*j+vLengthY+vModY); 168end;169173 Result:=vResultGrayArray;174//数组释放175for i:=0to sBmp.Width-1do176begin177 setlength(vBitmapGrayArray[i],0);178end;179 setlength(vBitmapGrayArray,0);180end;181182procedure TForm1.Button4Click(Sender: TObject);183var184 vP:PByteArray;185 x,y:Integer;186 vBmp:TBitmap;187 vGray:Integer;188 vLengthX, vLengthY, vModX, vModY,vRowMod,vColMod: Word;189 vX,vY:Byte;190 vGrayArray:ThresholdValueArray;191 vRow,vCol:byte;192begin193if Image1.Picture.Graphic =nil then194begin195 ShowMessage('没有图⽚!');196 Exit;197end;198 vX:=StrToIntDef(editX.Text ,3);199 vY:=StrToIntDef(editY.Text ,3);200201//暂时最多分成255*255块202if (vX<1) or (vX>255) or (vY<1) or (vY>255) then203begin204 MessageBox(Handle,PChar('X和Y的范围:1到255; 请输⼊在这个范围内的数字!'),PChar(Application.Title),MB_ICONEXCLAMATION); 205 Exit;206end;207 Label6.Caption:='总块数:'+inttostr(vX*vY);208 vBmp:=TBitmap.Create;209 vBmp.Assign(Image1.Picture.Bitmap);210 vBmp.PixelFormat:=pf24bit;211212 vGrayArray:=GetThresholdValue(vBmp,vX,vY);213for y:=0to vBmp.Height-1do214begin215 vP:=vBmp.ScanLine[y];216 vRow:=y div vLengthY;217 vRowMod:=y div vLengthY;218if vRow<vY then219begin220if vRowMod>0then221 vRow:=vRow+1;222end;223for x:=0to vBmp.Width-1do224begin225 vCol:=x div vLengthx;226 vColMod:=x div vLengthx;227if vCol<vX then228begin229if vColMod>0then230 vCol:=vCol+1;231end;232 vGray:=(77*vP[3*x+2] + 149*vP[3*x+1] + 29*vP[3*x]) shr8;233if vGray>vGrayArray[vCol,vRow] then234begin235 vP[3*x+2]:=255;236 vP[3*x+1]:=255;237 vP[3*x]:=255;238end239else240begin241 vP[3*x+2]:=0;242 vP[3*x+1]:=0;243 vP[3*x]:=0;244end;245end;246end;247 Image2.Picture.Assign(vBmp);248 vBmp.Free;249end;250251procedure TForm1.EditXChange(Sender: TObject);252begin253 Label6.Caption:='总块数:'+inttostr(StrToIntDef(EditX.Text ,0)*strtointDef(EditY.Text,0));--------unit结束--------Form开始1object Form1: TForm12 Left = 5133 Top = 3264 Width = 9105 Height = 5286 Caption = 'Form1'7 Color = clBtnFace8 Font.Charset = DEFAULT_CHARSET9 Font.Color = clWindowText10 Font.Height = -1111 = 'MS Sans Serif'12 Font.Style = []13 OldCreateOrder = False14 PixelsPerInch = 9615 TextHeight = 1316object Image1: TImage17 Left = 818 Top = 1619 Width = 42520 Height = 33721 Center = True22 Proportional = True23 Stretch = True24end25object Image2: TImage26 Left = 44827 Top = 1628 Width = 42529 Height = 33730 Center = True31 Proportional = True32 Stretch = True33end34object Label1: TLabel35 Left = 1636 Top = 36037 Width = 38538 Height = 2539 AutoSize = False40 Caption = '图⽚宽x⾼:'41end42object Label2: TLabel43 Left = 52844 Top = 36045 Width = 27346 Height = 1347 Alignment = taCenter48 AutoSize = False49 Caption = '按块求出阈值'50end51object Label3: TLabel52 Left = 45753 Top = 38154 Width = 7355 Height = 1356 Caption = '输⼊X x Y块:'57end58object Label4: TLabel59 Left = 53360 Top = 38161 Width = 2462 Height = 1363 Alignment = taRightJustify64 AutoSize = False65 Caption = 'X:'66end67object Label5: TLabel68 Left = 62069 Top = 38070 Width = 2171 Height = 1772 Alignment = taRightJustify73 AutoSize = False74 Caption = 'Y:'75end76object Label6: TLabel77 Left = 70478 Top = 38379 Width = 18580 Height = 1381 AutoSize = False82 Caption = '总块数:'83end84object Label7: TLabel85 Left = 51286 Top = 44087 Width = 37788 Height = 4589 AutoSize = False90 Caption = '理应是块数分的越多,越准确!本⼈这个呈抛物线的感觉,'#13#10'有⼀个最优的块数,算了先不找原因了,抛砖引⽟,哈哈哈'91 WordWrap = True92end93object Button1: TButton94 Left = 1695 Top = 41696 Width = 16197 Height = 2598 Caption = 'Button1_加载图⽚'99 TabOrder = 0100 OnClick = Button1Click101end102object Button2: TButton103 Left = 232104 Top = 416105 Width = 177106 Height = 25107 Caption = 'Button2_⼆值化_默认阈值'108 TabOrder = 1109 OnClick = Button2Click110end111object Button4: TButton112 Left = 560113 Top = 407114 Width = 297115 Height = 25116 Caption = 'Button4_分块求平均阈值,按块⼆值化'117 TabOrder = 2118 OnClick = Button4Click119end120object EditX: TEdit121 Left = 567122 Top = 378123 Width = 49124 Height = 21125 ImeName = '中⽂(简体) - 搜狗拼⾳输⼊法'126 TabOrder = 3127 Text = 'EditX'128 OnChange = EditXChange129end130object EditY: TEdit131 Left = 649132 Top = 379133 Width = 47134 Height = 21135 ImeName = '中⽂(简体) - 搜狗拼⾳输⼊法'136 TabOrder = 4137 Text = 'EditY'138 OnChange = EditXChange139end140object OpenPictureDialog1: TOpenPictureDialog141 Filter = 'Bitmaps (*.bmp)|*.bmp'142 Left = 72143 Top = 368144end145end------------Form结束。

delphi中的图像处理

delphi中的图像处理

图像处理基本知识彩色变灰度把一图由彩色变成灰度,也就是把每个像素的RGB各分量变为相同的,就成了灰度图像了pf24bit 模式下用BMP 的ScanLine 可以读取每一行的RGB数据.得到的是一个指针字节顺序是B,G,R亮度Y = 0.229R + 0.587G + 0.114B这个公式相当重要.以后很多图像处理都要用到它.方法1:方法一很简单,把RGB各分量相加,计算平均值,再设为新的RGB方法2:找出RGB 各分量中最大的.再设成新的RGB 值方法3:根据工式: Y = 0.229R + 0.587G + 0.114B算出亮度.新的RGB 各分量都为这个值.(个人认为第三种方法比较科学)代码:(方法一. 其它方法类似)bmp := TBitmap.Create;Bmp.Assign(Image1.Picture.Bitmap);bmp.HandleType :=bmDIB;bmp.PixelFormat := pf24bit;for j := 0 to bmp.Height -1 dobeginp := bmp.ScanLine[j];for i := 0 to Bmp.Width - 1 dobegingray1 :=Byte( (p[i*3] + p[i*3+1] + p[i*3+2]) div 3);p[i*3] := gray1;p[i*3+1]:= gray1;p[i*3+2] := gray1;end;end;Image2.Picture.Bitmap.Assign(bmp);bmp.free;==============================二值化:与灰度不同,二值化只有两种颜色.一般在做一些识别时用得比较多.方法:1, 计算出像素的亮度, 定义一个亮度阈值.2. 亮度大于这个阈值的像素,颜色为白,小于这个阈值的像素,颜色为黑.=======================================亮度调节取各个像素的RGB值,按比例加/减一个增量.也许用亮度公式来算出这个比例,比较科学.按一定比例,把部分的RGB 提升,一部分下降.================================-====Gamma校正(不太明白用在哪里.)分别把RGB 设为Min(255, round(255 * Power((OldValue / 256), 0.45))); NewValue := 255 乘(OldValue /256) 的 0.45 次方======================反色各分量取反.======================爆光小于128的取反。

基于Delphi扫描线技术的快速图像处理

基于Delphi扫描线技术的快速图像处理

基于Delphi扫描线技术的快速图像处理……t GRAPHICSPROGRAM………………………………………………………………………………………基于Delphi扫描线技术的快速图像处理张字摘要:传统的图像处理一般采用像素点赋值的方法,处理速度慢,对于大型图像几乎无能为力,而Delphi扫描线方法是对图像的每一行进行扫描,获得各像素的内存地址.这种内存操作比常规的像素点赋值效率高很多,从而可以大大提高大型位图图像的处理速度.关键词:内存操作;图像处理;扫描线Borland公司推出的Windows编程工具Delphi以其高度优化的编译器,强大的面向特性而越来越受到广大编程爱好者青睐,在许多大型项目如大型数据库系统设计,纹织CAD等企业级解决方案上有独特的优势.Delphi开发图像处理软件一般有两种基本方法:第一种方法是利用Delphi已经封装好了的可视化控件库VCL中已有的控件,Delphi中定义的类,对象,方法等,如Tlmage控件的一系列方法,TBitmap类的Scanline方法等,这种方法开发难度较低,开发者易于掌握;第二种方法是利用原生API或者经过Delphi稍微封装的函数开发,这种方法的特点是代码运行效率更高,节约资源,速度快,但同时开发难度稍大些.1原理Delphi提供了Canvas.Pixels属性,可以在画布(Canvas)上直接访问某一点的像素值.但用这个属性来执行访问速度很慢.比如,如果使用Pixels属性来把一个位图旋转90o,这种方法对于小的位图处理效果还是不错的,但是对于大一些的位图就无法接受了.它唯一的好处是,Canvas.Pixels属性对于所有的像素大小f1~24位1处理的方法都是一样的.在Delphi 中,可以替代Canvas.Pixels属性的就是直接引用WindowsAPI 来访问像素点数据f例如GetDIBits),但用WindowsAPI的DIB (DeviceIndependentBitmap)来访问像素数据更为复杂.假如使用DIB数据.则必须经常把它转换到TBitmap.并以Tlmage来显示.Delphi中TBitmap的Scanline和PixelFormat属性就提供了一个更好的Canvas.Pixels属性的代替.在Delphi的帮助中可以知道对Scanline的解释如下:propertyScanLine【Row:Integer]:Pointer;其中Row为位图图像的行号,返回的是一个指向位图像素数据的指针.通过Scanline可以获取某一行的所有像素点的信息,方便而且高速. 经测试,Scanline的速度为Canvas.PixelsIx]『y1Y方法的20倍以上.Delphi的Scanline包含了像素点的数据,但在访问像素数据以前,必须知道在内存中PixelFormat属性对Scanline属性的设计.因为不同的PixelFormat属性代表不同的位图格式,因而就有不同的Scanline方法.PixelFormat已在Graphics.pas 中定义了.其中包括pfCustom,pfDeviee,pflbit,pf4bit,pfSbit,pfl5bit.pf16bit.pf24bit和pf32bit.操作pf8bit位图相对容易,因为它的每个像素正好占一个字节,能够在pByteArray中直接访问.不过此时Seanline的值表示的是调色板上颜色的索引.调色板上包含了确切的R,G,B色.对于pf24bit的位图,首先定义一个类型:TypepRGBTripIeArray=TRGBTrIpIeArray:TRGBTripIeArray:ARRAY【0..32767】OFTRGBTriple;由于24bit的位图一个像素点是3个字节,不含调色板信息,所有的字节信息就是颜色信息,而由于pf32bit的位图一个像素点代表4个字节,Borland公司为此定义了一个类型(在Windows.pas下面1:pRGBQuad=q-RGBQuad;TRGBQuad=PACKEDRECORDrgbBlue:BYTE;rgbGreen:BYTE:rgbRed:B丫rE:rgbReserved:BYTE在颜色上.TRGBQuad和TRGBTriple是一样的.两者都用24位来记录颜色信息,8位红色,8位绿色,8位蓝色. TRGBQuad有更大一些的空间区域——"alpha"通道f在苹果机上较多采用).alpha通道在某些应用程序上用来传送灰度掩码信息,但现在还没有alpha通道相关的定义.要使用pf32bit 的Scanline就相当于要像使用单值动态数组一样来使用TBitmap.在测试中,用pf32bit的Scanline要比pf24bit快5%. 这就是32位属性的特点.所以用pf32bitSeanline有一些优势, 但是对于pt32bit来说,却没有那么多足够的空间来保存Scanline的值.一般在程序中将位图的格式设置为pf24bit就足够了…………………………………………………………实用第一智慧密集2图像的滤镜处理图像的滤镜处理可以用卷积运算来解决,卷积时使用一个奇数维的矩阵来表示.该矩阵体现在程序中就是模板概念.区域中的每个像素分别与模板中相应的元素相乘,相乘之和除以某个系数即为区域中心像素新值.不同的模板可以得到不同的效果.滤镜所用模板采用3x3矩阵,也可以采用5x5的矩阵,维数越大,处理时间越久.在采用模板操作时必须解决两个问题:一个是边界点问题,一般可以忽略第一列和最后一列像素的操作.或者直接进行边界像素的拷贝:还有一个是越界问题.必须保证中心像素点的各分量在0~255范围.为此定义一个存取模板矩阵值的数组v,长度为9,对于不同的滤镜效果,只需改变模板的矩阵值,而无需改动该处理过程.同时创建两个位图对象bmpl,bmp2,处理的思路是将Image控件上的位图分别加载到两个位图对象bmpl,bmp2中,其中从bmpi获取要处理的像素的信息,从bmp2获取要处理的像素的8个相邻像素信息.这样做的好处是从bmp2获取的是原始的未修改的信息,最后将bmpl显示于Image控件上.部分核心代码如下:V arbmp1.bmp2:TBitmap;//定义位图对象p1,p2,p3,p4:pByteArray;//定义字节指针j,j,z:integer;v:array[0..8】ofinteger;//定义模板数组beginz:=1://力口权后要除的系数bmpl:=TBitmap.Create;//l~Jj建位图对象1bmp2:=TBitmap.Create;//~U建位图对象2//力Ⅱ载位图到对象1中bmp1.Assign(image1.Picture.Bitmap);||格式转为24bitbmp1.PixeIFormat:=pf24bit;//力口载位图到对象2中|Q2.Assign(image1.Picture.Bitmap);//格式转为24bitbmp2.PixelFormat:=pf24bit;forj:=1tobmp1.height-2dobegin//扫描位图对象1第j行pl:=bmp1.ScanLine[j];∥扫描位图对象2的第卜1行p2:=bmp2.ScanLine[j一1】://扫描位图对象2的第1行p3:=bmp2.ScanLine[j];,/扫描位图对象2的第+1行p4:=bmp2.ScanLine[j+l】:fori:=1tobmp1.Width-2do与begin∥计算第个像素的红色分量p1【3i+2]:=min(255,max(O,((y【O】p213(i-1)+21+y[1lp213i+2】+y【2】p213(i+1)+2】+y【3】p313《i-1)+2】+yf4Jp313i+2】+yf5】p313(i+1)+21十yf6】p4[3(i-1)+2】+y【7lp413i+2】+y【8】p413(i+1)+2】))))//计算第i个像素的绿色分量p1【3i+1】:=min(255,max(0.((y【0Jp2【3({一1)+1l+y【1】p213i+11+y【2】p213(i+1)+1】+y【3】p313(i-1)+1】+Y【4】p313i+1l+y【5】p3[3(i+1)+1】+y【6】p4[3(i-1)+1】+y[7lp413i+1】+yl8lp413(i+1)+11))divz))://{十算第i个分量的蓝色分量p1【3il:=min(255,max(0,((y【O】p213(i-1)】+y【1lp213.】+y【2】p213(i十1)】+y【3】p3(i-1)】+y【4】p313i】+y{5】p313(1+ 1)】+y【6】p413(i-1)】+y【7lp4【3I】十yf81p4【3{i+1)】))": end;end;//将用模板处理后的位图重新显示Image1.Picture.Bitmap.Assign(Bmp1)Bmp1.free;//~放位图对象资源Bmp2.free;end;对于一幅24位的真彩色位图.代码中巧妙地利用Scanline获得了相邻三行像素的内存的起始地址,并由此取得特定像素点的R,G,B3个分量,其速度比用逐个的像素点操作快将近20倍,程序中的max和min函数有效地防止了中心像素点的越界可能.为了达到不同的滤镜效果,可以改变权系数数组Y,也就是改变模板矩阵Q.3图像的90.-决速旋转处理传统方法是将位图数据源像素信息赋予目的位置像素,最简单的方法就是采用Canvas.Pixel【x,y]赋值方式实现,这种方法的缺点是对于大型位图其实现速度非常慢.而扫描线方法可以获得旋转前位图和旋转后位图对应点的像素内存地址,通过把旋转前某点的像素值赋给旋转后对应点以达到整幅图像的旋转.这种基于内存的操作速度极快,核心代码如下:V araStream:TMemorystream;//定义内存流header:TBITMAPINFO;//定义位图信息头dc:hDC;//定义设备DCP:^THelpRGB;//定义一个THelpRGB类型的指针X,Y,b,h:Integer;RowOut:pRGBArray;//字节数组指针Begin∥创建一个内存流对象aStream:=TMemoryStream.Create;/y设置流的大小aStream.SetSizefBitmap.HeightBitmap.Width……GRAPHICSPROGIl 姗…………………………………………………………………………………………4):dc:=GetDC(O)//获得设备DCP:=aStream.Memory;//获得流的位置指针GetDIBits(dc,Bitmap.Handle,0,itmap.Height,Pheader,dib_RGB—Colors);ReleaseDC(O.dc);//释放设备DCb:=bitmap.Height;∥旋转前位图的高度h:=bitmap.Width;//旋转前位图的宽度bitmap.Width:=b:说//旋转后位图的宽度bitmap.height:=h:∥旋转后位图的高度forY:=0to(h一1)dObegin∥获得第Y行像素信息,这个是最重要的一步,节省时间row0ut:=Bitmap.ScanLine[y];∥获得内存指针P:=aStream.Memory;//将内存指针P位置增加Yinc(p,y):for×::0to(b-1)dobegin∥读取像素信息并且赋予相应位置rowout[x1:=p^.rgb;∥将内存指针P位置增加hinc(p,h);end;end;aStream.Free;//释放流资源end;4实验结果对比将一幅1024x768的24bit位图分别用Scanline方法和Canvas.Pixelfx,y】赋值方法进行旋转和高斯滤波,所用时问对比如表1所示.表1Scanline的方法和Canvas.Pixel【x,y】赋值方法处理时间比较Scanline疗法can,asPixe1[x.y]赋值方法实验名称所_刳时"1j所Hj时问高斯滤波13O270590.旋转l503240由表l也可以看出,采用Canvas,Pixellx,Y】方法的时间是Scanline方法的近20倍.其他的诸如位图的亮度,色度,饱和度等处理时间比较,Canvas.Pixel【x,y】方法的时间也接近Scanline方法时间的20倍.5结语Delphi的扫描线方法通过对位图图像的逐行扫描得到像素点的内存地址信息.所有的图像处理策略都在内存中实现.速度很快,这种优化方法对点阵图像的处理效果非常适合.对于大型位图图像,速度也很理想,用Scanline方法进行图像处理速度是像素点赋值速度的20倍以上.因此,Scanline方法越来越受到Delphi图像处理程序员的推崇.参考文献[1】MARCOCantu,王辉,李澎东,等译.Delphi从入门到精通[M】.北京:电子工业出版社,2002.[2】王华,梁志刚,王众,等.Delphi编程实例与技巧fM】.北京:机械工业出版社,2002.【3]阮秋琦.数字图像处理学【M】.北京:电子l[业出版社, 2002.【4]刘俊,王华.Delphi数字图像处理高级编程[M],北京:科学出版社.2003.(收稿日期:2009—12—26)升级到Windows7的好时机新一代操作系统受到业界好评近日,微软新一代操作系统Windows7自去年lO月份正式上市以来,凭借其优秀的整体性能和对生产力的明显促动,引发了众多用户的积极关注和采购热潮.其主流操作系统的地位已经广为市场接受.面对不断增长的企业用户对Windows7的需求,微软出台了一系列旨在推动Windows7企业客户的部署/使用的优惠措施,使企业客户可以在采用Windows7的新技术的过程中的各个环节.都能得到微软的针对性的支持和服务,还能以优惠的价格尽快迁移到Windows7最新数据表明,自Windows7正式发布至今,微软已经销售了超过9000万套许可,成为微软历史上上市以来销。

Delphi工具之Image Editor的使用

Delphi工具之Image Editor的使用

Delphi工具之Image Editor的使用Delphi Image Editor是一个工具,可用它来创建并编辑位图(.bmp)、图标(.ico)和光标(.cur),还可以用它创建资源工程,将多个位图、图标和光标包含到单个资源文件(.RES)中,再将该资源文件加到Delphi工程中供需要时使用。

如下图,是正在编辑中的Image Editor。

Note所有的Windows图像都是位图,无论它们是真正的Windows位图文件(.bmp),还是图标或光标。

在我们的讲解中,将所有图像都称为位图。

Image Editor只能处理Windows位图文件,它不支持其他文件格式,如PCX,TIFF,JPEG和GIF。

可从开始菜单中选择Image Editor菜单项启动Image Editor,也可以从Delphi的主菜单的【Tools | Image Editor】菜单项打开(如下图)。

Image Editor是一个单独的程序,不必在Delphi IDE中运行它。

Image Editor的各个部分介绍上图中将所有的工具箱中的工具名称列出,请熟悉它们。

Marquee选区工具和Lasso套索工具的作用一样的,前者用于选定矩形区域,后者用于任意形状的选择。

当一个区域被选定后,用户可剪切或复制该区域内的图像。

用Marquee和Lasso工具选定区域,将鼠标光标移动到该区域内(鼠标光标变成如下图的手型光标),拖动鼠标。

区域内的图像就会随鼠标的拖动而移动。

当剪切一个区域或移动它时,原始区域以当前背景色填充。

Note进行粘贴时,若选定了一个区域,则要粘贴的图像会随所选区域的大小而伸缩。

如下图:在使用Eraser橡皮工具时,鼠标的左右键的用法与使用其他工具时正好相反。

使用Eraser时,鼠标左键以背景色绘图,鼠标右键以前景色绘图。

Text工具能使用户在图像上书写文字,书写文字时使用当前正文设置,点击主菜单【Text】可设置字体的属性和正文对齐方式,如下图:Tip在画矩形时,可按住Shift键,将矩形变成正方形。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Delphi的图形处理Delphi的图形处理......................................................................................................- 1 - 第一章图像处理在可视化编程中的作用及其应用价值.................................- 2 - 第二章图像处理函数.......................................................................................- 2 -2.1 为什么选择Delphi..............................................................................- 2 -2.2 Delphi中用于图形处理的类...............................................................- 2 -2.3 GDI及Canvas类简介.........................................................................- 4 -第三章基本图像处理算法.............................................................................- 13 -3.1柔化和锐化处理.........................................................................................- 13 -3.2 图像混合(透明度)效果..............................................................................- 19 -3.3 转为灰度图像............................................................................................- 22 -3.4 对比度调整和反色处理.............................................................................- 23 -3.5 亮度的调整................................................................................................- 25 -3.6 浮雕效果....................................................................................................- 28 -3.7 马赛克效果................................................................................................- 31 -第一章图像处理在可视化编程中的作用及其应用价值图像处理,是可视化编程的基础内容。

在Windows操作系统中,一切要输出到屏幕上的东西都是通过图形处理这部分的内容来实现的。

比如一个程序使用了标签控件,它看起来似乎并没有用到什么图形处理,但实际上标签控件就是通过使用GDI库中的图形处理函数来实现的。

可见图形处理在编程中的重要性。

图像处理在实际的应用中也极具价值。

平面制作、动画制作等都离不开它。

这一部分的内容十分繁多。

我本次研究的内容,只是其中最基础的、最重要一部分。

第二章图像处理函数2.1 为什么选择Delphi所有的可视化编程语言都能够进行图像处理。

但由于这些语言的定位不同,它们在进行图形处理的效率和便捷程度上也各不相同。

实际上,Visual C 的图像处理效率是最高的,这是由于GDI类库本身就是用C++写的。

但是使用VC来编程并不是一件方便的事,因为这个语言本身就较为繁杂难懂,所以我没有选择它。

Visual Basic (VB)也是一个常用的语言,但它在图形处理方面能力较差。

首先是它的坐标系统是以twip为单位的浮点坐标系统,在调用GDI类库时,必须对坐标系统进行转换,浪费了大量的资源,编程起来较为麻烦。

在多方面因素的影响下,我觉得Delphi是一个理想的语言。

Delphi已经把绝大多数GDI绘图函数都封装成可直接调用的类,使用它进行图形处理操作十分方便,而且Delphi 是Pascal演变而来的,Pascal具有严谨易读的特点,因此很容易上手。

2.2 Delphi中用于图形处理的类Delphi为我们提供了许多图形图像方面的类,合理地使用这些类,我们可以方便地开发出各种图形处理程序。

这些类有TPicture、TBitmap、TGraphic、TIcon、TJPEGImage和TCanvas。

其中,TCanvas类用于绘图,TPicture、TBitmap、TIcon和TJPEGImage是专门用来处理图片的类,TGraphic是一个抽象类,一般不直接使用。

TPicture类可以载入所有支持的图片,而TBitmap、TIcon、TJPEGImage分别用于处理各种类型的图片。

在实际应用中,我们一般用这些具体类型的类载入图片,再将图片转为Bitmap格式来处理。

TPicture、TIcon、TJPEGImage类一般只用于输入和输出。

例如,下面的代码可以载入一幅任意支持格式的图片(Delphi所支持的格式为bmp、jpg、dib、wmf和emf)。

Var Pic:TPicture;BeginPic := TPicture.Create;Pic.LoadFromFile(FileName);End;用TPicture类来载入图片时,该类会根据文件名的扩展名来决定用何等方式来打开图片。

这就出现了一个问题,如果这个图片的扩展名被用户非法修改,程序就会把这个图片视为无效图片。

在真正编程中,我们要用TPicture、TBitmap、TJPEGImage、TIcon依次尝试去打开图片。

另外,Delphi本身是不支持GIF文件格式的。

我们可以借用一个第三方的类——GIFImage来让Delphi支持它。

这个类在附带的光盘中可以找到。

最终我们用下面的代码来完成载入图片的操作。

Procedure ReadPicture(FileName: String; Bitmap: Graphics.TBitmap);var pic:TPicture;Bit:Graphics.TBitmap;jpgPic:TJPEGImage;FGifPic:TGIFImage;icoPic:TIcon;beginFGifPic := TGifImage.Create;Pic:=Tpicture.Create;bit:=Graphics.TBitmap.Create;jpgPic:=TJPEGImage.Create;icoPic:=TIcon.Create;trypic.LoadFromFile(FileName);if uppercase(ExtractFileExt(Filename)) = '.ICO' then beginBitmap.Height:=pic.Height;Bitmap.Width:=Pic.Width;Bitmap.Canvas.Draw(0,0,Pic.Graphic);endelsebitmap.Assign(pic.Graphic);excepttrybitmap.LoadFromFile(FileName);excepttryjpgPic.LoadFromFile(FileName);bitmap.Assign(jpgPic);excepttryicoPic.LoadFromFile(Filename);bitmap.Free;Bitmap:=TBitmap.Create;bitmap.Height:=icoPic.Height;bitmap.Width:=icoPic.Width;bitmap.Canvas.Draw(0,0,icoPic);excepttryFgifPic.LoadFromFile(FileName);Bitmap.Assign(FGifPic.Bitmap);exceptbitmap.Height:=bitmap.Canvas.TextHeight('8');bitmap.Width:=bitmap.Canvas.TextWidth('无效图片'); BitMap.Canvas.TextOut(0,0,'无效图片');end;{try}end;end;{try}end;{try}end;{try}Pic.Free ;bit.Free;jpgPic.Free;icoPic.Free;FGifPic.Free;end;保存图片的方法跟打开图片的方法类似,我们可以使用不同类型的图片类的SaveToFile方法保存文件。

下面的代码可以根据文件名中扩展名的不同使用不同的类来保存Bitmap。

Procedure SaveBitmap(FileName: String; PicB: TBitmap);var pic:TPicture; FileExt:String;picJPG:TJPEGImage;picGIF:TGIFImage;beginpic:=TPicture.Create;picJPG:=TJPEGImage.Create;picGIF:=TGIFImage.Create;trypic.Assign(PicB);FileExt:= ExtractFileEXT(FileName);if (Uppercase(FileExt)='.JPG')or(Uppercase(FileExt)='.JPEG')or(Uppercase(FileExt)='.JPE') thenbeginpicJPG.Assign(PicB);picJPG.SaveToFile(FileName);endelse If (UpperCase(FileExt)='.BMP')OR(UpperCase(FileExt)='.DIB')THENBeginPicB.SaveToFile(FileName);endelse if (UpperCase(FileExt)='.GIF') then beginpicGIF.Assign(PicB);PicGIF.SaveToFile(FileName);endelsePic.SaveToFile(FileName);{End If}ShowPicture(PictureIndex,False,TPicture(PicB));Finallypic.Free;picJPG.Free;PicGIF.Free;end;end;2.3 GDI及Canvas类简介GDI(Graphics Device Interface,图形设备接口)是Windows为我们提供的一个专门用于图形绘制和屏幕输出的类库。

相关文档
最新文档