![]() |
Re: zwei Bitmaps vergleichen
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:
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 |
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:
Leider hab ich keine Ahnung von Zeigern und dem "inc()" kram. Wie sähe denn unter Berücksichtigung des Pixelformates meine angepasste Prozedur aus?
//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; mfg KahPee Edit: Zitat:
|
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:
Zu dem Problem mit den Zeigern:
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; 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 |
Re: zwei Bitmaps vergleichen
Ich habe das Bild im Moment als Tbitmap vorliegen.
Delphi-Quellcode:
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??) ?
myBmp.LoadFromFile( '<Filename goes here>' );
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 |
Re: zwei Bitmaps vergleichen
Ich würde das so machen:
Dein Momentanes Bild in einen Stream (TStream) schieben und dann myBmp.LoadFromStream(stream) aufrufen. |
Re: zwei Bitmaps vergleichen
das ist dann doch noch langsamer, da es dann gleich zweimal kopiert wird...
|
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:
Übrigens vielen Dank für den Hinweis mit "Inc()", das dürfte mir in Zukunft ein wenig Tipparbeit ersparen ;)
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; schon mal Vielen Dank KahPee |
Re: zwei Bitmaps vergleichen
So dürfte das funzen:
Delphi-Quellcode:
Du hast eine Untergrenze (posx,posy) aber warum keine Obergrenze?
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; Ein Optimierungsvorschlag für die vorige Routine wäre das hier:
Delphi-Quellcode:
Wie wärs denn mit soetwas?
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;
Delphi-Quellcode:
MfG
{ 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; |
Re: zwei Bitmaps vergleichen
Delphi-Quellcode:
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.
if (pic1.Width <> pic2.Width) or (pic1.Height <> pic2.Height) then
müsste es deshabl nicht so heißen?:
Delphi-Quellcode:
Außerdem hab ich hier was gefunden.. Müsste das an markierter Stelle nicht Pix1 statt Pix2 heißen?
if (pic1.Width < pic2.Width) or (pic1.Height < pic2.Height) then //für den Fall, dass Bild1 in einer Richtung kleiner ist
Delphi-Quellcode:
Ansonsten sieht der 2. Vorschlag schon besser aus, der bricht direkt ab, wenn es keine Übereinstimmung gibt. Das spart Rechenzeit ;).
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); 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 |
Re: zwei Bitmaps vergleichen
Ja sorry, da fehlt noch ein
inc() bei Pix1 MfG |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:52 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz