![]() |
|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
![]() Добрый день коллеги! Очень прошу помочь!
Давно уже бьюсь, но никак не могу расколоть сабжевую проблему, гугл выдает некую информацию, но мне никак не удается ее адаптировать для своих нужд. Учтите, речь идет не о сравнении одного изображения с другим. Мне нужно организовать поиск одного изображения (маленького, порядка 100х50 пикселей) в другом - большом, порядка 1280х1024 пикселей, причем поиск должен осуществлятся максимально быстро < 1 сек. Результатом работы функкции должны быть координаты X,Y маленьгоко изображения в большом (исходном). Причем поиск долже выполнятся по полному схождению части большого изображения и маленького. Так как если искать по нескольки ключевых точек, то такие функции в моем случае дают сбой. Код:
procedure TForm1.Button4Click(Sender: TObject); Type TRGBTripleArray = ARRAY[WORD] OF TRGBTriple; pRGBTripleArray = ^TRGBTripleArray; var b1, b2: TBitmap; // c1, c2: PByteArray; c1, c2: pRGBTripleArray; x, y, i,: Integer; eq: boolean; resX, resY: integer; begin b1 := Image1.Picture.Bitmap; b2 := Image2.Picture.Bitmap; Assert(b1.PixelFormat = b2.PixelFormat); // they have to be equal for y := 0 to b1.Height - 1 do // Внешний цикл по строкам оригинала begin c1 := b1.Scanline[y]; c2 := b2.Scanline[0]; // Ищу на соответствие только по 1-й строке for x := 0 to b1.Width - 1 do begin eq := true; for i := 0 to b2.Width - 1 do // Цикл по строке искомой строки begin if (c1[x+i].RGBtRed <> c2[i].RGBtRed) or (c1[x+i].RGBtGreen <> c2[i].RGBtGreen) or (c1[x+i].RGBtBlue <> c2[i].RGBtBlue) then begin eq := false; break; end end; if ( eq ) then begin resX:=x; resY:=y; break; end; end; if ( eq ) then break; end; if ( eq ) then begin Memo1.Lines.Add('FOUND'); b1.canvas.Brush.Color := clRed; b1.canvas.Ellipse(resX-3, resY-3, resX+3, resY+3); end else Memo1.Lines.Add('NOT FOUND'); end; Этот код работает, но не быстро (в силу его примитивности и неоптимизированности) и ищет только по первой строке второго изображения. Как оптимально сделать чтобы он искал быстро по всем строкам под-изображения я еще не придумал. Есть другой вариант, с которым мне помогли, там очень быстро ищется под-изображение по 4-м точкам. Но этот алгоритм в силу его ограниченности часто дает сбой, а модифицировать его должным образом у меня не вышло. Код:
... ... PInt = ^integer; var Form1: TForm1; implementation {$R *.dfm} function SearchBitmap(const bmMain,bmSub:TBitmap; var Res:TPoint):boolean; var iMainHeight, iMainWidth, iSubHeight, iSubWidth, iMainPXWidth, iSubPXWidth, iDiffPXWidth, iDiffHeight: integer; i,j:integer; eq: boolean; pRowMain, pRowSub : PByteArray; ltPt,rtPt,lbPt,rbPt : PInt; cPoints:array[0..3] of integer; begin Res.X := -1; Res.Y := -1; SearchBitmap := false; bmMain.PixelFormat:=pf24bit; bmSub.PixelFormat:=pf24bit; iMainHeight := bmMain.Height; iMainWidth := bmMain.Width; iMainPXWidth := iMainWidth * 3; iSubHeight := bmSub.Height; iSubWidth := bmSub.Width ; iSubPXWidth := iSubWidth *3 ; iDiffPXWidth := iMainPXWidth - iSubPXWidth; iDiffHeight:= iMainHeight - iSubHeight; pRowSub := bmSub.ScanLine[0]; cPoints[0]:= PInt(@(pRowSub^[0]))^ and $FFFFFF; cPoints[1]:= PInt(@(pRowSub^[iSubPXWidth-3]))^ and $FFFFFF; pRowSub := bmSub.ScanLine[iSubHeight-1]; cPoints[2]:= PInt(@(pRowSub^[0]))^ and $FFFFFF; cPoints[3]:= PInt(@(pRowSub^[iSubPXWidth-3]))^ and $FFFFFF; eq:=false; for i:=0 to iDiffHeight - 1 do begin pRowMain := bmMain.ScanLine[i]; pRowSub := bmMain.ScanLine[i+iSubHeight-1]; j:=0; ltPt := PInt(@pRowMain^[j]); lbPt := PInt(@pRowSub^[j]); //rtPt := PInt(pRowMain + iSubPXWidth - 3); //rbPt := PInt(pRowSub + iSubPXWidth - 3); asm mov eax,iSubPXWidth sub eax,3 mov ecx,eax add ecx,ltPt mov rtPt,ecx mov ecx,eax add ecx,lbPt mov rbPt,ecx end; while j<iDiffPXWidth do begin { eq := ((PInt(@(pRowMain^[j]))^ and $FFFFFF) = cPoints[0]) and ((PInt(@(pRowMain^[j+iSubPXWidth-3]))^ and $FFFFFF) = cPoints[1]) and ((PInt(@(pRowSub^[j]))^ and $FFFFFF ) = cPoints[2]) and ((PInt(@(pRowSub^[j+iSubPXWidth-3]))^ and $FFFFFF) = cPoints[3]); } eq := ((ltPt^ and $FFFFFF) = cPoints[0]) and ((rtPt^ and $FFFFFF) = cPoints[1]) and ((lbPt^ and $FFFFFF) = cPoints[2]) and ((rbPt^ and $FFFFFF) = cPoints[3]); if ( eq ) then begin Res.X := j div 3; Res.Y := i; SearchBitmap := true; break; end; asm add ltPt,3 add rtPt,3 add lbPt,3 add rbPt,3 end; inc(j,3); end; if eq then break; end; end; function CaptureScreenRect(ARect : TRect) : TBitmap; var ScreenDC: HDC; begin Result:=TBitmap.Create; with result, ARect do begin Width:=Right-Left; Height:=Bottom-Top; ScreenDC:=GetDC(0); try BitBlt(Canvas.Handle, 0,0,Width,Height,ScreenDC, Left, Top, SRCCOPY ); finally ReleaseDC(0, ScreenDC); end; end; end; procedure Search(pattern: string; p_color: TColor); var bmMain, bmSub: TBitmap; startPoint: TPoint; c: TCanvas; begin c := TCanvas.Create; c.Handle := GetDC(0); bmMain := TBitmap.Create(); bmSub := TBitmap.Create(); try // image1.Picture.Bitmap := CaptureScreenRect(Rect(0,0,Screen.Width,Screen.Height)); bmMain := CaptureScreenRect(Rect(0,0,Screen.Width,Screen.Height)); // bmMain.LoadFromFile('screen_main.bmp'); bmSub.LoadFromFile(pattern); if (SearchBitmap(bmMain, bmSub, startPoint)) then begin c.Brush.Color := p_color; c.Ellipse(startPoint.x-3, startPoint.y-3, startPoint.x+3, startPoint.y+3); end; finally bmMain.Free; bmSub.Free; c.Free; end; end; |