AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Efectos con Scanline

Ein Thema von DP News-Robot · begonnen am 19. Jun 2020
Antwort Antwort
Benutzerbild von DP News-Robot
DP News-Robot

Registriert seit: 4. Jun 2010
15.392 Beiträge
 
#1

Efectos con Scanline

  Alt 19. Jun 2020, 00:40


Tbitmap.scanline es una propiedad indexada de solo lectura que devuelve un puntero a una fila de pixeles de un bitmap.
Es la forma más rápida de acceder a los píxeles de una imagen y esto depende del formato del mapa de bits que se indica desde la propiedad Pixelformat de la unit Graphics.

TPixelFormat = (pfDevice, pf1bit, pf4bit, pf8bit, pf15bit, pf16bit, pf24bit, pf32bit, pfCustom);

Ejemplo de carga un bitmap:

VAR
bmp: tbitmap;
BEGIN
bmp := tbitmap.Create;
TRY
IF OpenDialog1.Execute THEN
BEGIN
bmp.LoadFromFile(OpenDialog1.FileName);
bmp.PixelFormat := pf24bit;
Invalidate; { Mostrar la imagen }
END;
FINALLY
bmp.Free;
END;
END;

Cuando creamos un mapa de bits cada pixel se inicializa al máximo valor, es decir a 255 por eso el mapa de bits es blanco, ese el formato de pixel predeterminado.
Un pixel en un mapa de bits de 24 bits se describe con 3 valores rojo, verde y azul, que se almacenan en la memoria en orden inverso: azul, verde y rojo.
El puntero a la matriz de bytes que hace scanline se vería de la siguiente forma:




Para obtener el resultado anterior hay que asignar el resultado de Scanline a un puntero de bytes: pByteArray

VAR
p: PByteArray;
BEGIN
p := FImage.ScanLine[0];
END;

Por ejemplo para poner el primer pixel de de la primera fila de la imagen de color negro y el segundo de color blanco habría que hacer:


VAR
p: PByteArray;
BEGIN
p := FImage.ScanLine[0]; { lee la primera fila }
p[0] := 0; { primer pixel de color negro }
p[1] := 0;
p[2] := 0;
p[3] := 255; { segundo pixel de color blanco }
p[4] := 255;
p[5] := 255;
Invalidate;
END;


También podemos usar la siguiente estructura:

type
TRGBTriple = packed record
rgbtBlue: Byte;
rgbtGreen: Byte;
rgbtRed: Byte;
end;

Para conseguir que la segunda fila del bitmap sea de color negro:

type
PRGBTripleArray = ^TRGBTripleArray;
TRGBTripleArray = array[0..4095] of TRGBTriple;

procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
Bitmap: TBitmap;
Pixels: PRGBTripleArray;
begin
Bitmap := TBitmap.Create;
try
Bitmap.Width := 3;
Bitmap.Height := 2;
Bitmap.PixelFormat := pf24bit;
// get pointer to the second row's raw data
Pixels := Bitmap.ScanLine[1];
// iterate our row pixel data array in a whole width
for I := 0 to Bitmap.Width - 1 do
begin
Pixels[I].rgbtBlue := 0;
Pixels[I].rgbtGreen := 0;
Pixels[I].rgbtRed := 0;
end;
Bitmap.SaveToFile('c:\Image.bmp');
finally
Bitmap.Free;
end;
end; De lo anterior podemos observar que el primer pixel del bitmap se encuentra en el offset 0 de la primera fila, el segundo en el offset 3, el tercero en el offset 6 esto quiere decir que el byte en la ubicación x*3 es el componente azul, el byte de la ubicación x*3+1 es el componente verde y el x*3+2 es el rojo.
Entonces si quisiéramos poner una imagen en color negro habría que hacer lo siguiente:

VAR
p: PByteArray;
x: Integer;
y: Integer;
BEGIN { Iterar entre todas las líneas}
FOR y := 0 TO Pred(FImage.Height) DO
BEGIN
p := FImage.ScanLine[y];
FOR x := 0 TO Pred(FImage.Width) DO
BEGIN
p[x * 3] := 0;
p[x * 3 + 1] := 0;
p[x * 3 + 2] := 0;
END;
END;
END; Ahora vamos a profundizar un poco más en este aspecto, hemos visto que cambiando los valores de los bytes de un pixel podemos conseguir los diferentes tipos de colores y si vamos un poco más allá conseguiremos espectaculares efectos visuales como los siguientes:

- Solarize

VAR
p: PByteArray;
x: Integer;
y: Integer;
BEGIN
FOR y := 0 TO Pred(FImage.Height) DO
BEGIN
p := FImage.ScanLine[y];
FOR x := 0 TO Pred(FImage.Width) DO
BEGIN
IF p[x * 3] > 127 THEN
p[x * 3] := 255 - p[x * 3];
IF p[x * 3 + 1] > 127 THEN
p[x * 3 + 1] := 255 - p[x * 3 + 1];
IF p[x * 3 + 2] > 127 THEN
p[x * 3 + 2] := 255 - p[x * 3 + 2];
END;
END;
END;

