[SOLVED]Better/Fastest way to compare two images. lazarus / 39-Graphics ---------------------------------------------------------------------- gafe · 2014-11-14 18:38 Hi: I'm doing a couple of apps to learn the language, one is a copy utility that can copy only changed parts of a file (i have questions about this, it's working, but will post another topic other day) and a remote control (like vnc) utility. As a proof of concept, i have it working sending a tjpegimage saved in a tmemorystream over the network every second, and it works well...but the next step is getting the differences between two images to send only those. I read the wiki, but i'm not sure what's the best/fast way to compare two images...TLazIntfImage? TBGRABitmap? Also, as i don't know anything about graphics processing, i have other question: Will it be hard to change bit depth? Scale to lower resolutions? If someone it's interested, i can make a zip of source code, but it's very early code, and the processing of TCP streams it's implemented badly (messages between client/server not of fixed lenght, for example) Thanks all. ---------------------------------------------------------------------- derek.john.evans · 2014-11-14 18:50 I did something similar a few years back.  I XOR-ed each 32bit pixel with the previous frame. All the pixels that are the same will go black. Then compress to PNG or some TStream based compressor before sending. ---------------------------------------------------------------------- gafe · 2014-11-14 19:57 Thanks, that's smart. I'm looking and i think i can implement that with bitblt http://lazarus- ccr.sourceforge.net/docs/lcl/lclintf/bitblt.html and SRCINVERT "Fills the destination area with (Dst xor Src)".... Will try it if i have time this weekend...thanks again... ---------------------------------------------------------------------- User137 · 2014-11-14 20:10 You are talking about verifying data from corruption in network transfer. For this you don't need to specify image comparison, but raw byte array comparison which is much simpler. What you get from stream is just byte data in essence. ---------------------------------------------------------------------- gafe · 2014-11-14 20:32 Quote from: User137 on November 14, 2014, 09:10:13 pmYou are talking about verifying data from corruption in network transfer. For this you don't need to specify image comparison, but raw byte array comparison which is much simpler. What you get from stream is just byte data in essence. No, that's not what i mean (not a native english speaker)...i try to get the difference between two images (two bitmaps, for example) to repaint/redraw that difference only in another computer.... ---------------------------------------------------------------------- circular · 2014-11-14 22:14 Hi! You can use XOR as Derek suggested. Also if you have the bounds, you can send only this rectangle of data. Note that using the XOR method, you cannot use JPEG compression, because of the loss of quality, you can't know which pixels to keep and the losses may add with time. With JPEG compression, you can determine the region that has changed as a matrix of 8x8 blocks, fill the rest with black, and send both the JPEG of that and the matrix of change. The size of the matrix will be small if you store in a bit array. One byte can be used to store 8 bits, so that represents 8x8x8 = 512 pixels. ---------------------------------------------------------------------- gafe · 2014-11-14 22:34 Thanks....which method do you think will be faster, as i have to iterate over all the pixels in a image? a Tlazintfimage? use TFastBitmapPixel ? raw memory? TBGRABitmap.ScanLine? ...there's a lot of examples in the wiki...don't know what to choose as i never did graphics programming.... ---------------------------------------------------------------------- Laksen · 2014-11-14 23:45 The fastest would be to use a block sized fuzzy hash based approach. Fuzzy has was developed for this purpose. Here was the port I made a few years ago: http://j-software.dk/pasfuzzy.zip It was faster than the C version back then, and could extremely easily be made thread safe unlike the C version ---------------------------------------------------------------------- Eugene Loza · 2014-11-15 08:02 If its for expansion later, I'd better thought of 2d Fourier transform (FFT will be quicker) plus correlation analysis of both results to counter scaling and brightness. That would not just show pixel-by- pixel comparison, but would be able to detect scaled and processed images (e.g. with different JPEG compression quality / or two scanned images of the same document with different DPI), but not HUE/Saturation changes, rotation or other deformation, those should be handled separately. Thou, it's definately not the fastest way ---------------------------------------------------------------------- gafe · 2014-11-15 10:34 I could try later the hash approach (but that means processing all the pixels anyway)... and the fourier transform seems overkill for this little project. As my time is limited (you know, children,family,work...) i will try starting with tlazintfimage getdatalinestart and grow from there to a bgrabitmap if i need it to process the image later (change bit depth, to grayscale,etc.) Thanks for your suggestions...i think that's what keeps the fpc/lazarus environment working.... ---------------------------------------------------------------------- Laksen · 2014-11-15 10:44 You don't have to hash the pixels just the file directly. That assumes the compressions are roughly the same of course ---------------------------------------------------------------------- gafe · 2014-11-15 12:05 There's no file...right now is: Bitmap of screen - tjpegimage - savetostream - send tmemorystream over network ---------------------------------------------------------------------- circular · 2014-11-16 01:28 Quote from: gafe on November 14, 2014, 11:34:35 pmThanks....which method do you think will be faster, as i have to iterate over all the pixels in a image? a Tlazintfimage? use TFastBitmapPixel ? raw memory? TBGRABitmap.ScanLine? ...there's a lot of examples in the wiki...don't know what to choose as i never did graphics programming.... Basically the fastest way is to do direct access with TBGRABitmap or TLazIntfImage or TRawImage. I suppose using one or the other is not very significant compared to doing the actual processing and compression. Of course, if you want more functions, TBGRABitmap provides a lot. There is also Graphics32 that is similar but may be less portable. And also AggPas but may be more complicated to use. ---------------------------------------------------------------------- gafe · 2014-11-16 08:57 Well, i did a quick test of comparing all pixels of two screencaptures (1 screencapture one second after): tlazintinfimage - 192 ms and tbgrabitmap ¡26 ms! . That is with 1920x1080 24bit in a old AMD Athlon(tm) II X2 245. As there is a lot of difference this is how i done it: - Tlazintinfimage: Code: [Select]    for py:=0 to SrcIntfImg.Height-1 do begin       for px:=0 to SrcIntfImg.Width-1 do begin         if (SrcIntfImg.Colors[px,py] <> TempIntfImg.Colors[px,py] ) then         begin         end         else         TempIntfImg.Colors[px,py]:=TColorToFPColor(clBlack);         {TempIntfImg.Colors[px,py]:=SrcIntfImg.Colors[px,py] xor TempIntfImg.Colors[px,py]; }       end;     end;      and tbgrabitmap (SrcIntfImg in this case is a TBGRABitmap, didn't change the name): Code: [Select]for n:=SrcIntfImg.NbPixels-1 downto 0 do     begin        if p^ = r^   then        begin          r^:=CSSBlack;        end        else        begin        end;        inc(p);        inc(r);     end;                  Also, TBGRABitmap gives more options to process the image....for me there's a winner  Thank you all again. ---------------------------------------------------------------------- BigChimp · 2014-11-16 10:18 Great - thanks for posting such a useful solution! ---------------------------------------------------------------------- circular · 2014-11-16 14:06 Yes, accessing the Colors property of TLazIntfImage is slow. However if you use GetDataLineStart, you can however scan each line more quickly. In this case, you need to make sure about the pixel format. You don't need to think about that with BGRABitmap because it is always 32-bit BGRA.