Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Mehrere Bilder vergleichen


HenryHux - Do 23.09.10 13:30
Titel: Mehrere Bilder vergleichen
Hi,

ich habe ja mit eurer Hilfe mitlerweile ein Programm hinbekommen, welches Bilder vergleiche kann. Klappt auch 1A!
Jetzt versuche ich aber ein Bild mit ca 50 verschiedenen zu vergleichen. Wie realisiere ich das am besten? Ich kann ja nicht schlecht 50 TImage erzeugen, oder?

Hier die Funktion, die die Bilder vergleicht :

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
function CompareImages(Bitmap3, Bitmap2: TBitmap): LongWord;
var
  xy: integer;
  P1, P2: PInteger;
begin
  Result:=0;
  Bitmap3.PixelFormat:=pf32bit;
  Bitmap2.PixelFormat:=pf32bit;
  P1:=Bitmap3.ScanLine[Bitmap3.Height-1];
  P2:=Bitmap2.ScanLine[Bitmap2.Height-1];
  for xy:=1 to Bitmap3.Height*Bitmap3.Width do begin
    Inc(Result, Byte(P1^<>P2^));
    Inc(P1);
    Inc(P2);
  end;
end;


Und hier die, die sie aufruft:

Delphi-Quelltext
1:
2:
3:
4:
procedure TForm1.Button3Click(Sender: TObject);
begin
ShowMessage(IntToStr(CompareImages(Image1.Picture.Bitmap,Image2.Picture.Bitmap)));
end;


Vielen Dank!


Gausi - Do 23.09.10 13:42

Wie liegen die Bitmaps denn vor? In Dateien? Dann könnte man das so machen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
EinBild.LoadFromFile('c:\meinBild.bmp');

for i := 1 to 50 do
begin
  NocheinBild.LoadFromFile('c:\NocheinBildNr' + IntTostr(i) + '.bmp'); 
  // Annahme: Bilder sind durchnumeriert
  Diff := CompareImages(EinBild, NocheinBild);
  ShowMessage(IntToStr(Diff)); 
  // oder halt sonst wie die Differenzen verwalten/speichern/...
end;


HenryHux - Do 23.09.10 14:31

Ok, denke das könnte so klappen.
Habs jetzt so:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure TForm1.Button4Click(Sender: TObject);
var i, diff : integer;
    EinBild, NocheinBild : TBitmap;
begin
EinBild.LoadFromFile('D:\image.bmp');

for i := 1 to 2 do
begin
  NocheinBild.LoadFromFile('D:\image' + IntTostr(i) + '.bmp');
  // Annahme: Bilder sind durchnumeriert
  Diff := CompareImages(EinBild, NocheinBild);
  ShowMessage(IntToStr(Diff));
  // oder halt sonst wie die Differenzen verwalten/speichern/...
end;
end;


Wenn ichs starte stürtzt er ab mit der Fehlermeldung und zeigt mir EinBild.LoadFromFile('D:\image.bmp'); als Fehlerquelle.
Ne Idee?

---------------------------
Debugger Exception Notification
---------------------------
Project Project2.exe raised exception class EAccessViolation with message 'Access violation at address 0045890D in module 'Project2.exe'. Read of address 00000000'. Process stopped. Use Step or Run to continue.
---------------------------
OK Help
---------------------------


bummi - Do 23.09.10 14:32

Wenn Du nicht BMP's mit JPG's vergeleichen muß wie wäre es mit:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,Math, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
function CompareStreams(Stream1, Stream2: TStream): Extended;
type
  TBuffer = array[0..8191of Byte;
const
  BuffSize = SizeOf(TBuffer);
var
  Buffer1: TBuffer;
  Buffer2: TBuffer;
  BytesRead1: Integer;
  BytesRead2: Integer;
  DifferenceCount: Int64;
  Index: Integer;
  MaxCount: Integer;
begin
  Stream1.Position := 0;
  Stream2.Position := 0;
  DifferenceCount := 0;
  while True do
    begin
    BytesRead1 := Stream1.Read(Buffer1, BuffSize);
    BytesRead2 := Stream2.Read(Buffer2, BuffSize);
    MaxCount := Min(BytesRead1, BytesRead2);
    for Index := 0 to MaxCount -1 do
      if Buffer1[Index] <> Buffer2[Index] then

        Inc(DifferenceCount);
    if (BytesRead1 <> BytesRead2) or (BytesRead1 = 0or (BytesRead2 = 0then
      Break;
  end;
  Result := (DifferenceCount * 100) / Max(Stream1.Size, Stream2.Size);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Stream1: TFileStream;
  Stream2: TFileStream;
  Differences: Extended;
begin
  Differences := 0.0000;
    try
      Stream1 := TFileStream.Create('C:\temp\1.jpg', fmOpenRead);
      Stream2 := TFileStream.Create('C:\temp\1.1.jpg', fmOpenRead);
      Differences := CompareStreams(Stream1, Stream2);
    finally
      FreeAndNil(Stream1);
      FreeAndNil(Stream2);
    end;
  ShowMessageFmt('%.4f', [Differences]);
end;


end.


Gausi - Do 23.09.10 14:36

Vorher müssen natürlich die Bitmap-Objekte einmal erzeugt werden:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
EinBild := TBitmap.Create;
NochEinBild := TBitmap.Create;

// ...

EinBild.Free;
NochEinBild.Free;

Zusätzlich noch Ressourcen-Schutzblöcke, also try...finally drumherum wie im Code von user profile iconbummi bei den FileStreams. :)


HenryHux - Do 23.09.10 14:49

Danke!
Hatte die Bilder im Bitmap Format. Aber Jpeg ist auch nicht schlecht zu wissen =)


user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
Vorher müssen natürlich die Bitmap-Objekte einmal erzeugt werden
:oops: ..Natürlich. Danke!

Aber was ich nicht verstehe:

Zuerst vergleicht er ja das bmp mit bmp1. Die sind beide gleich, bis auf, dass das Zweite ein wenig mehr nach rechts verschoben ist. Das erkennt er gut und gibt mir als Wert 9967.
Dann vergleicht er bmp mit bmp2. Zwei völlig verschiedene Bilder. Er gibt mir 1000.
Dann bmp mit bmp3. Beide identisch und er gibt mir 0. Wieso? 0 dürfte hier doch nit exat gleich bedeuten?

Edit:
Ok 0 bedeutet 100%...
Eine kleine abschließenden Frage hätte ich aber noch.
Wie kann ich bei GetShoot2Image(image1,Rect(Breite,Hoehe,Breite + Breite2,Hoehe + Hoehe2),1); das Bild an sich kleiner machen?


Tilman - Do 23.09.10 16:24

Nur kurz zur Erklärung dieser Term: "(P1^<>P2^)", ergibt true wenn P1^ ungleich P2^ ist, und False wenn sie gleich sind. Das wird dann als Byte umgewandelt, true ist als Zahl "1" und False als Zahl "0". Wenn beide Pixel identisch sind, wird result also um 0 erhöht, sind beide verschieden wird Result um 1 erhöht. Vermutlich die schnellste Lösung, die aber dazu führt dass kein Anfänger den Code mehr begreift :D