- Invertir colores

VAR
p: PByteArray;
x: Integer;
y: Integer;
BEGIN
FOR y := 0 TO Pred(FImage.Height) DO
BEGIN { get the pointer to the y line }
p := FImage.ScanLine[y];
FOR x := 0 TO Pred(FImage.Width) DO
BEGIN { modificar el color azul }
p[x * 3] := 255 - p[x * 3]; { modificar el color verde }
p[x * 3 + 1] := 255 - p[x * 3 + 1]; { modificar el color rojo }
p[x * 3 + 2] := 255 - p[x * 3 + 2];
END;
END;
END;

- Convertir a escala de grises

Se hace con la siguiente fórmula
Gray = (Red * 3 + Blue * 4 + Green * 2) div 9

VAR
p: PMyPixelArray;
x: Integer;
y: Integer;
gray: Integer;
BEGIN
FOR y := 0 TO Pred(FImage.Height) DO
BEGIN
p := FImage.ScanLine[y];
FOR x := 0 TO Pred(FImage.Width) DO
WITH p[x] DO
BEGIN
gray := (Red * 3 + Blue * 4 + Green * 2) DIV 9;
Blue := gray;
Red := gray;
Green := gray;
END;
END;
END;


- Hacer un espejo vertical

procedure TForm1.Button1Click(Sender: TObject);

procedure EspejoVertical(Origen,Destino:TBitmap);
var
x,y : integer;
Alto : integer;
Po,Pd : PByteArray;
tmpBMP : TBitmap;
LongScan : integer;
begin
{Si es un modo raro... pasamos}
case Origen.PixelFormat of
pfDevice,
pfCustom:
Raise exception.create( 'Formato no soportado'+#13+
'Bitmap Format not valid');
end;

{Calculamos variables intermedias}
Alto :=Image1.Picture.Bitmap.Height-1;
try
{Calculo de cuánto ocupa un scan}
LongScan:= Abs( Integer(Origen.ScanLine[0])-
Integer(Origen.ScanLine[1]) );
except
Raise exception.create( 'ScanLine Error...');
end;

{Cremos un bitmap intermedio}
tmpBMP:=TBitmap.Create;
with tmpBMP do
begin
{Lo asignamos, así se copia la paleta si la hay}
Assign(Origen);
{Esto es para que sea un bitmap nuevo... es un bug de D3 y D4}
Canvas.Pixels[0,0]:=Origen.Canvas.Pixels[0,0];
end;

{Damos la vuelta al bitmap}
for y:=0 to Alto do
begin
Po := Origen.ScanLine[y];
Pd := tmpBMP.ScanLine[Alto-y];
for x := 0 to LongScan-1 do
begin
Pd^[X]:=Po^[X];
end;
end;
{Lo asignamos al bitmap destino}
Destino.Assign(tmpBMP);
{Esto es para parchear un bug de Delphi 3 y Delphi4...}
Destino.Canvas.Pixels[0,0]:=tmpBMP.Canvas.Pixels[0,0];
tmpBMP.Free;
end;
begin
EspejoVertical( Image1.Picture.Bitmap,
Image1.Picture.Bitmap);
Image1.Refresh;
end;


- Ajustar el brillo

Se hace con la siguiente fórmula:
NewPixel = OldPixel + (1 * Percent) div 200

FUNCTION IntToByte(AInteger: Integer): Byte; INLINE;
BEGIN
IF AInteger > 255 THEN
Result := 255
ELSE IF AInteger < 0 THEN
Result := 0
ELSE
Result := AInteger;
END;

PROCEDURE TMainForm.AdjustBrightness(Percent: Integer);
VAR
p: PMyPixelArray;
x: Integer;
y: Integer;
amount: Integer;
BEGIN
amount := (255 * Percent) DIV 200;
FOR y := 0 TO Pred(FImage.Height) DO
BEGIN
p := FImage.ScanLine[y];
FOR x := 0 TO Pred(FImage.Width) DO
WITH p[x] DO
BEGIN
Blue := IntToByte(Blue + amount);
Green := IntToByte(Green + amount);
Red := IntToByte(Red + amount);
END;
END;
Invalidate;
END;

PROCEDURE TMainForm.ScanLineBrightnessClick(Sender: TObject);
VAR
amount: Integer;
BEGIN
amount := StrToInt(InputBox('Brightness Level', 'Enter a value from -100 to 100:', '50'));
AdjustBrightness(amount);
END;Suscribirse :



Weiterlesen...
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:56 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz