Find a smaller bitmap in a larger bitmap using ScanLine? lazarus / 39-Graphics ---------------------------------------------------------------------- gwiesenekker · 2014-06-20 10:58 Hi, I am trying to find a smaller bitmap in a larger bitmap. The code below that compares the bitmaps pixel by pixel works but is very slow. I tried to use ScanLine to speed things up, but the code below that uses it never finds ScanLine[0]. I guess the problem is with these statements:       P := TheP + 3 * X;       if CompareByte(P, TheSmallP, 3 * TheSmallPicture.Bitmap.Width) = 0 then The bitmaps are 24-bit. As a final test I commented out these lines:   //ThePicture.Bitmap.Width := TheBitmap.Width;   //ThePicture.Bitmap.Height := TheBitmap.Height;   //ThePicture.Bitmap.Canvas.Draw(0, 0, TheBitmap); and replaced them with:   ThePicture.LoadFromFile(BitmapFileName); So now it tries to compare the same bitmaps using ScanLine but that also fails to find ScanLine[0]. Any ideas? Thanks, Gijsbert procedure TMyApplication.FindBitmap(BitmapFileName: string); var   hWnd: THandle;   hdcSrc: THandle;   DX, DY: Integer;   X, Y: Integer;   TheBitmap: TBitmap;   ThePicture: TPicture;   TheRect: TRect;   TheSmallPicture: TPicture;   Found: Boolean;   X1, Y1: Integer;   TheP, TheSmallP : pByteArray;   P: pByteArray; begin   hWnd := GetForeGroundWindow;   if hWnd = 0 then Exit;   hdcSrc := GetDCEx(hWnd, 0, 0);   GetWindowRect(hWnd, TheRect);   DX := TheRect.Right - TheRect.Left;   DY := TheRect.Bottom - TheRect.Top;   //writeln('width and height of foreground window: ', DX, ' ', DY);   //grab the bitmap of the foreground window   TheBitmap := TBitmap.Create;   TheBitmap.Width := DX;   TheBitmap.Height := DY;   BitBlt(TheBitmap.Canvas.Handle, 0, 0, TheBitmap.Width, TheBitmap.Height, hdcSrc, 0, 0, SRCCOPY);   //copy the bitmap in case it is black   ThePicture := TPicture.Create;   //ThePicture.Bitmap.Width := TheBitmap.Width;   //ThePicture.Bitmap.Height := TheBitmap.Height;   //ThePicture.Bitmap.Canvas.Draw(0, 0, TheBitmap);   ThePicture.LoadFromFile(BitmapFileName);   TheSmallPicture := TPicture.Create;   TheSmallPicture.LoadFromFile(BitmapFileName);   if ThePicture.Bitmap.PixelFormat = pf24Bit then writeln('24 bit');   if TheSmallPicture.Bitmap.PixelFormat = pf24Bit then writeln('24 bit');   //find bitmap using scanline   ExitCode := -1;   for Y := 0 to ThePicture.Bitmap.Height - TheSmallPicture.Bitmap.Height do   begin     TheP := ThePicture.Bitmap.ScanLine[Y];     TheSmallP := TheSmallPicture.Bitmap.ScanLine[0];     for X := 0 to ThePicture.Bitmap.Width - TheSmallPicture.Bitmap.Width do     begin       writeln('Scanline ', Y, ' ', X);       P := TheP + 3 * X;       if CompareByte(P, TheSmallP, 3 * TheSmallPicture.Bitmap.Width) = 0 then       begin         writeln('Found ScanLine 0');         Found := True;         //now compare the remaining scanlines         for Y1 := 1 to TheSmallPicture.Bitmap.Height - 1 do         begin           TheP := ThePicture.Bitmap.ScanLine[Y + Y1];           TheSmallP := TheSmallPicture.Bitmap.ScanLine[Y1];           P := TheP + 3 * X;           if CompareByte(P, TheSmallP, 3 * TheSmallPicture.Bitmap.Width) <> 0 then           begin             Found := False;             break;           end;         end;         if Found then         begin           writeln('Scanline found at ', X, ' ', Y);           writeln('1');           ExitCode := 1;           Exit;         end;       end;     end;   end;   writeln('0');   ExitCode := 0;   ExitCode := -1;   for X := 0 to ThePicture.Bitmap.Width - TheSmallPicture.Bitmap.Width do   begin     for Y := 0 to ThePicture.Bitmap.Height - TheSmallPicture.Bitmap.Height do     begin       if ThePicture.Bitmap.Canvas.Pixels[X, Y] = TheSmallPicture.Bitmap.Canvas.Pixels[0, 0] then       begin         Found := True;         for X1 := 0 to TheSmallPicture.Bitmap.Width - 1 do         begin           for Y1 := 0 to TheSmallPicture.Bitmap.Height - 1 do           begin             if not(ThePicture.Bitmap.Canvas.Pixels[X + X1, Y + Y1] = TheSmallPicture.Bitmap.Canvas.Pixels[X1, Y1]) then             begin               Found := False;               break;             end;           end;           if not Found then break;         end;         if Found then         begin           writeln('Pixel found at ', X, ' ', Y);           writeln('1');           ExitCode := 1;           Exit;         end;       end;     end;   end;   writeln('0');   ExitCode := 0; end; ---------------------------------------------------------------------- gwiesenekker · 2014-06-20 12:08 I added these debug statements: writeln('Width ', TheSmallPicture.Bitmap.Width); writeln('Delta ', Abs(Integer(TheSmallPicture.Bitmap.Scanline[1]) - Integer(TheSmallPicture.Bitmap.Scanline[0]))); The width of the bitmap is 147 pixels, but the delta between two scanlines is 444 bytes, which would mean 148 pixels if the bitmap is 24 bit. Why? Gijsbert ---------------------------------------------------------------------- gwiesenekker · 2014-06-20 12:57 I found the problem! The calls to CompareByte should be: CompareByte(TheP^[3 * X], TheSmallP^, 3 * TheSmallPicture.Bitmap.Width) Gijsbert