Is there a better way than examine them pixel by pixel?
Why would you start an answer to a question with "I don't know"? If you don't know, don't answer.
raven
2009-08-29 20:41:44
well, just give some idea.
silent
2009-08-29 20:44:20
Maybe the silence is better when you dont know, silent.
Cesar Romero
2009-08-29 21:11:02
Using a hash function is not a bad idea.
RRUZ
2009-08-29 21:43:23
To compute the hashes one would need to visit each byte of both bitmaps. So why not compare them directly in the first place?
mghie
2009-08-29 21:44:10
@RRUZ: Actually for this task it **is** a bad idea.
mghie
2009-08-29 21:45:06
mghie you are right, calculate the hash is slower than using CompareMem, I wrote a version using ScanLine. ;)
RRUZ
2009-08-29 23:04:51
Look on the plus side - delete this now and you get a badge!
Argalatyr
2009-08-30 03:06:00
mghie: cache size maybe. The compare needs more data active in the cache. But I think that is theoretic only, since the action per pixel are way higher in the hash case (since you have to pick a pretty decent one to avoid false positives)
Marco van de Voort
2009-08-30 09:30:28
@Marco: The killer argument against the hash approach is that it gives a result only after the algorithm has completed, while a pixel comparison can exit at the very first difference. If there's a decent chance that bitmaps are different this should trump all other considerations.
mghie
2009-08-30 10:12:48
@mghie: that's a great argument for the scanline approach as well.
Argalatyr
2009-08-30 13:08:50
@Argalatyr: Indeed, and I would be surprised if it didn't completely outclass the memory stream solution performance-wise. But the OP will have to *measure* it, now that he has the two solutions.
mghie
2009-08-30 13:42:20
A:
If you need an accurate answer, no. If you need an approximation, you probably could check a selection of pixels. But if you want to find out if the two bitmaps are exactly identical you need to compare the entire pixel and pixel format data.
TommyA
2009-08-29 20:59:19
+11
A:
You can save both Bitmaps to TMemoryStream and compare using 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;
I did not benchmark this code X scanline, if you do, please let us know which one is the fastest.
Cesar Romero
2009-08-29 21:23:39
Some comments: 1) Code isn't exception-safe. 2) I would return False immediately if width or height of the bitmaps differ. Or maybe even if the pixel formats differ, but the question is too vague to tell.
mghie
2009-08-29 21:35:54
Nice comments mghie. Ill change the code to test the height and width.
Cesar Romero
2009-08-29 21:46:27
I dont think I can "allow" others to edit my posts, if I can, please let me know how.If you post here your suggestions I can edit and mention in my post.
Cesar Romero
2009-08-29 21:53:56
mghie's comment above asks whether matching pixel format is a specification, but it's easy to add as illustrated in RRUZ's answer.
Argalatyr
2009-08-30 01:47:06
Strictly speaking, such compares can go wrong when one of the bitmaps has a bit garbage in the alignment bytes/bits between lines. Therefore we always compare the pixeldata with comparemem on a per line basis.
Marco van de Voort
2009-08-30 09:25:52
+10
A:
Using ScanLine, Without 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;
Bye.
RRUZ
2009-08-29 22:52:24
+1 very nicely composed. It would be interesting to compare the speed of this versus Cesar's solution. This has more comparisons, but saves time by not allocate memory. The question title did specify **fastest**, after all.
Argalatyr
2009-08-30 01:45:00
@RRUZ: I agree that this is a good solution if same bitmap means the same memory layout, +1. I'd consider a fast check for equal bitmaps in possibly different formats to be a more interesting problem, though. If a pf24bit or pf32bit bitmap has less than 256 colours it can make sense to save it in pf8bit, but the same bitmap will still be displayed.
mghie
2009-08-30 06:46:26
I usually only use pf8bit, and for this it would be ok. I wonder though if alignment bits are checked if you have pf12bit and an odd width. Same for bpp's below 8, but those are planed afaik.
Marco van de Voort
2009-08-30 09:28:58