Los ejemplos de este artículo resumen los métodos básicos de procesamiento de imágenes de Delphi. Compártelo con todos para tu referencia. El análisis específico es el siguiente:
//Procedimiento de relieve Emboss(SrcBmp,DestBmp:TBitmap;AzimuthChange:integer);overload;var i, j, Gray, Azimuthvalue, R, G, B: integer for i: = 0 a SrcBmp.Height - 1 comienza SrcRGB := SrcBmp.ScanLine[i]; DestRGB := DestBmp.ScanLine[i]; si (AzimuthChange >= -180) y (AzimuthChange < -135) entonces comience si i > 0 entonces SrcRGB1 := SrcBmp.ScanLine[i-1] más SrcRGB1 := SrcRGB Inc(SrcRGB1); := SrcRGB; Inc(SrcRGB2); finalice si (AzimuthChange >= -135) y (AzimuthChange < -90) luego comience si i > 0 entonces SrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB; SrcRGB2 := SrcRGB1 Inc(SrcRGB2); (AzimuthChange >= -90) y (AzimuthChange < -45) luego comience si i > 0 entonces SrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB2 := SrcRGB1; -45) y (AzimuthChange < 0) luego comience SrcRGB1 := SrcRGB; si i > 0 entonces SrcRGB2 := SrcBmp.ScanLine[i-1] else SrcRGB2 := SrcRGB; finalice else if (AzimuthChange >= 0) y (AzimuthChange < 45) luego comience SrcRGB2 := SrcRGB; SrcBmp.Height - 1) luego SrcRGB1 := SrcBmp.ScanLine[i+1] else SrcRGB1 := SrcRGB; finalice else if (AzimuthChange >= 45) y (AzimuthChange < 90) luego comience si (i < SrcBmp.Height - 1) luego SrcRGB1 := SrcBmp.ScanLine[i +1] más SrcRGB1 := SrcRGB2 := SrcRGB1; finalice si (AzimuthChange >= 90) y (AzimuthChange < 135) luego comience si (i < SrcBmp.Height - 1) entonces SrcRGB1 := SrcBmp.ScanLine[i+1] else SrcRGB1 := SrcRGB2 := SrcRGB1; Inc(SrcRGB1); (AzimuthChange >= 135) y (AzimuthChange <= 180) luego comience si (i < SrcBmp.Height - 1) entonces SrcRGB2 := SrcBmp.ScanLine[i+1] else SrcRGB2 := SrcRGB Inc(SrcRGB2); = SrcRGB Inc(SrcRGB1); fin; 0 a SrcBmp.Width - 1 comience si (AzimuthChange >= -180) y (AzimuthChange < -135) luego comience Azimuthvalue := AzimuthChange + 180 R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Azimuthvalue div; 45)-((SrcRGB2.rgbtRed)*(45-Valor de azimut) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*Valor de azimut div 45)-((SrcRGB2.rgbtGreen)*(45- Valor de acimut)div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*Azimuthvalue div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; fin si (AzimuthChange >= -135) y (AzimuthChange) < -90) luego comience el valor de azimut := Cambio de azimut + 135; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Valor de azimut div 45)-((SrcRGB2.rgbtRed)*(Valor de azimut 45) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*Valor de azimut div 45)-((SrcRGB2.rgbtGreen)*(Valor de azimut 45) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue) *Div valor de acimut 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; finalice si (AzimuthChange >= -90) y (AzimuthChange < -45) luego comience si j=1 y luego Inc(SrcRGB1,- 1); valor de acimut: = cambio de azimut + 90; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Valor de azimut div 45)-((SrcRGB2.rgbtRed)*(Valor de azimut 45) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *Div valor de acimut 45)-((SrcRGB2.rgbtGreen)*(45-Valor de azimut) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*Valor de azimut div 45)-((SrcRGB2.rgbtBlue)*(45- Valor de acimut) div 45)+78; si (AzimuthChange >= -45) y (AzimuthChange < 0) entonces comienza si j=1 entonces comienza Inc(SrcRGB1,-1); Inc(SrcRGB2,-1); SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Valor de acimut div 45)-((SrcRGB2.rgbtRed)*(45-Valor de azimut) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*Valor de azimut div 45)-((SrcRGB2.rgbtGreen)*(45- Valor de acimut)div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*Azimuthvalue div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; fin si (AzimuthChange >= 0) y (AzimuthChange < 45) entonces comienza si j=1 entonces comienza Inc(SrcRGB1,-1); Inc(SrcRGB2,-1); valor de azimut:= Cambio de azimut; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Valor de azimut div 45)-((SrcRGB2.rgbtRed)*( 45-valor de azimut)div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*Valor de azimut div 45)-((SrcRGB2.rgbtGreen)*(Valor de azimut 45) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue) *Div valor de acimut 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; finalice si (AzimuthChange >= 45) y (AzimuthChange < 90) luego comience si j=1 entonces Inc(SrcRGB2,-1) ; Valor de azimut := Cambio de azimut - 45; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Valor de azimut div 45)-((SrcRGB2.rgbtRed)*(Valor de azimut 45) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *Div valor de acimut 45)-((SrcRGB2.rgbtGreen)*(45-Valor de azimut) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*Valor de azimut div 45)-((SrcRGB2.rgbtBlue)*(45- Valor de acimut) div 45)+78; si (AzimuthChange >= 90) y (AzimuthChange < 135) entonces comience Azimuthvalue := AzimuthChange - 90; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Azimuthvalue div 45)-((SrcRGB2.rgbtRed)*(45 -Valor de acimut) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*Valor de azimut div 45)-((SrcRGB2.rgbtGreen)*(Valor de azimut 45) div 45)+78; (SrcRGB1.rgbtBlue)*Valor de acimut div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; finalice si (AzimuthChange >= 135) y (AzimuthChange <= 180) luego comience Azimuthvalue := AzimuthChange - 135; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Valor de azimut div 45)-((SrcRGB2.rgbtRed)*(Valor de azimut 45) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *Div valor de acimut 45)-((SrcRGB2.rgbtGreen)*(45-Valor de azimut) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*Valor de azimut div 45)-((SrcRGB2.rgbtBlue)*(45- Valor de acimut) div 45)+78; R:=Mín(R,255); R:=Máx(R,0); G:=Mín(G,255); B:=Max(B,0); Gris := (R shr 2) + (R shr 4) + (G shr 1) + (G shr 4) + (B shr 3); DestRGB.rgbtRed:=Gris; DestRGB.rgbtGreen:=Gris; DestRGB.rgbtBlue:=Gris; si (j=-180) y (AzimuthChange<-135)) o ((AzimuthChange>=90) y (AzimuthChange<=180 ))) luego comience Inc(SrcRGB1); (j=135) y (AzimuthChange<180)) o ((AzimuthChange>=-180) y (AzimuthChange<=-90))) luego comienzan Inc(SrcRGB2); fin; fin; fin; procedimiento Emboss(Bmp:TBitmap;AzimuthChange:integer;ElevationChange:integer;WeightChange:integer);sobrecarga;var DestBmp:TBitmap;begin DestBmp:=TBitmap.Create DestBmp.Assign(Bmp); ,Cambio de peso); Bmp.Assign(DestBmp);end;//Procedimiento inverso Negativo(Bmp:TBitmap);var i, j: Integer; PRGB: pRGBTriple;begin Bmp.PixelFormat:=pf24Bit for i := 0 to Bmp.Height - 1; comience PRGB := Bmp.ScanLine[i]; para j := 0 a Bmp.Width - 1 comenzar PRGB^.rgbtRed :=no PRGB^.rgbtRed ; PRGB^.rgbtGreen :=no PRGB^.rgbtGreen; PRGB^.rgbtBlue :=no PRGB^.rgbtBlue Inc(PRGB); Procedimiento de exposición Exposición(Bmp:TBitmap);var i, j: entero PRGB: pRGBTriple;begin; Bmp.PixelFormat:=pf24Bit; para i := 0 a Bmp.Height - 1 comienza PRGB := Bmp.ScanLine[i]; para j := 0 a Bmp.Width - 1 comienza si PRGB^.rgbtRed<128 entonces PRGB^.rgbtRed :=no PRGB^.rgbtRed ; si PRGB^.rgbtGreen<128 entonces PRGB^.rgbtGreen :=no PRGB^.rgbtGreen; si PRGB^.rgbtBlue<128 entonces PRGB^.rgbtBlue :=no PRGB^.rgbtBlue; Inc(PRGB); fin;//procedimiento de desenfoque Desenfoque( SrcBmp:TBitmap);var i, j:Entero; SrcRGB:pRGBTriple; SrcNextRGB:pRGBTriple; SrcPreRGB:pRGBTriple; procedimiento IncRGB; final; SrcBmp.PixelFormat:=pf24Bit; para i := 0 a SrcBmp.Height - 1 comience si i > 0 entonces SrcPreRGB:=SrcBmp.ScanLine[i-1] else SrcPreRGB := SrcBmp.ScanLine[i]; SrcBmp.ScanLine[i]; si i < SrcBmp.Height - 1 entonces SrcNextRGB:=SrcBmp.ScanLine[i+1] else SrcNextRGB:=SrcBmp.ScanLine[i]; para j := 0 a SrcBmp.Width - 1 comience si j > 0 entonces DecRGB;=SrcPreRGB.rgbtRed+ SrcRGB; .rgbtRed+SrcNextRGB.rgbtRed si j > 0 entonces IncRGB Valor:=Valor+SrcPreRGB.rgbtRed+SrcRGB.rgbtRed+SrcNextRGB.rgbtRed; si j < SrcBmp.Width - 1 entonces IncRGB Valor:=(Valor+SrcPreRGB.rgbtRed+SrcRGB.rgbtRed+SrcNextRGB.rgbtRed) división 9; DecRGB; SrcRGB.rgbtRed:=valor; si j > 0 entonces DecRGB Valor:=SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen; Valor:=Valor+SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen; si j < SrcBmp.Width - 1 entonces IncRGB Valor:=(Valor+SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen) div 9; ; SrcRGB.rgbtGreen:=valor; si j>0 entonces DecRGB;=SrcPreRGB.rgbtBlue+SrcRGB.rgbtBlue+SrcNextRGB.rgbtBlue; si j>0 entonces IncRGB; .rgbtAzul; si j < SrcBmp.Width - 1 luego IncRGB; Valor:=(Valor+SrcPreRGB.rgbtBlue+SrcRGB.rgbtBlue+SrcNextRGB.rgbtBlue) div 9; SrcRGB.rgbtBlue:=valor;fin;//procedimiento de afilado; Enfocar(SrcBmp:TBitmap);var i, j: entero; SrcRGB: pRGBTriple; SrcPreRGB: pRGBTriple; valor entero; comience SrcBmp.PixelFormat:=pf24Bit; para i := 0 a SrcBmp.Height - 1 comience SrcBmp.ScanLine[i]; SrcPreRGB:=SrcBmp.ScanLine[i-1] else SrcPreRGB:=SrcBmp.ScanLine[i]; para j := 0 a SrcBmp.Width - 1 comience si j = 1 luego Dec(SrcPreRGB); rgbtRed+(SrcRGB.rgbtRed-SrcPreRGB.rgbtRed) div 2; Valor:=Max(0,Valor); Valor:=Min(255,Valor; SrcRGB.rgbtRed:=valor:=SrcRGB.rgbtGreen+(SrcRGB.rgbtGreen-SrcPreRGB.rgbtGreen) div 2; Máximo (0, Valor); Valor: = Mín (255, Valor); SrcRGB.rgbtGreen:=valor;=SrcRGB.rgbtBlue+(SrcRGB.rgbtBlue-SrcPreRGB.rgbtBlue) div 2 Valor:=Max(0,Valor:=Min(255,SrcRGB.rgbtBlue); valor Inc(SrcRGB); Inc(SrcPreRGB); fin; [Rotación y volteo de imágenes] El siguiente código se implementa usando ScanLine con movimiento del puntero, para color de 24 bits. //Girar 90 grados procedimiento Rotate90(const Bitmap:TBitmap);var i,j:Integer; rowIn,rowOut:pRGBTriple; Bmp:TBitmap Ancho,Alto:Integer;begin Bmp:=TBitmap.Create; Mapa de bits.Altura; Bmp.Altura := Mapa de bits.Ancho; Bmp.PixelFormat := pf24bit; Ancho:=Bitmap.Width-1; Alto:=Bitmap.Height-1; para j:= 0 hasta Ancho comienza filaEn:= Bitmap.ScanLine[j]; = Bmp.ScanLine[i]; Inc(filaOut,Altura - j); filaOut^ := filaIn^; Bitmap.Assign(Bmp);end;//Rotar 180 grados procedimiento Rotate180(const Bitmap:TBitmap);var i,j:Integer; rowIn,rowOut:pRGBTriple; TBitmap.Create; Bmp.Ancho:= Mapa de bits.Ancho; Bmp.Altura:= Bitmap.Height; Bmp.PixelFormat := pf24bit; Ancho:=Bitmap.Width-1; Alto:=Bitmap.Height-1 para j := 0 a Alto comience filaEn := Bitmap.ScanLine[j]; := 0 a Ancho comienza rowOut := Bmp.ScanLine[Height - j] Inc(rowOut,Width - i); filaOut^ := filaIn^; Inc(rowIn); end; Bitmap.Assign(Bmp);end;//Rotar 270 grados procedimiento Rotate270(const Bitmap:TBitmap);var i,j:Integer; pRGBTriple; Bmp: TBitmap Ancho, Alto: Entero; comenzar Bmp: = TBitmap.Create; := Bitmap.Height; Bmp.Height := Bitmap.Width; Bmp.PixelFormat := pf24bit; Ancho:=Bitmap.Width-1; := Bitmap.ScanLine[j]; para i := 0 a Ancho comience rowOut := Bmp.ScanLine[Ancho - i]; Inc(rowOut,j); rowOut^ := rowIn^; Bitmap.Assign(Bmp);end;// Cualquier función de ángulo RotateBitmap(Bitmap): TBitmap;Ángulo:Entero;BackColor:TColor):TBitmap;var i,j,iOriginal,jOriginal,CosPoint,SinPoint: entero; RowOriginal,RowRotated: pRGBTriple; SinTheta,CosTheta: Extendido; AngleAdd: entero;comenzar Resultado:=TBitmap.Create;Angle Mod 360; ; si Ángulo<0 entonces Angle:=360-Abs(Angle); si Angle=0 entonces Result.Assign(Bitmap) si no, si Angle=90 entonces comience Result.Assign(Rotate90(Result);//Si se gira 90 grados, llame directamente El código anterior termina si (Angle>90) y (Angle<180) luego comienzan AngleAdd:=90; Angle:=Angle-AngleAdd; end else if Angle=180 luego comience Result.Assign(Rotate180(Result);// Si se gira 180 grados, llame directamente al proceso anteriorend else if (Angle>180) y ( Ángulo<270) luego comienza AngleAdd:=180; Ángulo:=Angle-AngleAdd termina si Angle=270 luego comienza; Result.Assign(Bitmap); Rotate270(Result);// Si se gira 270 grados, llame directamente al proceso anterior y finalice si (Angle>270) y (Angle<360) luego comience AngleAdd:=270; Ángulo -AngleAdd; fin si no AngleAdd:=0 si (Angle>0) y (Angle<90) entonces comienzan SinCos((Angle) + AngleAdd) * Pi / 180, SinTheta, CosTheta); si (SinTheta * CosTheta) < 0 entonces comience Result.Width := Round(Abs(Bitmap.Width * CosTheta - Bitmap.Height * SinTheta)); = Redondo(Abs(Mapa de bits.Ancho * SinTheta - Mapa de bits.Altura * CosTheta)); fin si no comenzar Result.Width := Round(Abs(Bitmap.Width * CosTheta + Bitmap.Height * SinTheta) Result.Height := Round(Abs(Bitmap.Width * SinTheta + Bitmap.Height * CosTheta)); ; CosTheta:=Abs(CosTheta); (AngleAdd=0) o (AngleAdd=180) luego comience CosPoint:=Round(Bitmap.Height*CosTheta); ); CosPoint:=Round(Bitmap.Width*SinTheta); Result.Height-1 comienza RowRotated := Result.Scanline[j]; para i := 0 a Result.Width-1 comienza Case AngleAdd de 0: comienza jOriginal := Round((j+1)*CosTheta-( i+1-SinPunto)*SinTheta)-1; iOriginal := Ronda((i+1)*CosTheta-(CosPoint-j-1)*SinTheta)-1; final 90: inicio iOriginal := Ronda((j+1)*SinTheta-(i+1-SinPoint)*CosTheta; )-1; jOriginal := Mapa de bits.Altura-Ronda((i+1)*SinTheta-(CosPoint-j-1)*CosTheta); fin 180: comenzar jOriginal := Bitmap.Height-Round((j+1)*CosTheta-(i+1-SinPoint)*iOriginal := Bitmap.Width-Round((i+1)*CosTheta-); (CosPoint-j-1)*SinTheta); fin 270: comienzo iOriginal := Bitmap.Width-Round((j+1)*SinTheta-(i+1-SinPoint)*CosTheta); jOriginal := Round((i+1)*SinTheta-(CosPoint-j-1)*CosTheta)-1 ; fin; fin; si (iOriginal >= 0) y (iOriginal <= Bitmap.Width-1) y (jOriginal >= 0) y (jOriginal <= Bitmap.Height-1) luego comience RowOriginal := Bitmap.Scanline[jOriginal]; Inc(RowOriginal,iOriginal); RowRotated^ := RowOriginal^; ; end; end; end;end;//Procedimiento de giro horizontal FlipHorz(const Bitmap:TBitmap);var i,j:Integer; filaIn,rowOut:pRGBTriple; Bmp:TBitmap; Ancho,Alto:Integer;comenzar Bmp:=TBitmap.Create; Formato de píxel:= pf24bit Ancho:=Mapa de bits.Ancho-1; Altura:=Bitmap.Height-1; para j:= 0 a Altura, comience la filaIn:= Bitmap.ScanLine[j]; para i:= 0 a Ancho, comience la filaSalida:= Bmp.ScanLine[j]; ,Ancho - i); filaOut^ := filaIn^; Inc(filaIn final); FlipVert(const Bitmap:TBitmap);var i,j:Integer; filaIn,rowOut:pRGBTriple; Bmp:TBitmap Ancho,Alto:Integer;begin Bmp:=TBitmap.Create; Alto:= Mapa de bits.Ancho; Bmp.PixelFormat:= pf24bit; Ancho:=Bitmap.Width-1; Alto:=Bitmap.Height-1; para j:= 0 hasta Alto comienza filaEn:= Bitmap.ScanLine[j]; .ScanLine[Altura - j]; Inc(filaOut,i); filaOut^ := filaIn^; Bitmap.Assign(Bmp);end;[Ajuste de brillo, contraste y saturación] ¡El siguiente código se implementa usando ScanLine con movimiento del puntero! función Min(a, b: entero): entero;comienza si a < b entonces resultado:= a else resultado:= b;fin;función Max(a, b: entero): entero;comienza si a> b entonces resultado: = un resultado else := b;end;//Procedimiento de ajuste de brillo BrightnessChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var i, j: integer; SrcRGB, DestRGB: pRGBTriple; comenzar para i := 0 a SrcBmp.Height - 1 comenzar SrcRGB := SrcBmp.ScanLine[i]; 1 comienzo si ValueChange> 0 y luego comienzo DestRGB.rgbtRed: = Min(255, SrcRGB.rgbtRed + ValueChange); DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + ValueChange); DestRGB.rgbtBlue := Min(255, SrcRGB.rgbtBlue + ValueChange); =Máx(0, SrcRGB.rgbtRed + ValueChange); DestRGB.rgbtGreen:= Max(0, SrcRGB.rgbtGreen + ValueChange); DestRGB.rgbtBlue:= Max(0, SrcRGB.rgbtBlue + ValueChange); ; fin; fin; fin;//procedimiento de ajuste de contraste ContrastChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var i, j: integer; DestRGB: pRGBTriple;comenzar para i := 0 a SrcBmp.Height - 1 comenzar SrcRGB := SrcBmp.ScanLine[i] ; DestRGB := DestBmp.ScanLine[i]; := 0 a SrcBmp.Width - 1 comience si ValueChange>=0 luego comience si SrcRGB.rgbtRed >= 128 luego DestRGB.rgbtRed := Min(255, SrcRGB.rgbtRed + ValueChange) más DestRGB.rgbtRed := Max(0 , SrcRGB.rgbtRed - Cambio de valor); SrcRGB.rgbtGreen >= 128 entonces DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + ValueChange) más DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen - ValueChange); si SrcRGB.rgbtBlue >= 128 entonces DestRGB.rgbtBlue); := Min(255, SrcRGB.rgbtBlue + ValueChange) else DestRGB.rgbtBlue := Max(0, SrcRGB.rgbtBlue - ValueChange); finaliza si SrcRGB.rgbtRed >= 128 entonces DestRGB.rgbtRed := Max(128, SrcRGB.rgbtRed + Cambio de valor) más DestRGB.rgbtRed := Min(128, SrcRGB.rgbtRed - ValueChange); si SrcRGB.rgbtGreen >= 128 entonces DestRGB.rgbtGreen := Max(128, SrcRGB.rgbtGreen + ValueChange) más DestRGB.rgbtGreen := Min(128, SrcRGB .rgbtVerde - ValueChange); si SrcRGB.rgbtBlue >= 128 entonces DestRGB.rgbtBlue := Max(128, SrcRGB.rgbtBlue + ValueChange) más DestRGB.rgbtBlue := Min(128, SrcRGB.rgbtBlue - ValueChange inc; Inc(DestRGB); end;end;//Procedimiento de ajuste de saturación SaturationChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var Grays: matriz[0..767] de Integer; matriz[0..255] de Word Gray; x, y: Entero; SrcRGB,DestRGB: pRGBTriple i: Byte;beginValueChange:=ValueChange+255;for i := 0 a 255 do Alpha[i] := (i * ValueChange) Shr 8;x := 0;for i := 0 a 255 dobegin Gray := i - Alpha [i]; Grises[x] := Gris; Inc(x); Grises[x] := Gris; Grises[x] := Gris; Inc(x);fin; para y := 0 a SrcBmp.Height - 1 dobegin SrcRGB := SrcBmp.ScanLine[Y]; comience Gris := Grises[SrcRGB.rgbtRed + SrcRGB.rgbtGreen + SrcRGB.rgbtBlue]; si Gray + Alpha[SrcRGB.rgbtRed]>0 entonces DestRGB.rgbtRed := Min(255,Gray + Alpha[SrcRGB.rgbtRed]) más DestRGB.rgbtRed := 0; rgbtGreen]>0 luego DestRGB.rgbtGreen := Min(255,Gray + Alpha[SrcRGB.rgbtGreen]) else DestRGB.rgbtGreen := 0; si Gray + Alpha[SrcRGB.rgbtBlue]>0 entonces DestRGB.rgbtBlue := Min(255,Gray + Alpha[SrcRGB.rgbtBlue] ) más DestRGB.rgbtBlue := 0 Inc(SrcRGB); Inc(DestRGB); end;end; end;//procedimiento de ajuste RGB RGBChange(SrcBmp,DestBmp:TBitmap;RedChange,GreenChange,BlueChange:integer);var SrcRGB, DestRGB: pRGBTriple; = 0 a SrcBmp.Height- 1 comience SrcRGB := SrcBmp.ScanLine[i]; DestRGB :=DestBmp.ScanLine[i]; para j := 0 a SrcBmp.Width - 1 comience si RedChange> 0 entonces DestRGB.rgbtRed := Min(255, SrcRGB.rgbtRed + RedChange) de lo contrario DestRGB.rgbtRed := Max(0, SrcRGB.rgbtRed + RedChange); si GreenChange> 0 entonces DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + GreenChange) si no DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen + GreenChange); .rgbtAzul := Mín(255, SrcRGB.rgbtBlue + BlueChange) else DestRGB.rgbtBlue := Max(0, SrcRGB.rgbtBlue + BlueChange); Inc(SrcRGB Inc(DestRGB); fin;[Ajuste de color]//RGB<=>BGRprocedure); RGB2BGR(mapa de bits constante:TBitmap);var X: entero; Y: entero; pRGBTriple Color: Byte; comenzar para Y := 0 a (Bitmap.Height - 1) comenzar para X := 0 a (Bitmap.Width - 1) comenzar Color := PRGB^.rgbtRed : = PRGB^.rgbtBlue; PRGB^.rgbtBlue := Color; Inc(final PRGB); end;end;//Procedimiento en escala de grises (ponderado) Escala de grises(const Bitmap:TBitmap);var X: Entero Y: Entero: pRGBTriple;comenzar para Y := 0 a (Bitmap.Height - 1) comience PRGB := Bitmap.ScanLine[Y] para X := 0 a (Bitmap.Width - 1) comience Gray := (77 * Rojo + 151 * Verde + 28 * Azul) shr 8; PRGB^.rgbtRed:=Gris; PRGB^.rgbtGreen:=Gris; PRGB^.rgbtBlue:=Gris; fin; ;
Teoría:
Palabras clave:
Área de dibujo: es decir, el área donde la ventana muestra la imagen, que también puede ser la pantalla completa (el efecto de dibujo es mejor en la pantalla completa que en la ventana general)
Punto central: es decir, las coordenadas del punto central que se mostrarán en el área de dibujo en la imagen original (descargo de responsabilidad: este concepto es particularmente importante)
Primero hablemos de la ampliación de la imagen. Para ampliar una imagen, nuestro método general es ampliar la imagen directamente. Sin embargo, el método presentado en este artículo solo amplía la parte que podemos ver. después de la ampliación es más grande que el área de dibujo. Es aún más pequeño. No hay nada que decir en esta situación, por supuesto, se muestra todo. Imagen; el segundo es que la imagen ampliada es más grande que el área de dibujo. Este es el tema clave que vamos a discutir hoy. En este caso, primero debemos determinar el tamaño de la imagen ampliada y luego calcular el tamaño. imagen original según la posición y el tamaño del "punto central" y, finalmente, amplíe la imagen capturada al área de dibujo.
Hablemos de la itinerancia de imágenes. Cuando la imagen mostrada excede el área de dibujo, necesitamos recorrer la imagen para verla completa. El principio es: cuando el mouse hace clic en el área de dibujo, comienza a deambular, primero registra la posición del clic del mouse, luego detecta el movimiento del mouse y calcula el "punto central" según el mouse y el último desplazamiento ( las coordenadas de la pantalla deben convertirse a las coordenadas de la imagen original), saque la parte que se mostrará de la imagen original de acuerdo con el principio de ampliación anterior, amplíela y muéstrela en el área de dibujo.
Implementación del algoritmo:
1. Ampliación de imagen
Definición de variable:
PZoom: tasa de ampliación (entero: 100% cuando se usa 100, 100 se puede cambiar a 10000 o más según sea necesario, pero no se recomiendan números de punto flotante)
a, b: punto central
w, h: ancho y alto de la imagen original a capturar
x, y: la posición a interceptar (esquina superior izquierda)
sw,sh: ancho y alto de la imagen original
p1, p2: relación de aumento
aw,ah: el tamaño de la imagen ampliada
pw,ph: tamaño del área de dibujo
vx,vy: la posición que se muestra en el área de dibujo (esquina superior izquierda)
vw, vh: el tamaño que se muestra en el área de dibujo
ptx, pty: variables temporales
Variables conocidas: PZoom, (a, b), (sw, sh), (p1, p2), (aw, ah), (pw, ph)
Variables a calcular: (x,y),(w,h),(vx,vy),(vw,vh)
Comience a calcular:
aw=Round(PZoom*sw/100);ah=Round(PZoom*sh/100);p1=aw/pwp2=ah/ph// Nota: Round se usa para redondear, como Int(), Fix en otros idiomas () etc. si p1>1 entonces w=Round(sw/p1) más w=swif p2>1 entonces h=Round(sh/p2) más h=sh// Nota: shr es el operador de desplazamiento a la derecha, puedes usar ">>1", "div 2", "/2" o "Round(w/2)" en lugar de x=aw shr 1y=bh shr 1 // Nota: div es el operador de división de enteros ptx=(w*PZoom) div 100pty=(h*PZoom) div 100// Lo siguiente calcula el tamaño y la posición de la imagen mostrada en el área de dibujo.
variable
Pencent:double; // Relación de zoom wx:double; // Relación de zoom amplia hx:double; // Relación de zoom alta // Obtener relación de zoom wx:=pw/ptx hx:=ph/pty si wx>hx entonces Pencent: =hx else Pencent:=wx; // Obtener el tamaño final de la imagen vw:=Round(Pencent*ptx); vh:=Round(Pencent*pty); Calcula la posición de la imagen vx:=(pw-vw) div 2 vy:=(ph-vh) div 2;// --------------------; - ---------------
Bien, se han completado dos tareas importantes (x, y), (w, h), (vx, vy), (vw, vh). Se muestra el siguiente trabajo. Elegimos la API de Windows para realizar la operación.
variable
sDC es el identificador de dispositivo (DC) de la imagen original. tDC es el identificador de dispositivo temporal dDC y el identificador de dispositivo final BitBlt(tDC,0,0,w,h,sDC,0,0,SRCCOPY);SetStretchBltMode(dDC). ,STRETCH_DELETESCANS);StretchBlt(dDC,0,0,vw,vh,tDC,0,0,w,h,SRCCOPY);
Finalmente, dibuje en el área mostrada:
Por ejemplo:
BitBlt(GetDC(0),vx,vy,vx+vw,xy+vh,dDC,0,0,SRCCOPY);
2. Imagen itinerante
Primero defina tres variables globales:
FBeginDragPoint :TPoint; // Registra la posición donde el mouse comienza a arrastrar FBeginDragSBPoint :TPoint; // Registra la posición del "punto central" FBeginDrag :boolean // Si ha comenzado "arrastrar" a, b: integer; " Ubicación
Cuando se hace clic con el botón izquierdo del mouse, registre la posición del mouse y la posición del "punto central" y establezca FBeginDrag en verdadero.
Cuando aparezca el botón derecho del mouse, configure FBeginDrag en falso
Cuando se mueve el mouse, se juzga FBeginDrag. Si es falso, no se realizará ningún procesamiento. Si es verdadero, se realizará el siguiente procesamiento:
Supongamos que X e Y son la posición actual del mouse
a=FBeginDragPoint.X-((X-FBeginDragPoint.X)*100) div PZoomb=FBeginDragPoint.Y-((Y-FBeginDragPoint.Y)*100) div PZoom
Finalmente, use la imagen presentada arriba para ampliar y mostrar la imagen.
Consejos:
1. Si la imagen es grande, se producirá un error de desbordamiento de memoria al utilizar el objeto de mapa de bits de Delphi. En este caso, puede realizar las siguientes configuraciones:
bitImage:=TBitmap.Create; bitImage.PixelFormat:=pf24bit;ReleaseHandle;
2. Si desea que la imagen se adapte automáticamente al tamaño de la ventana, consulte el siguiente código:
var p1,p2 :double;begin p1:=pw/sw; p2:=ph/sw; si p1>p2 entonces PZoom:=Round(p2*100) else PZoom:=Round(p1*100); 0 entonces PZoom:=100;fin;
Procesamiento de brillo de color de píxeles de imagen en escala de grises de Delphi
En el procesamiento de imágenes, la velocidad es importante. Por lo tanto, tenemos que reprocesar TBitmap para obtener TVczhBitmap. Esto se debe simplemente a que GetPixels y SetPixels son demasiado lentos, simplemente use otro método.
unidad untBitmapProc; la interfaz utiliza gráficos, SysUtils; escriba TVczhBitmap=class(TBitmap) datos privados:PByteArray; procedimiento SetFormat; :Byte); función GetBytes(X,Y:Integer):Byte constructor publicado protegido Crear; propiedad pública Bytes[X,Y:Integer]:Byte leído GetBytes escribir SetBytes;procedimiento LoadFromFile(FileName:String);procedimiento ToGray;procedimiento de implementación TVczhBitmap.SetFormat; TVczhBitmap.GetBytePointer(X,Y:Integer):PByte comienza si Línea<>Y entonces; comenzar línea:=Y; datos:=ScanLine[Y]; fin; Longint(resultado):=Longint(Datos)+X; procedimiento TVczhBitmap.SetBytes(X,Y:Integer;Valor:Byte); X,Y)^:=Valor; fin; función TVczhBitmap.GetBytes(X,Y:Integer):Byte; resultado:=GetBytePointer(X,Y)^; fin; constructor TVczhBitmap.Create; comenzar a crear SetFormat heredado; ; Línea:=-1; fin; procedimiento TVczhBitmap.ToGray var X,Y,R:Integer; B:Byte; comenzar para Y:=0 a Alto-1 hacer para X:=0 a Ancho-1 comenzar R:=0 para B:=0 a 2 hacer R:=R+GetBytes(X*3+; B,Y); para B:=0 a 2, haga SetBytes(X*3+B,Y,R div 3 end);
Después de esto, necesitamos crear varios formularios. El primero se usa para mostrar imágenes y el segundo se usa para procesar imágenes. Todos los demás formularios heredan del segundo formulario y contienen los métodos de procesamiento reales.
Veamos primero la segunda ventana:
la interfaz untProc utiliza Windows, Mensajes, SysUtils, Variantes, Clases, Gráficos, Controles, Formularios, Diálogos, ExtCtrls, untBitmapProc, StdCtrls, ComCtrls tipo TfrmProcessor = class(TForm) pbBar: TPaintBox: TGroupBox; procedimiento FormCreate(Remitente: TObject); procedimiento FormDestroy(Remitente: TObject); procedimiento FormShow(Remitente: TObject); procedimiento pbBarPaint(Remitente: TObject); procedimiento Button1Click(Remitente: TObject); privado {Declaraciones privadas} público {Declaraciones públicas} BarData:array[0] ..255]de Byte; Bar:TVczhBitmap; procedimiento DrawBar; fin; implementación {$R *.dfm} usa untViewer; procedimiento TfrmProcessor.DrawBar; var I:Integer; comenzar Bar.Canvas.FillRect(Bar.Canvas.ClipRect); I:=1 a 255 hacer Bar.Canvas.LineTo(I,255-BarData[I]); TfrmProcessor.FormCreate(Remitente: TObject); barra de inicio:=TVczhBitmap.Create; Bar.Width:=256; Bar.Height:=256; =bsSolid; finalizar; procedimiento TfrmProcessor.FormDestroy(Remitente: TObject comenzar Bar.Free); finalizar; procedimiento TfrmProcessor.FormShow(Remitente: TObject); var I:Integer; comenzar para I:=0 a 255 hacer BarData[I]:=I; procedimiento TfrmProcessor.pbBarPaint(Remitente: TObject); .Canvas.Draw(0,0,Bar); fin; procedimiento TfrmProcessor.Button1Click(Remitente: TObject); var X,Y:Integer; comenzar para Y:=0 a Buffer.Height-1 hacer para X:=0 a Buffer.Width*3-1 hacer Played.Bytes[X,Y]:=BarData[Buffer.Bytes[ X,Y]]; frmViewer.FormPaint(frmViewer); fin.
Después de eso, cree una ventana que herede de ella, luego ajuste BarData[] y presione Aplicar para ver el resultado.
Ahora comience a procesar la imagen. Consulte el programa de muestra para efectos específicos.
1. Inversión de color.
Los colores de las imágenes en escala de grises varían de 0 a 255, por lo que para invertir el color, podemos restar el valor del color de 255 para obtener el color invertido.
var I:Integer; comienza heredado; para I:=0 a 255 do BarData[I]:=255-I;// Resta el valor del color de 255 DrawBar;
2. Reduce la gama de colores para realzar o debilitar el brillo.
El color es originalmente de 0~255. Si ajusta su rango, por ejemplo de 0 a 16, la imagen será significativamente más oscura. Podemos establecer el valor inicial en a y el valor final en b, luego el nuevo valor de color Nuevo=a+(b-1)*Antiguo/255. Hacer esto cambia el brillo sin destruir la secuencia de colores original. El código es el siguiente.
var I:Integer; comenzar para I:=0 a 255 hacer BarData[I]:=(255-sbMin.Position)+Round((sbMin.Position-sbMax.Position)/255*I); ); Botón1Haga clic (Botón1);
Aquí, sbMin.Position y sbMaxPosition están invertidos. Por lo tanto, usa 255 para restar
3. Aumentar la gama de colores dentro de un rango determinado.
Si la imagen en sí tiene una gama de colores pequeña, puede utilizar este método para aumentar el contraste de la imagen, lo que resulta beneficioso para el análisis de la imagen. Métodos específicos:
Seleccione un valor a como valor inicial, seleccione un valor b como valor final y luego deforme de acuerdo con la siguiente fórmula:
| 0 (X<=a)
f(X)= | 255/(ba)*(Xa)
255(X>=b)
var I:Integer; comenzar para I:=0 a 255 comenzar si I<=sbMin.Position luego BarData[I]:=0 si no I>=sbMax.Position entonces BarData[I]:=255 else BarData[I ]:=Round(255/(sbMax.Position-sbMin.Position)*(I-sbMin.Position end; pbBarPaint(pbBar); Botón1Clic(Botón1);
4. Convertir a imágenes en blanco y negro
Al utilizar la tercera función, encontrará que cuando b <= a, los colores de la imagen son blancos excepto el negro. Los beneficios de esta operación no se pueden mostrar directamente. Esto sólo será efectivo cuando se trate de procesamiento de imágenes más avanzado, como la detección de bordes. Este ejemplo se puede transformar utilizando la fórmula del tercer método, por lo que no se detallará.
5. Ajuste de brillo exponencial
Suponemos que el dominio de este gráfico es [0,1] y el rango de valores también es [0,1]. Luego, defina la función f(x)=x^c, entonces la imagen de f(x) tiene una sección como se muestra arriba. Cuando usamos el mouse para operar nuevamente, podemos tomar un punto P (a, b) en él y luego hacer que f (x) pase por el punto P, luego c = ln (b)/ln (a). Con C, podemos operar en color:
Nuevo = (Old/255)^C*255 = exp (Ln (Old/255)*C)*255 Var EA, EB, EC: Extendido; /255; Bardata [i]: = Exp (Ln ((I/255))*EC)*255);
Hacer esto ajusta el brillo de la imagen.
Consejos para mostrar efectos especiales en gráficos de Delphi
Descripción general
---- En la actualidad, en muchos software de aprendizaje y CD de juego, a menudo puedes ver varios
La tecnología de visualización gráfica se basa en el movimiento, la entrelazamiento, la forma de la gota de lluvia, las persianas, el apilamiento de bloques de construcción y otros métodos de gráficos para hacer que la imagen sea más animada y más atractiva para la audiencia. Este artículo explorará cómo implementar varias técnicas de visualización gráfica en Delphi.
Principios básicos
---- En Delphi, es muy simple mostrar una imagen. y el archivo seleccionado se mostrará en el componente de tiempo. Pero esto solo muestra los gráficos directamente en el formulario, y no hay habilidad en absoluto. Para que la pantalla gráfica tenga un efecto único, puede seguir los siguientes pasos:
---- Defina un componente de tiempo y cargue los gráficos que se mostrarán primero en el componente de tiempo, es decir, cargue el contenido de gráficos desde el disco en la memoria como un caché de gráficos.
---- Cree un nuevo objeto de mapa de bits con el mismo tamaño que los gráficos en el componente de tiempo.
---- use la función de copirrector de lienzo (copie el área rectangular de un lienzo al área rectangular de otro lienzo), use técnicas y forma dinámica
Convierta el contenido del archivo en un mapa de bits y luego muestre el mapa de bits en el formulario.
---- Método de implementación
A continuación se introducen varias técnicas de visualización gráfica:
1.Exto-empuje-pull
Tire de los gráficos para que se muestren en la pantalla desde arriba, hacia abajo, la izquierda y las direcciones correctas, y al mismo tiempo cubrir los gráficos antiguos originales en la pantalla. Tire a la izquierda y tire a la derecha.
Principio: Primero, mueva la primera línea horizontal en el gráfico temporal al último en el mapa de bits que se mostrará, y luego mueva las dos primeras líneas horizontales en el gráfico temporal a los últimos dos mapas de bits que se mostrarán. Mueva las primeras tres y cuatro líneas hasta que se muevan todos los datos gráficos. Durante el proceso de mudanza, puede ver que los flotadores de mapa de bits mostrados de abajo hacia arriba, logrando un efecto pull-up.
Algoritmo del programa:
Procedimiento TForm1.Button1Click (remitente: Tobject); : = image1.Height; i: = 0 a bmpheight Do Comenzar newbmp.canvas.copyrect (Rect (0, Bmpheight-I, BmpWidth, Bmpheight), Image1.Canvas, Rect (0,0, Bmpwidth, I)); , NewBMP);
2. Efecto escalonado vertical
Principio: divida los gráficos que se mostrarán en dos partes. Desde la pantalla, puede ver que los gráficos más ligeros que aparecen en los extremos superior e inferior se mueven hacia el centro de la pantalla hasta que estén completamente claros.
Algoritmo del programa:
Procedimiento tform1.Button4Click (remitente: tobject); ; i: = 0; bmpheight-i+j-1, bmpwidth, bmpheight-i+j)); (0, bmpheight-j, bmpwidth, bmpheight-j+1), image1.canvas, rect (0, ij, bmpwidth, i-j+1)); (120,100, Newbmp);
3. Efecto escalonado horizontal
Principio: El mismo principio que el efecto entrelazado vertical, excepto que los gráficos divididos en dos grupos se mueven a la pantalla desde los extremos izquierdo y derecho, respectivamente.
Algoritmo del programa:
Procedimiento TForm1.Button5Click (remitente: Tobject); ; i: = 0; i+j-1,0, bmpwidth-i+j, bmpheight)); (bmpwidth-j, 0, bmpwidth-j+1, bmpheight), imagen1.canvas, rect (ij, 0, i-j+1, bmpheight)); (120,100, Newbmp);
4. Efecto de gota de lluvia
Principio: Mueva la última línea de escaneo de los gráficos temporales al primero a la última línea de escaneo de la mapa de bits visible en secuencia, lo que permite que esta línea de escaneo deje su rastreo en la pantalla. Luego, la penúltima línea de escaneo de los gráficos temporales se mueve al primero a las penúltimas líneas de escaneo de la mapa de bits visible en secuencia. Y así sucesivamente para las líneas de escaneo restantes.
Algoritmo del programa:
Procedimiento tform1.Button3Chick (remitente: tobject); ; para i: = bmpheight downto 1 do para j: = 1 para comenzar newbmp.canvas.copyrect (rect (0, j-1, bmpwidth, j), image1.canvas, rect (0, i-1, bmpwidth,, i))
5. Efecto de los de los Luuvres
Principio: Divida los datos colocados en los gráficos temporales en varios grupos y luego muévalos secuencialmente del primer grupo al último grupo. El tiempo mueve la segunda línea de escaneo, luego mueva las líneas de escaneo tercera y cuarta.
Algoritmo del programa:
Procedimiento TForm1.Button6Chick (remitente: Tobject); altura: = imagen1.Height; bmpwidth: = image1.width; -1, bmpwidth, xcount*j+i), image1.canvas, rect (0, xCount*J+I-1, BMPWIDTH, XCOUNT*J+I));
6. Efecto de bloques de construcción
Principio: Es una variación del efecto de gota de lluvia.
Algoritmo del programa:
Procedimiento TForm1.Button7Chick (remitente: Tobject); ; i: = bmpheight; , bmpwidth, i); fin;
Conclusión
Todos los efectos de visualización gráfica anterior se han pasado en la máquina. Funciona muy bien.
Implementación de la lupa de imagen usando Delphi
Agregue dos componentes de tiempo al formulario. Otro componente de tiempo tiene su propiedad de nombre establecida en Image2, que muestra la imagen ampliada.
El núcleo de este ejemplo es la función de estiramiento.
Procedimiento tForm1.Image1MouseMove (remitente: tobject; shift: tshiftState; x, y: integer); comienza estiramiento (image2.canvas.handle, 0,0, image2.width, image2.height, image1.canvas.handle, y- 20,40,40, srccopy); Screen.cursors [1]: = loadCursorFromFile ('Magnify.cur');
El programa primero llamará a la función Stretchblt, usará la posición actual del mouse como punto central, seleccione la imagen parcial en el componente Image1 con una longitud lateral de 40 y amplíe la imagen parcial al componente Image2. Luego, actualice la visualización del componente Image2 llamando al método de actualización del componente Image2. Finalmente, configure el puntero del mouse en la nueva forma.
El código del programa es el siguiente:
Unidad de la unidad1; InterfaceUsWindows, mensajes, sysutils, variantes, clases, gráficos, controles, formularios, diálogos, extcTrls, stdctrls; type tform1 = class (tform) image1: winter2: wimage; ; FormMouseMove (remitente: tobject; shift: tshiftState ;; shift: tshiftState; x, y: entero); BeginStretchBlt (Image2.Canvas.Handle, 0,0, Image2.Width, Image2.Height, Image1.Canvas.Handle, X-20, Y-20,40,40, SrcCopy); ]: = LoadCursorFromFile ('Magnify.cur'); Self.cursor: = 1; end; procedimiento tform1.FormMouseMove (remitente: tobject; shift: tshiftState; x, y: entero); comenzar pantalla. .
Guarde el archivo y luego presione la tecla F9 para ejecutar el programa y el programa se ejecutará.
Las imágenes de aumento es una función esencial de un excelente software de visualización de imágenes.
Espero que este artículo sea útil para la programación Delphi de todos.