Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi zwei Bitmaps vergleichen (https://www.delphipraxis.net/147071-zwei-bitmaps-vergleichen.html)

KahPee 1. Feb 2010 13:00


zwei Bitmaps vergleichen
 
Hallo,
ich hatte so eine ähnliche Frage schon mal gestellt, allerdings bin ich bei der Umsetzung damals gescheitert.
Ich habe vor zwei Bitmaps zu vergleichen.
Ich hatte bei meinem ersten Versuch vorallem Probleme mit den konvertieren und ähnlichem. Aber nochmal zu dem Problem:
1. Die beiden Bitmaps haben unterschiedliche größen (Bild1 ist sowohl in y als auch in x Richtung "größer gleich" Bild2)
2. Es soll geprüft werden ob Bild 2 an einer bestimmten Stelle von Bild1 ist
3. Ergebnis soll true/false sein

Im Prinzip stelle ich mir also so etwas vor:
Delphi-Quellcode:
function compareBitmaps(Bild1, Bild2: TBitmap; posx,posy: Integer):boolean;
  //Posx und Posy sollen angeben an welcher Stellen von Bild1 Bild2 verglichen werden wollen (obere linke Ecke)
var x,
    y,
    comparedpix,             //Anzahl der verglichenen Pixel
    machtingpix: integer;    //Anzahl der übereinstimmenden Pixel
   
begin
  Result:=false;

  for x:=0 to Bild2.width-1 do
  begin
    for y:=0 to Bild2.height-1 do
    begin
      if Bild1.Pixels[posx+x,posy+y]=Bild2.Pixels[x,y] then matchingpix:=matchingpix+1;
             //Problem: keine "Pixels" Option für Tbitmaps nur für TCanvas
      comparedpix:=comparedpix+1;
    end;
  end;
 
  if comparedpix=matchingpix then result:=true;

end
Ich hoffe obiger Sketch des Programmcodes kann einen Eindruck vermitteln was ich vor habe. Ich suche auch immer noch eine etwas schnellere Methode. Scanline fällt in diesem Fall weg (???) weil ich ja nur einen Auschnitt vergleichen will.

Wäre nett wenn mir jemand auf die Sprünge helfen könnte ;)

mfg Kahpee

thepaine91 1. Feb 2010 13:08

Re: zwei Bitmaps vergleichen
 
Nein Scanline ist genau richtig. Tipp: Schau dir mal das Return Value an. ;)
Das Beispiel in der Delphi Hilfe zu Scanline kann dir auch weiterhelfen.

KahPee 1. Feb 2010 13:26

Re: zwei Bitmaps vergleichen
 
In meiner Hilfe (TurboDelphi "f1") sieht das seeehr mager aus.
Zitat:

Syntax
Delphi-Quellcode:
 property ScanLine: Pointer read GetScanline;
Beschreibung
ScanLine wird nur bei DIBs (Device Independent Bitmaps) für Bildbearbeitungsprogramme verwendet, die Low-Level-Operationen auf Pixelebene durchführen.
Da komm ich nicht mit weiter. :(
Hast du vllt einen Link oder so? Auch ist mir noch nicht unklar wie ich bei ScanLine einen bestimmten Punkt in Bild1 angebe ab dem verglichen werden soll ...

thepaine91 1. Feb 2010 13:33

Re: zwei Bitmaps vergleichen
 
Das zeigt mir Delphi als Beispiel. Hoffe das hilft dir weiter. ;)

property ScanLine[Row: Integer]: Pointer;

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);

// Dieses Beispiel zeigt das direkte Zeichnen in das Bitmap
var
  x,y : Integer;
  BitMap : TBitMap;
  P : PByteArray;
begin
  BitMap := TBitMap.create;
  try
    BitMap.LoadFromFile('C:\Programme\Gemeinsame Dateien\Borland Shared\Images\Splash\256color\factory.bmp');
    for y := 0 to BitMap.Height -1 do
    begin
      P := BitMap.ScanLine[y];
      for x := 0 to BitMap.Width -1 do

        P[x] := y;
    end;
    Canvas.Draw(0,0,BitMap);
  finally
    BitMap.Free;
  end;
end;

KahPee 1. Feb 2010 13:41

Re: zwei Bitmaps vergleichen
 
ehm ja... Ich bin glaube ich zusehr Delphi Laie als das da zu sehen :(...

wie ich die jeweils richtige Zeile auslese hab ich glaube ich schon kappiert:
Delphi-Quellcode:
  if Bild1.scanline[posy+y]=Bild2.Pixels[y] then matchingpix:=matchingpix+1;
Allerdings wird in diesem Fall von Bild 1 die ganze Zeile gescannt. das will ich ja gar nicht :o . Ich möchte, dass ja nur ein bestimmter Teil des 1. Bildes gescannt wird. Wie krieg ich denn da jetzt eine Kontrolle über die gescannten und am Ende auch verglichenen Längen und Positionen der Zeilen?

mfg KahPee

thepaine91 1. Feb 2010 13:50

Re: zwei Bitmaps vergleichen
 
:wall: Das ganze nochmal kommentiert.

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);

// Dieses Beispiel zeigt das direkte Zeichnen in das Bitmap
var
  x,y : Integer;
  BitMap : TBitMap;
  P : PByteArray;
begin
  BitMap := TBitMap.create;
  try
    BitMap.LoadFromFile('C:\Programme\Gemeinsame Dateien\Borland Shared\Images\Splash\256color\factory.bmp');
    for y := 0 to BitMap.Height -1 do
    begin
      P := BitMap.ScanLine[y]; // Füllt einen Array of Byte mit den Daten der angegebenen Zeile.
      for x := 0 to BitMap.Width -1 do
        // P = length Bitmap.width -1
// Wenn man jetzt row 1 ausliest und P unser Bytearray ist und dem zu folge P[1] ausliest hätte man das selbe wie Pixels[1,1]
        P[x] := y;
    end;
    Canvas.Draw(0,0,BitMap);
  finally
    BitMap.Free;
  end;
end;
Jetzt soweit verständlich :coder2:

KahPee 1. Feb 2010 13:54

Re: zwei Bitmaps vergleichen
 
Oh.. Das war einfach VIELEN DANK!!

Noch eine ganz kurze Frage. Bei der aktuellen Prozedur wird in dem größeren Bild (Bild1) die ganze Zeil gescannt und anschließend wird nur an einer bestimmten Stelle verglichen. Kann man von vorneherein angeben, dass nur ein teil der Zeil gescannt werden soll um rechenzeit zu sparen?
Ich gehe mal davon aus, dass der array mit "0" anfängt ;)

mdf Kahpee

Aphton 1. Feb 2010 14:13

Re: zwei Bitmaps vergleichen
 
Zitat:

Zitat von thepaine91
:wall: Das ganze nochmal kommentiert.

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);

// Dieses Beispiel zeigt das direkte Zeichnen in das Bitmap
var
  x,y : Integer;
  BitMap : TBitMap;
  P : PByteArray;
begin
  BitMap := TBitMap.create;
  try
    BitMap.LoadFromFile('C:\Programme\Gemeinsame Dateien\Borland Shared\Images\Splash\256color\factory.bmp');
    for y := 0 to BitMap.Height -1 do
    begin
      P := BitMap.ScanLine[y]; // Füllt einen Array of Byte mit den Daten der angegebenen Zeile.
      for x := 0 to BitMap.Width -1 do
        // P = length Bitmap.width -1
// Wenn man jetzt row 1 ausliest und P unser Bytearray ist und dem zu folge P[1] ausliest hätte man das selbe wie Pixels[1,1]
        P[x] := y;
    end;
    Canvas.Draw(0,0,BitMap);
  finally
    BitMap.Free;
  end;
end;
Jetzt soweit verständlich :coder2:

:wall: Das ganze nochmal verbessert

Du weißt schon, dass das so nicht korrekt ist?
Es gibt soetwas, dass nennt sich Pixelformat. Falls es beispielsweise auf pf24Bit gesetzt ist,
besteht das Bild (bzw dann die einzelnen Rows) aus aneinander gereihten 24/8 Bytes -> r, g, b; wobei die Reihenfolge nicht die gleiche sein muss...

Sieh dir das hier mal an:
Delphi-Quellcode:
var
  Pixel  : PByte;
  y, k, x : Integer;
  bytes  : Byte;
const
  PixelFormatBytes: Array[TPixelFormat] of Byte = ( 0, 0, 0, 1, 0, 2, 3, 4, 0 );
begin
  bytes := PixelFormatBytes[bmp.PixelFormat];
  if bytes = 0 then
    Exit; // PixelFormat wird nicht unterstützt ... kannst du dann gerne von mir aus umändern ...
  for y := 0 to bmp.Height - 1 do
  begin
    Pixel := bmp.Scanline[y];
    for x := 0 to bmp.Width - 1 do
      for k := 0 to bytes - 1 do
      begin
        Pixel^ := 0;
        inc( Pixel );
      end;
  end;
end;

KahPee 1. Feb 2010 14:16

Re: zwei Bitmaps vergleichen
 
Delphi-Quellcode:
function Bitmapcompare(pic1, pic2: Tbitmap; Posx,posy: Integer): Boolean;
var line1,line2: Pbytearray;
    x,y: integer;
    compix, matchpix: integer;
begin
  Result:=false;
  matchpix:=0;
  compix:=0;

  for y := 0 to pic2.Height - 1 do
  begin
    line1:=pic1.ScanLine[posy+y];
    line2:=pic2.ScanLine[y];
    for x := 0 to pic2.width - 1 do
      begin
        if line1[posx+x]=line2[x] then matchpix:=matchpix+1;
        compix:=compix+1;
      end;
  end;

  if compix=matchpix then Result:=true;

end;
Der Code macht seine Sache gut ;). Vielen Dank habs grad ausprobiert und der erste Test verlief erfolgreich :P

mfg KahPee

thepaine91 1. Feb 2010 14:20

Re: zwei Bitmaps vergleichen
 
Nein weis ich nicht weil ich mich noch nie mit TBitmap befasst hatte vorher ich hab nur 2 min die Hilfe durchgeguckt ob ich was finde. ;)
Und da habe ich das wohl übersehen.

Aphton 1. Feb 2010 14:49

Re: zwei Bitmaps vergleichen
 
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:

Zitat von KahPee
Der Code macht seine Sache gut ;). Vielen Dank habs grad ausprobiert und der erste Test verlief erfolgreich :P

mfg KahPee

Ich möchte dich hiermit herzlichst darauf hinweisen - das wird es nicht lange... Siehe dazu Bild im Anhang.
Die Bilder in der Mitte und Rechts wurden durch die beiden Routinen (Algorithmen) gejagt.
Bei der Linken (Mittleren) sieht man schön dass nicht alle Pixel "angetastet" (schwarz gesetzt) werden, wohingegen die korrigierte Routine auch wirklich alle Pixel abtastet.

Edit:
Ich habe eine kleine ScanlineBitmap Unit angehangen. Mit TScanlineBitmap.Pixel[] bist du schneller dran, da es per Scanline arbeitet.

MfG

KahPee 1. Feb 2010 16:02

Re: zwei Bitmaps vergleichen
 
Mh jetzt versteh ich schon wieder nur Bahnhof :P. Hatte mich gerade gefreut, dass das ganze so einfach lief :D

Also gut. Man vergleiche deinen und meinen Teil, da fällt auf, dass

Delphi-Quellcode:
//eine Abfrage dazukommt
bytes := PixelFormatBytes[bmp.PixelFormat];
  if bytes = 0 then
    Exit;

//das hier anstelle des meines Vergleiches steht
for k := 0 to bytes - 1 do
      begin
        Pixel^ := 0; //Zeiger??
        inc( Pixel ); //inc??
 //hier müsste der Vergleich der Pixel hin?!
       end;
Leider hab ich keine Ahnung von Zeigern und dem "inc()" kram. Wie sähe denn unter Berücksichtigung des Pixelformates meine angepasste Prozedur aus?

mfg KahPee

Edit:
Zitat:

Zitat von Aphton
Edit:
Ich habe eine kleine ScanlineBitmap Unit angehangen. Mit TScanlineBitmap.Pixel[] bist du schneller dran, da es per Scanline arbeitet.

Arbeitet der obige Quellcode nicht auch per "Scanline"?

Aphton 1. Feb 2010 16:56

Re: zwei Bitmaps vergleichen
 
Ja das tut es, aber mit der Unit bist du besser unterwegs, da du nur noch mehr Folgendes (bsp) machen musst:

