C'è un modo migliore di esaminarli pixel per pixel?Qual è il modo più veloce per verificare se due Tbitmap sono uguali?
risposta
È possibile salvare entrambe le bitmap a TMemoryStream e confrontarlo con CompareMem:
function IsSameBitmap(Bitmap1, Bitmap2: TBitmap): Boolean;
var
Stream1, Stream2: TMemoryStream;
begin
Assert((Bitmap1 <> nil) and (Bitmap2 <> nil), 'Params can''t be nil');
Result:= False;
if (Bitmap1.Height <> Bitmap2.Height) or (Bitmap1.Width <> Bitmap2.Width) then
Exit;
Stream1:= TMemoryStream.Create;
try
Bitmap1.SaveToStream(Stream1);
Stream2:= TMemoryStream.Create;
try
Bitmap2.SaveToStream(Stream2);
if Stream1.Size = Stream2.Size Then
Result:= CompareMem(Stream1.Memory, Stream2.Memory, Stream1.Size);
finally
Stream2.Free;
end;
finally
Stream1.Free;
end;
end;
begin
if IsSameBitmap(MyImage1.Picture.Bitmap, MyImage2.Picture.Bitmap) then
begin
// your code for same bitmap
end;
end;
non l'ho fatto riferimento questo codice X scanline, se lo fai, fatecelo sapere quale è il più veloce.
Alcuni commenti: 1) Il codice non è sicuro per le eccezioni. 2) Vorrei restituire False immediatamente se la larghezza o l'altezza delle bitmap differiscono. O forse anche se i formati dei pixel differiscono, ma la domanda è troppo vaga da dire. – mghie
commenti piacevoli mghie. Ill cambiare il codice per testare l'altezza e la larghezza. –
Ingerire le eccezioni non era quello che intendevo, permettimi di modificare il codice ... – mghie
Se è necessaria una risposta precisa, no. Se hai bisogno di un'approssimazione, probabilmente potresti controllare una selezione di pixel. Ma se vuoi scoprire se i due bitmap sono esattamente identici devi confrontare l'intero pixel e i dati in formato pixel.
Utilizzo di ScanLine, senza TMemoryStream.
function IsSameBitmapUsingScanLine(Bitmap1, Bitmap2: TBitmap): Boolean;
var
i : Integer;
ScanBytes : Integer;
begin
Result:= (Bitmap1<>nil) and (Bitmap2<>nil);
if not Result then exit;
Result:=(bitmap1.Width=bitmap2.Width) and (bitmap1.Height=bitmap2.Height) and (bitmap1.PixelFormat=bitmap2.PixelFormat) ;
if not Result then exit;
ScanBytes := Abs(Integer(Bitmap1.Scanline[1]) - Integer(Bitmap1.Scanline[0]));
for i:=0 to Bitmap1.Height-1 do
Begin
Result:=CompareMem(Bitmap1.ScanLine[i],Bitmap2.ScanLine[i],ScanBytes);
if not Result then exit;
End;
end;
Ciao.
+1 molto ben composto. Sarebbe interessante confrontare la velocità di questa contro la soluzione di Cesar. Questo ha più confronti, ma consente di risparmiare tempo non allocare memoria. Il titolo della domanda ha specificato ** il più veloce **, dopo tutto. – Argalatyr
@RRUZ: Sono d'accordo che questa è una buona soluzione se la stessa bitmap indica lo stesso layout di memoria, +1. Considererei un rapido controllo per bitmap uguali in formati possibilmente diversi per essere un problema più interessante, però. Se una bitmap pf24bit o pf32bit ha meno di 256 colori, può avere senso salvarla in pf8bit, ma la stessa bitmap verrà comunque visualizzata. – mghie
Di solito uso solo pf8bit, e per questo sarebbe ok. Mi chiedo però se i bit di allineamento sono controllati se hai pf12bit e una larghezza dispari. Lo stesso per bpp è sotto l'8, ma quelli sono programmati afaik. –
Si prega di chiarire: Se hanno diversi formati di pixel (ad esempio pf24bit e pf8bit) e quindi diverse dimensioni in memoria, ma contengono gli stessi pixel, sono uguali o no? – mghie