Модераторы: Snowy, Alexeis, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Быстрый поиск на изображении. Deformable Template Model 
:(
    Опции темы
CynicRus
Дата 17.9.2014, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 248
Регистрация: 31.5.2012

Репутация: 2
Всего: 5



Приветствую уважаемых форумчан. Решаю задачу поиска заранее определенного объекта на изображении. Изображение может быть как большим, так и не очень(скриншот экрана или окна). Для этих целей использую импровизацию на тему Deformable Template Model алгоритма. 
Класс точки на изображеннии определен как:
Код

TDTMPoint = class
private
  Fx: Integer;
  FY: Integer;
  FColor: Integer;
  FTolerance: integer;
  FAreaSize: integer;
  FBp: boolean;
public
  procedure Reset;
  constructor Create;
  procedure DrawToCanvas(Render: TCanvas;aColor,Width,Height: integer);
  property x: Integer read Fx write Fx;
  property y: Integer read FY write FY;
  property Color: Integer read FColor write FColor;
  property Tolerance: Integer read FTolerance write FTolerance;
  property AreaSize: integer read FAreaSize write FAreaSize;
  property Bp: boolean read FBp write FBp;
end;

Где x,y: точка на изображении(0,0 для главной), Color - ожидаемый цвет, Tolerance - допустимое отклонение цвета, AreaSize - размер площади точки в пикселях.

Соответственно базовый класс состоит из главной DTMточки, и подчиненного ей массива DTMТочек. В массиве поля x,y содержат смещение по x и y до главной точки. 



Ищу это по изображению следующим образом:
Код

function TFinder.FindDTMs(DTM: TDTMS; out Points: TPointArray; x1, y1, x2, y2, maxToFind: Integer): Boolean;
var
  Len: integer;
  b: array of array of Integer;
  ch: array of array of integer;
  W, H: integer;
  MA: TBox;
  MaxX, MaxY: integer;
  xx, yy: integer;
  i, xxx, yyy: Integer;
  StartX, StartY, EndX, EndY: integer;
  pc: Integer;
  Found: boolean;
  goodPoints: array of Boolean;
  col_arr, tol_arr: array of Integer;
  ctsinfoarray: TCTSInfoArray;
  compare: TCTSCompareFunction;
  BMP: TDTMBitmap;

label
  theEnd;

label
  AnotherLoopEnd;
begin
  pc := 0;
  SetLength(FClientTPA, 0);
  MA := ValidMainPointBox(DTM, x1, y1, x2, y2);
  Len := dtm.points.Count;
  setlength(goodPoints, Len);
  for i := 0 to Len - 1 do
    goodPoints[i] := not DTM.Points[i].bp;
  W := x2 - x1;
  H := y2 - y1;
  setlength(b, (W + 1));
  setlength(ch, (W + 1));
  for i := 0 to W do
  begin
    setlength(ch[i], (H + 1));
    FillChar(ch[i][0], SizeOf(Integer) * (H + 1), 0);
    setlength(b[i], (H + 1));
    FillChar(b[i][0], SizeOf(Integer) * (H + 1), 0);
  end;
  SetLength(col_arr, Len);
  SetLength(tol_arr, Len);
  for i := 0 to Len - 1 do
  begin
    col_arr[i] := DTM.Points[i].color;
    tol_arr[i] := DTM.Points[i].tolerance;
  end;
  ctsinfoarray := Create_CTSInfoArray(col_arr, tol_arr);
  compare := Get_CTSCompare(Self.CTS);
  BMP := Target.CopyBitmap(x1, y1, x2, y2);
  UpdateCachedValues(BMP.Width, BMP.Height);
  MA.x1 := x1;
  MA.y1 := y1;
  MA.x2 := x2;
  MA.y2 := y2;
  MaxX := x2 - x1;
  MaxY := y2 - y1;
  for yy := MA.y1 to MA.y2 - 1 do
    for xx := MA.x1 to MA.x2 - 1 do
    begin
      for i := 0 to Len - 1 do
      begin
        Found := false;
        StartX := max(0, xx - Dtm.Points[i].AreaSize + Dtm.Points[i].x);
        StartY := max(0, yy - Dtm.Points[i].AreaSize + Dtm.Points[i].y);
        EndX := Min(MaxX, xx + Dtm.Points[i].AreaSize + Dtm.Points[i].x);
        EndY := Min(MaxY, yy + Dtm.Points[i].AreaSize + Dtm.Points[i].y);
        for xxx := StartX to EndX do
        begin
          for yyy := StartY to EndY do
          begin
            if ch[xxx][yyy] and (1 shl i) = 0 then
            begin
              ch[xxx][yyy] := ch[xxx][yyy] or (1 shl i);
              if compare(ctsinfoarray[i], BMP.ScanLine[yyy] ^[xxx]) then
                b[xxx][yyy] := b[xxx][yyy] or (1 shl i);
            end;
            if (b[xxx][yyy] and (1 shl i) <> 0) then
            begin
              if GoodPoints[i] then
              begin
                Found := true;
                break;
              end
              else
                goto AnotherLoopEnd;
            end;
          end;
          if Found then
            Break;
        end;
        if (not found) and (GoodPoints[i]) then
          goto AnotherLoopEnd;
      end;
      ClientTPA[pc] := Point(xx, yy);
      Inc(pc);
      if (pc = maxToFind) then
        goto theEnd;
      AnotherLoopEnd:
    end;
  TheEnd: BMP.Free;
  Free_CTSInfoArray(ctsinfoarray);
  SetLength(Points, pc);
  if pc > 0 then
    Move(ClientTPA[0], Points[0], pc * SizeOf(TPoint));
  Result := (pc > 0);
end; 


И всё это работает, объект на изображении находится. При этом на небольших изображениях - работает довольно сносно, а вот на изображениях по крупнее , особенно если там не один объект - работает очень задумчиво. Собственно вопрос в том - каким образом оптимизировать поиск такой структуры на изображениях различных размеров?

PS: TDTMBitmap - просто объект, в одном из полей которого содержится массив с реальным битмапом в виде array of TRGBTriple.

PPS: как оно работает.

создаём модель для искомого участка на изображении:
user posted image

и по этой модели уже проводим поиск, в результате находим искомое. Ну или не находим, хотя если модель верно составлена, то объект находится всегда.

Это сообщение отредактировал(а) CynicRus - 17.9.2014, 10:15
PM MAIL   Вверх
drkot
Дата 18.9.2014, 11:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: нет
Всего: 8



Разбить код на подпрограммы и произвести профилирование.
Выявить что именно потребляет время. Хотя бы будет понятно, какой код оптимизировать.
В идеале на каждый поиск надо запускать отдельный поток.
Так же целесообразно использовать в качестве ключа не одну точку, а матрицу 3*3 (или 2*2). Это сократит количество "ложных" ветвлений.
Если предполагается искать несколько объектов, то также целесообразно преобразовать битмап в массив.

Добавлено через 1 минуту и 39 секунд
Цитата(CynicRus @  17.9.2014,  11:07 Найти цитируемый пост)
              if compare(ctsinfoarray[i], BMP.ScanLine[yyy] ^[xxx]) then

ScanLine вызывается на каздой итерации двойного цикла... жирновато как то....


--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Звук, графика и видео"
Girder
Snowy
Alexeis

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делится вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • По вопросам разработки игр стоит заглянуть сюда

FAQ раздела лежит здесь!


Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Girder, Snowy.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Звук, графика и видео | Следующая тема »


 




[ Время генерации скрипта: 0.0447 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.