Delphi-Quellcode:
var
  myBmp : TScanlineBitmap;
  x, y : Integer;
begin
  myBmp := TScanlineBitmap.Create;
  myBmp.LoadFromFile( '<Filename goes here>' );
  myBmp.UpdateScanlineBase();
  for y := 0 to myBmp.Height - 1 do
    for x := 0 to myBmp.Width - 1 do
    begin
      myBmp.Pixel[x,y] := $FF0000; // r = 0xFF, g = 0x00, b = 0x00
    end;
end;
Zu dem Problem mit den Zeigern:
1. Pixel zeigt auf den Start der RowLine (Scanline) -> Pixel := ...Scanline[y];
2. per Dereferenzierung (pointervariable + "^") greife ich nun direkt auf den Wert, auf den "gezeigt" wird zu und ändere sie:
Pixel^ := 0;
3. Inc( Variable ) = Increment = Erhöhe - entspricht --> Variable := Variable + 1;
Dh. der Zeiger Pixel zeigt nun auf die Addresse + 1

So wird solange verfahren, bis man am Ende der Zeile (scanLINE) angelangt ist.
Und wie schon beschrieben, besteht eine Zeile aus Width*Bytes Pixel, wobei Bytes PixelFormat entspricht -> 8, 16, 24 oder 32 Bit (es sind auch nur diese, die in der Unit uScanlineBitmap unterstützt werden)

Hoffe, ich konnte Licht ins Dunkel bringen...

Edit:
Zur Abfrage -> Falls Bytes = 0 -> dh <> 8, 16, 24 oder 32 Bit, dann brich ab, da wir nicht mit Bits rümkämpfen wollen.
Zur Schleife mit Schleifenvariable k -> der Pointer muss (Width * Bytss) mal inkrementiert werden, damit man an das Ende gelangt.
die kleine Schleife erhöht die Variable "Bytes" mal UND die Schleife wird Width mal aufgerufen.

Komisch zum Erklären, aber es sollte verständlich sein.

MfG

KahPee 1. Feb 2010 17:23

Re: zwei Bitmaps vergleichen
 
Ich habe das Bild im Moment als Tbitmap vorliegen.
Delphi-Quellcode:
myBmp.LoadFromFile( '<Filename goes here>' );
Das lädt ein Bitmap aus einer Datei, allerdings ist dieser vorgang schon längst passiert.. Kann ich an der Stelle irgendwie aus einer bestehenden Variable auslesen (Assign??) ?
Da das ganze nur ein kleiner Teil eines Programms ist und gerade diese Prozedur oft aufgerufen wird. Wäre interessant ob das wirklich eine schnelle variante ist, wenn das Bitmap jeweils einmal kopiert werden muss in eine weitere Variable. Deshalb hatte ich ja auch vor das ganze mit einem TBitmap zu machen.
Bleibt also letztendlich die Frage welche Variante schneller ist (die mit einmal kopieren (+ deine Unit einbinden) oder das ganze ohne deine Unit).

mfg Kahpee

Teekeks 1. Feb 2010 18:02

Re: zwei Bitmaps vergleichen
 
Ich würde das so machen:
Dein Momentanes Bild in einen Stream (TStream) schieben und dann myBmp.LoadFromStream(stream) aufrufen.

KahPee 1. Feb 2010 18:30

Re: zwei Bitmaps vergleichen
 
das ist dann doch noch langsamer, da es dann gleich zweimal kopiert wird...

KahPee 1. Feb 2010 22:28

Re: zwei Bitmaps vergleichen
 
So ich habe das ganze nochmal eingehender studiert. Unten habe ich meine ursprüngliche Funktion noch mal aufgegriffen und versucht anzupassen. Allerdings will das nocht nicht so wie ich will :(. Wie gebe ich die x-koordinate für den Pixel an? Mein Gefühl sagt, mir das ich nur 2-3 Zeilen von der Lösung weg bin. Aber ich hoffe ich täusche micht nicht :P. Es wäre nett wenn mir da nochmal auf die Sprünge geholfen werden könnte.

Delphi-Quellcode:
function Bitmapcompare(pic1, pic2: Tbitmap; Posx,posy: Integer): Boolean;
var
  Pix1, Pix2   : PByte;
  y, k, x : Integer;
  bytes  : Byte;
  compix, matchpix: integer;
const
  PixelFormatBytes: Array[TPixelFormat] of Byte = ( 0, 0, 0, 1, 0, 2, 3, 4, 0 );
begin
  result:=false;
  bytes1 := PixelFormatBytes[pic1.PixelFormat];
  bytes2 := PixelFormatBytes[pic2.PixelFormat];
 
  if (bytes1 = 0) or (bytes2=0) then
    Exit; // PixelFormat wird nicht unterstützt ... kannst du dann gerne von mir aus umändern ...
  for y := 0 to pic2.Height - 1 do
  begin
    Pix1 := pic1.Scanline[posy+y];
    Pix2 := pic2.Scanline[y];
    for x := 0 to pic2.Width - 1 do
      for k := 0 to bytes2 - 1 do
      begin
    //VERGLEICH
        if pix1=pix2 then inc(matchpix); //x-Koordinate nicht berücksichtigt
   
        Pix1^ := 0;
        inc(Pix1);
        Pix2^ :=0;
        inc(pix2);
     
        inc(compix);
      end;
  end;

   if compix=matchpix then Result:=true;
end;
Übrigens vielen Dank für den Hinweis mit "Inc()", das dürfte mir in Zukunft ein wenig Tipparbeit ersparen ;)

schon mal Vielen Dank

KahPee

Aphton 2. Feb 2010 07:21

Re: zwei Bitmaps vergleichen
 
So dürfte das funzen:

Delphi-Quellcode:
function Bitmapcompare(pic1, pic2: Tbitmap; Posx,posy: Integer): Boolean;
var
  Pix1, Pix2   : PByte;
  y, k, x : Integer;
  bytes: Byte;
  compix, matchpix: integer;
const
  PixelFormatBytes: Array[TPixelFormat] of Byte = ( 0, 0, 0, 1, 0, 2, 3, 4, 0 );
begin
  result:=false;
  bytes := PixelFormatBytes[pic1.PixelFormat];
  if bytes <> PixelFormatBytes[pic2.PixelFormat] then
    Exit;
  if (bytes = 0) then
    Exit; // PixelFormat wird nicht unterstützt ... kannst du dann gerne von mir aus umändern ...
  if (pic1.Width <> pic2.Width) or (pic1.Height <> pic2.Height) then
    Exit;
  matchpix := 0;
  compix := 0;
  for y := 0 to pic2.Height - 1 do
  begin
    Pix1 := pic1.Scanline[posy+y];
    Pix2 := pic2.Scanline[y];
    inc( Pix2, Posx*bytes );
    for x := 0 to pic2.Width - 1 do
      for k := 0 to bytes - 1 do
      begin
    //VERGLEICH
        if pix1^= pix2^ then
          inc(matchpix); //x-Koordinate nicht berücksichtigt
        inc(Pix1);
        inc(pix2);
        inc(compix);
      end;
  end;
  if compix = matchpix then
    Result := true;
end;
Du hast eine Untergrenze (posx,posy) aber warum keine Obergrenze?

Ein Optimierungsvorschlag für die vorige Routine wäre das hier:

Delphi-Quellcode:
function Bitmapcompare(pic1, pic2: Tbitmap; Posx,posy: Integer): Boolean;
var
  Pix1, Pix2   : PByte;
  y, k, x : Integer;
  bytes: Byte;
const
  PixelFormatBytes: Array[TPixelFormat] of Byte = ( 0, 0, 0, 1, 0, 2, 3, 4, 0 );
begin
  result:=false;
  bytes := PixelFormatBytes[pic1.PixelFormat];
  if bytes <> PixelFormatBytes[pic2.PixelFormat] then
    Exit;
  if (bytes = 0) then
    Exit; // PixelFormat wird nicht unterstützt ... kannst du dann gerne von mir aus umändern ...
  if (pic1.Width <> pic2.Width) or (pic1.Height <> pic2.Height) then
    Exit;
  for y := 0 to pic2.Height - 1 do
  begin
    Pix1 := pic1.Scanline[posy+y];
    Pix2 := pic2.Scanline[y];
    inc( Pix2, Posx*bytes );
    for x := 0 to pic2.Width - 1 do
      for k := 0 to bytes - 1 do
      begin
    //VERGLEICH
        if pix1^ <> pix2^ then
          Exit;  // ungleich, verlasse deshalb routine. Result ist in diesem Falle = False ...
        inc(Pix1);
        inc(pix2);
      end;
  end;
  // wenn wir es bis hierher geschafft haben, dann sind die bilder von (posx, posy) aufwärts gleich
  Result := true;
end;
Wie wärs denn mit soetwas?
Delphi-Quellcode:
{ Rückgabe = Gleichheit in % }
function CompareBitmap( bmp1, bmp2: TScanlineBitmap; const posX, posY, Width, Height: Integer ): Byte;
var
  x, y,
  TotalPixels,
  MatchingPixels : Integer;
  Bytes : Byte;
const
  PixelFormatBytes: Array[TPixelFormat] of Byte = ( 0, 0, 0, 1, 0, 2, 3, 4, 0 );
begin
  Result := 0;
  if (bmp1.Width <> bmp2.Width) or (bmp1.Height <> bmp2.Height) then
    Exit;
  if (bmp1.PixelFormat <> bmp2.PixelFormat) then
    Exit;
  Bytes := PixelFormatBytes[bmp1.PixelFormat];
  TotalPixels := (Height-posY) * (Width-posX);
  MatchingPixels := 0;
  for y := posY to Height - 1 do
    for x := posX to Width - 1 do
      if bmp1.Pixel[x,y] = bmp2.Pixel[x,y] then
        inc( MatchingPixels );
  Result := Round(MatchingPixels * 100 / TotalPixels);
end;
MfG

KahPee 2. Feb 2010 08:08

Re: zwei Bitmaps vergleichen
 
Delphi-Quellcode:
if (pic1.Width <> pic2.Width) or (pic1.Height <> pic2.Height) then
Das macht genau das was ich NICHT möchte. pic1 ist ja hat in den meisten Fällen (99% oder sogar mehr) eine größere Größe als pic1 sowohl in x als auch in y Richtung.
müsste es deshabl nicht so heißen?:
Delphi-Quellcode:
if (pic1.Width < pic2.Width) or (pic1.Height < pic2.Height) then //für den Fall, dass Bild1 in einer Richtung kleiner ist
Außerdem hab ich hier was gefunden.. Müsste das an markierter Stelle nicht Pix1 statt Pix2 heißen?
Delphi-Quellcode:
for y := 0 to pic2.Height - 1 do
  begin
    Pix1 := pic1.Scanline[posy+y];
    Pix2 := pic2.Scanline[y];
    inc( Pix1, Posx*bytes );           //Position wird bei dem größeren! Bild verschoben
    for x := 0 to pic2.Width - 1 do
      for k := 0 to bytes - 1 do
      begin
    //VERGLEICH
        if pix1^= pix2^ then
          inc(matchpix);
Ansonsten sieht der 2. Vorschlag schon besser aus, der bricht direkt ab, wenn es keine Übereinstimmung gibt. Das spart Rechenzeit ;).
Die Prozentangabe find ich nett, verfehlt aber in meinem speziellen Fall den Zweck, bei geht es ja nur um 100% Übereinstimmung ja oder nein. von der 3. Prozedur möchte ich wie schon oben bemerkt Abstand nehmen (TscanlineBitmap<>Bitmap {zu viele Konvertierungen wären nötig -> kostet Zeit}; außerdem verstehe ich das andere noch halbwegs :P )

Es gibt keine Obergrenze weil das 2. Bild als das kleinere (in x und y Richtung) komplett in dem ersten drin sein soll (an einer bestimmten Stelle). D.h. das zweite Bild besteht nur aus dem Ausschnitt den ich haben will. Obergrenze ist also (pic2.height-1 bzw. pic2.width-1)


mfg KahPee

Aphton 2. Feb 2010 11:16

Re: zwei Bitmaps vergleichen
 
Ja sorry, da fehlt noch ein
inc() bei Pix1

MfG

KahPee 2. Feb 2010 11:32

Re: zwei Bitmaps vergleichen
 
Wo fehlt da noch ein inc() :? ? Ich hätte gesagt, dass die nachfolgende Version eigentlich klappen müsste.. Allerdings ist das nur die Version wo die bei meinem letzten Post angegeben Verbesserungsvorschläge eingearbeitet werden.
Delphi-Quellcode:
function Bitmapcompare(pic1, pic2: Tbitmap; Posx,posy: Integer): Boolean;
var
  Pix1, Pix2   : PByte;
  y, k, x : Integer;
  bytes: Byte;
