Einzelnen Beitrag anzeigen

Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
737 Beiträge
 
Delphi 11 Alexandria
 
#12

AW: Zwei transparente Bitmaps miteinader verrechnen

  Alt 4. Jun 2017, 19:41
Hallo Harry

die Formel darf dich nicht abschrecken. Du musst eigentlich nur zwei Dinge tun für jedes Pixel:

1. Den neuen Alphawert berechnen
2. Die neuen Farbwerte für R,G,B.

Ich hab's rasch getan und das Resultat sieht wirklich gut aus.

In diesem Beispiel siehst du, wie du es für zwei gleich grosse Bitmaps A, B tun kannst, welche direkt übereinander gelegt werden.
( Du willst dann natürlich Code schreiben für A an Position x, y über B legen oder ähnlich. )

Delphi-Quellcode:
procedure AueberB( a, b, c : TBitMap );

var lineA, lineB, lineC : PRGB32Array;
    x, y : integer;
    alphaA, alphaB, alphaC : extended;
begin
  a.PixelFormat := pf32Bit;
  b.PixelFormat := pf32Bit;
  c.PixelFormat := pf32bit;

  for y := 0 to a.Height-1 do
  begin
    lineA := a.ScanLine[y];
    lineB := b.ScanLine[y];
    lineC := c.ScanLine[y];

    for x := 0 to a.Width-1 do
    begin
       // Test
      (* lineA[x].A := 255;
      lineB[x].A := 0; *)

      alphaA := lineA[x].A/255;
      alphaB := lineB[x].A/255;
      // 0 = Transparent - 1 = instransparent
      alphaC := alphaA + ( 1 - alphaA )*alphaB; // (den Fall alphaA=0 UND alphaB=0 musst du hier noch sep. behandeln)
      lineC[x].A := round(alphaC*255);
      lineC[x].R := round(1/alphaC*(alphaA*lineA[x].R + (1-alphaA)*alphaB*lineB[x].R ));
      lineC[x].G := round(1/alphaC*(alphaA*lineA[x].G + (1-alphaA)*alphaB*lineB[x].G ));
      lineC[x].B := round(1/alphaC*(alphaA*lineA[x].B + (1-alphaA)*alphaB*lineB[x].B ));
    end;
  end;

end;

Testen:
So rufe ich die Prozedur auf:
Ich lade in diesem Beispiel in A und B das gleiche Bild, in A um 10,10 versetzt.
Ins Bild A schreibe ich den Buchstaben 'A' rein, ins Bild B den Buchstaben 'B'. (Damit sehe ich im Resultatbild C in etwa, wie A und B zum Resultat C beitragen.)

In der Prozedur AueberB (siehe Code oben) habe ich zwei Zeilen
lineA[x].A := 255;
lineB[x].A := 0;
"auskommentiert". Dort kannst du globale Alpha-Werte setzen und sehen, wie sich diese Werte aufs Resultatbitmap C auswirken.


Delphi-Quellcode:
procedure TForm100.Button1Click(Sender: TObject);
var a,b,c : TBitMap;
begin
  a := TBitMap.Create;
  b := TBitMap.Create;
  c := TBitMap.Create;

  a.LoadFromFile( 'C:\Users\Michael\Desktop\thun.bmp' );
  b.LoadFromFile( 'C:\Users\Michael\Desktop\thun.bmp' );
  a.Canvas.Draw( 10,10,b );

  a.Canvas.Font.Size := 100;
  a.Canvas.TextOut( 10,10, 'A' );
  b.Canvas.Font.Size := 100;
  b.Canvas.TextOut( 10,210, 'B' );
  c.SetSize( a.Width, a.Height );

  AueberB( a, b, c );

  c.SaveToFile( 'C:\Users\Michael\Desktop\thun2.bmp');

  a.Free;
  b.Free;
  c.Free;
end;

Natürlich kann man die ganze Sache auch in den "Integer Bereich" verlegen. Bei modernen Prozessoren gewinnt man aber (leider ) häufig gar nicht mehr viel Zeit; auf älteren Kisten jedoch sehr...
Michael Gasser

Geändert von Michael II ( 4. Jun 2017 um 20:41 Uhr)
  Mit Zitat antworten Zitat