Jak porównać dwie bitmapy
function GetDifference(Img1, Img2:TImage; var XStart, XStop, YStart, YStrop:integer):boolean; var Pixel1:^TrgbTriple; Pixel2:^TrgbTriple; x, y:integer; TheSame:boolean; begin Img1.Picture.Bitmap.PixelFormat:=pf24bit; Img2.Picture.Bitmap.PixelFormat:=pf24bit; TheSame:=true; for y:=0 to Img1.Picture.Bitmap.Height -1 do begin Pixel1:=Img1.Picture.Bitmap.ScanLine[y]; Pixel2:=Img2.Picture.Bitmap.ScanLine[y]; for x:=0 to Img1.Picture.Bitmap.Width-1 do begin if (Pixel1.RgbtRed<>Pixel2.RgbtRed) or (Pixel1.RgbtGreen<>Pixel2.RgbtGreen)or (Pixel1.RgbtBlue<>Pixel2.RgbtBlue) then begin if TheSame or (XStart>X) then XStart:=X; if TheSame or (XStop<X) then XStop:=X ; if TheSame or (YStart>Y) then YStart:=Y; if TheSame or (YStrop<Y) then YStrop:=Y; TheSame:=false; end; inc(Pixel1); inc(Pixel2); end; Result:=not TheSame; end; end;
Kod pochodzi autorstwa Piotrkadp, pochodzący z tego wątku na forum. I jeszcze wersja dla C++Builder przetłumaczona przez AklimX-a:
bool GetDifference(TImage Img1, TImage Img2, int &XStart, int &XStop, int &YStart, int &YStrop) { TrgbTriple* Pixel1, *Pixel2; int x, y; bool TheSame; Img1->Picture->Bitmap->PixelFormat = pf24bit; Img2->Picture->Bitmap->PixelFormat = pf24bit; TheSame = true; for(y=0; y<Img1->Picture->Bitmap->Height; ++y) { Pixel1 =Img1->Picture->Bitmap->ScanLine[y]; Pixel2 =Img2->Picture->Bitmap->ScanLine[y]; for( x=0; x<Img1->Picture->Bitmap->Width; ++x) { if( (Pixel1->RgbtRed!=Pixel2->RgbtRed) || (Pixel1->gbtGreen!=Pixel2->RgbtGreen)|| (Pixel1->RgbtBlue!=Pixel2->RgbtBlue) ) { if ((TheSame) || (XStart>X)) XStart=X; if ((TheSame) || (XStop <X)) XStop =X; if ((TheSame) || (YStart>Y)) YStart=Y; if ((TheSame) || (YStrop<Y)) YStrop=Y; TheSame=false; } ++Pixel1; ++Pixel2; } } return !TheSame; }
5 komentarzy
Jesem kompletnym laikiem jeśli chodzi mi o programowanie. Potrzebny jest mi jednak program wykrywający zmiany na monitorze (np. odświeżenie i zmiana zawartości strony www). Nie wiem jak to zrobić- możnaby się pokusić (o ile nie ma prostszego rozwiązania) tworzenie co pewien czas screenów, i późniejsze porównywanie ich jako bitmapy (ale niestety nawet nie umiem wykorzystać podanego kodu). Prosiłbym o szczegółową pomoc. Z góry dziękuję
Przyznam, że dziwi mnie to. Przecież porównanie czy zwiększanie (adresów) trwa tyle samo dla danych 1 i 4 bajtowych, a w drugim jest po prostu więcej operacji.. Na pierwszy rzut oka - bez sensu.
napisałem procedury tak :
function GetDifference(const Bitmap1, Bitmap2:TBitmap; var XStart, XStop, YStart, YStrop:integer):boolean;
var
Pixel1,Pixel2:^DWORD;
x, y:integer;
TheSame:boolean;
begin
Bitmap1.PixelFormat:=pf32bit;
Bitmap2.PixelFormat:=pf32bit;
TheSame:=true;
for y:=0 to Bitmap1.Height -1 do
begin
Pixel1:=Bitmap1.ScanLine[y];
Pixel2:=Bitmap2.ScanLine[y];
for x:=0 to Bitmap1.Width-1 do
begin
if (Pixel1^<>Pixel2^) then
begin
if TheSame or (XStart>X) then XStart:=X;
if TheSame or (XStop<X) then XStop:=X ;
if TheSame or (YStart>Y) then YStart:=Y;
if TheSame or (YStrop<Y) then YStrop:=Y;
TheSame:=false;
end;
inc(Pixel1);
inc(Pixel2);
end;
Result:=not TheSame;
end;
end;
function GetDifference2(const Bitmap1, Bitmap2:TBitmap; var XStart, XStop, YStart, YStrop:integer):boolean;
var
Pixel1,Pixel2:^TRGBQuad;
x, y:integer;
TheSame:boolean;
begin
Bitmap1.PixelFormat:=pf32bit;
Bitmap2.PixelFormat:=pf32bit;
TheSame:=true;
for y:=0 to Bitmap1.Height -1 do
begin
Pixel1:=Bitmap1.ScanLine[y];
Pixel2:=Bitmap2.ScanLine[y];
for x:=0 to Bitmap2.Width-1 do
begin
if (Pixel1.RgbRed<>Pixel2.RgbRed) or
(Pixel1.RgbGreen<>Pixel2.RgbGreen)or
(Pixel1.RgbBlue<>Pixel2.RgbBlue) or
(Pixel1.rgbReserved<>Pixel2.rgbReserved) then
begin
if TheSame or (XStart>X) then XStart:=X;
if TheSame or (XStop<X) then XStop:=X ;
if TheSame or (YStart>Y) then YStart:=Y;
if TheSame or (YStrop<Y) then YStrop:=Y;
TheSame:=false;
end;
inc(Pixel1);
inc(Pixel2);
end;
Result:=not TheSame;
end;
end;
Właczyłem test na wykonanie 10 000 razy na Bitmapie o wymiarach
500 X 500 pixeli no i procedura 2 z or ' ami okazała się szybsza za każdym razem o jakieś 1,7 sekundy
test przeprowadzany 20 krotnie na
Komputerze
AMD Athlon(tm) XP 1800+
1.50 GHz, 256 MB RAM System 32 bitowy
<b>
Do postu Szczawik'a:</b> też mnie to zdziwiło ale być może czytając jako DWORD procesor porównuje wszystkie 3 bajty natomiast w or'owych wyskakuje dalej zaraz po pierwszym bajcie niezgodnym i może stąd ta roznica ale to tylko być może :) nie wiem nie znam się , nie orientuje się :)
Po pierwsze ustawienie 32bit pozwoliłoby na wykonanie jednego porównania na DWORD zamiast trzech z'or'owanych porównań na byte (po to w ogóle stworzono bmp 32bit, zanim jeszcze wprowadzono kanał alpha). Trzeba jednak pamiętać, że w tym wszystkim najbardziej czasochłonną operacją nie jest znalezienie różnic, ale zmiana głębi kolorów. Gdy bitmapy są już w głębi docelowej, wtedy można porównywać szybkość.
Pod drugie, skoro znamy kolejność przechodzenia w osi Y (tu rosnąco), to przy wykryciu różnicy nie trzeba sprawdzać, czy (StopY<Y), bo zawsze jest co najwyżej równe.
Przy odliczaniu pętlą w dół po obu osiach i skracając operacje w pętli mamy większe szanse na objęcie kodu przez cache procesora, a zatem być może nawet większy zysk szybkości.
Jesem kompletnym laikiem jeśli chodzi mi o programowanie. Potrzebny jest mi jednak program wykrywający zmiany na monitorze (np. odświeżenie i zmiana zawartości strony www). Nie wiem jak to zrobić- możnaby się pokusić (o ile nie ma prostszego rozwiązania) tworzenie co pewien czas screenów, i późniejsze porównywanie ich jako bitmapy (ale niestety nawet nie umiem wykorzystać podanego kodu). Prosiłbym o szczegółową pomoc. Z góry dziękuję