const
  PixelFormatBytes: Array[TPixelFormat] of Byte = ( 0, 0, 0, 1, 0, 2, 3, 4, 0 );
begin
  result:=false;
  bytes := PixelFormatBytes[pic1.PixelFormat];
  if bytes <> PixelFormatBytes[pic2.PixelFormat] then
    Exit;
  if (bytes = 0) then
    Exit; // PixelFormat wird nicht unterstützt ... kannst du dann gerne von mir aus umändern ...
  if (pic1.Width < pic2.Width) or (pic1.Height < pic2.Height) then
    Exit;
  for y := 0 to pic2.Height - 1 do
  begin
    Pix1 := pic1.Scanline[posy+y];
    Pix2 := pic2.Scanline[y];
    inc(Pix1, Posx*bytes ); //Verschieben der Zeigerposition beim größeren Bild
   
    for x := 0 to pic2.Width - 1 do
      for k := 0 to bytes - 1 do
      begin
    //VERGLEICH
        if pix1^ <> pix2^ then
          Exit;  // ungleich, verlasse deshalb routine. Result ist in diesem Falle = False ...
        inc(Pix1);
        inc(pix2);
      end;
  end;
  // wenn wir es bis hierher geschafft haben, dann sind die bilder von (posx, posy) aufwärts gleich
  Result := true;
end;

Amateurprofi 2. Feb 2010 16:17

Re: zwei Bitmaps vergleichen
 
Scheint zu funktionieren, jedoch hätte ich noch einen Vorschlag, wie das ohne große Mühe, deutlich schneller läuft.
Beim Vergleichen einer Zeile zählst du die Pixel (in x), dann zählst du die Bytes je Pixel (in k).

Ich hole mir die Länge einer Zeile in Bytes.
Hieraus errechne ich die Anzahl der vollen DWords und die ggfs. verbleibenden Bytes.
Beim Prüfen einer Zeile muß ich dann nicht Byte für Byte vergleichen sondern je 4 Bytes auf einmal, was einen entsprechenden Performancegewinn ergibt.
Ich denke, mit etwas Aufwand kann man die Performance noch einmal um 50 bis 100 % steigern.

Delphi-Quellcode:
function xBitmapcompare(pic1, pic2: Tbitmap; Posx,posy: Integer): Boolean;
var
  Pix1, Pix2   : PByte;
  y, k, x, b, dw : Integer;
  bytes: Byte;
const
  PixelFormatBytes: Array[TPixelFormat] of Byte = ( 0, 0, 0, 1, 0, 2, 3, 4, 0 );
begin
  result:=false;
  bytes := PixelFormatBytes[pic1.PixelFormat];
  if bytes <> PixelFormatBytes[pic2.PixelFormat] then
    Exit;
  if (bytes = 0) then
    Exit; // PixelFormat wird nicht unterstützt ... kannst du dann gerne von mir aus umändern ...
  if (pic1.Width < pic2.Width) or (pic1.Height < pic2.Height) then
    Exit;
  b:=bytes*pic2.Width; // Anzahl Bytes je Zeile
  dw:=b shr 2-1;      // Anzahl DWords je zeile
  b:=b and 3-1;       // restliche Bytes je Zeile
  for y := 0 to pic2.Height - 1 do
  begin
    Pix1 := pic1.Scanline[posy+y];
    Pix2 := pic2.Scanline[y];
    inc(Pix1, Posx*bytes ); //Verschieben der Zeigerposition beim größeren Bild
    for x:=dw downto 0 do begin // Volle DWords vergleichen
      if PInteger(Pix1)^ <> PInteger(Pix2)^ then exit;
      inc(Pix1,4);
      inc(pix2,4);
    end;
    for x:=b downto 0 do begin // Restliche Bytes vergleichen
      if Pix1^ <> Pix2^ then exit;
      inc(Pix1);
      inc(pix2);
    end;
  end;
  // wenn wir es bis hierher geschafft haben, dann sind die bilder von (posx, posy) aufwärts gleich
  Result := true;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:52 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