Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > Сравнение картинок


Автор: welt 19.5.2009, 23:22
Вобщем такая задача: Есть две картинки: большая и маленькая.
Маленькая  -это кусок картинки прямоугольного размера, вырезанный из большой каринки.
Нужно, найти, с какого места (координаты) малая картинка вырезана из большой. 
Для этого надо сравать в цикле попиксельно две картинки: вырезать из большой прямоугольнуюобласть и 
сравнивать с маленькой. Сравнивать по яркости пикселей. и так в цикле передвигаться по большой, вырезать из нее область
и сравнивать. Пр сравнении двух одинаковых по рамеру областец я складываю разность яркостей всех пикселей этих областей.
Если эта яркость равна нулю, то картинка найдена. Вроде написал, но очень медленно работает. Будет считать часов 5 или больше.
Может есть способ оптимизировать? или вообще другой способ. Код ниже...
 

Код


var
mPicture,bPicture,CMP_Picture:TPicture; //малая, большая, результативная
mHeight, mWidth, cWidth: Integer; //Размеры эталона
bHeight, bWidth, cHeight: Integer; //Размеры большой картинки
RIGHT_INF, BOTTOM_INF:integer; //правый и нижний пределы
i,j,k,m,p,L:integer;
II,JJ:Integer;  //координаты найденной картинки;

dR,dG,dB:byte;
dLIGHT:array[1..10000000] of Double    ; //массив разности яркостей
Lmin:Single; //минимальный элемент массива разности яркостей
size11:Single;
Rct_Dest,Rct_Source:TRect;

bcanvas:TCanvas;
begin

size11:=9;
//Создаем картинки
bPicture:=TPicture.Create;
mPicture:=TPicture.Create;
CMP_Picture:=TPicture.Create;

bPicture.LoadFromFile('image_big.bmp');
mPicture.LoadFromFile('image_small.bmp');


//Считываем размеры
mHeight:=mPicture.Height;
mWidth:=mPicture.Width;
cHeight:=mHeight;
cWidth:=mWidth;
bHeight:=bPicture.Height;
bWidth:=bPicture.Width;

CMP_Picture.Bitmap.Height:=mHeight;
CMP_Picture.Bitmap.Width:=mWidth;
size11:=1/(mHeight*mWidth);

//Ограничения в цикле
RIGHT_INF:=bWidth-mWidth;
BOTTOM_INF:=bHeight-mHeight;
//showmessage(inttostr(bWidth)+' '+inttostr(mWidth));

//Инициализация
i:=0; j:=0; k:=0; m:=0; L:=0;

bCanvas:=bPicture.Bitmap.Canvas;//.Create;

for j:=0 to BOTTOM_INF do
 begin
  for i:=0 to BOTTOM_INF do
   begin
    writeln(i, ' ', j);
   //Область, в которую копируем
    Rct_Dest:=Rect(0,0,CMP_Picture.Width,CMP_Picture.Height);
   //Откуда копируем 
    Rct_Source:=Rect(i,j,mWidth+i,mHeight+j);
    CMP_Picture.Bitmap.Canvas.CopyRect(Rct_Dest,bCanvas,Rct_Source);

//-----теперь в цикле сравниваем две мелкие картинки
    for L:=1 to mHeight-1 do
     for m:=1 to mWidth-1 do
      begin
       inc(k);
       dr:=GetRValue(CMP_Picture.Bitmap.Canvas.Pixels[m,L]) -
              GetRValue(mPicture.Bitmap.Canvas.Pixels[m,L]);
       dg:=GetGValue(CMP_Picture.Bitmap.Canvas.Pixels[m,L]) -
              GetGValue(mPicture.Bitmap.Canvas.Pixels[m,L]);
       db:=GetBValue(CMP_Picture.Bitmap.Canvas.Pixels[m,L]) -
              GetBValue(mPicture.Bitmap.Canvas.Pixels[m,L]);
     //Записываем в массив разность яркостей. 
       dLIGHT[k]:=0.299*dr+0.587*dg+0.114*db;
      end; //for m
//--------------
   end; //for i
  Application.ProcessMessages;
 end; //for j

// goto ext;
p:=k;
k:=0;
//Находим минимальную разность
Lmin:=dLIGHT[1];
 for k:=1 to p do
   if dLIGHT[k]<Lmin then Lmin:=dLIGHT[k];
//Теперь, по номеру k надо найти координаты картинки, начиная с
// которых надо вырезать маленькую картинку из большой.
ii:=0; JJ:=0;
JJ:=(k div RIGHT_INF)+1;
II:=k-((JJ-1)*RIGHT_INF);

Rct_Dest:=Rect(0,0,CMP_Picture.{Bitmap.}Width,CMP_Picture.{Bitmap.}Height);
Rct_Source:=Rect(II,JJ,mWidth+II,mHeight+JJ);
CMP_Picture.Bitmap.Canvas.CopyRect(Rct_Dest,bCanvas,Rct_Source);

CMP_Picture.Bitmap.SaveToFile('Result.bmp');

readln;
end.


Автор: Keeper89 19.5.2009, 23:27
Посмотрите это: http://www.swissdelphicenter.ch/torry/showcode.php?id=1635

Автор: welt 20.5.2009, 00:23
Keeper89
Видел я этот код. Он в сети повсюду. Но что-то неполучается его грамотно применить.
Я выделил линию, а потом к ней доступ по элементам x,y и опять тоже самое - долго, долго считает......

Автор: AntonN 20.5.2009, 00:36
долго потому что Canvas.Pixels[], можно переделать на bitmap.scanline, раз в десять быстрее будет smile

Автор: Keeper89 20.5.2009, 01:00
Посмотрите следующие ссылки по теме Image retrieval:
http://en.wikipedia.org/wiki/Image_retrieval
http://en.pudn.com/downloads107/ebook/detail442443_en.html

Вот то, о чем говорил AntonN:
http://www.delphisources.ru/pages/sources/database/2008-year/compare-pictures.html

Автор: Crw 20.5.2009, 16:22
1. Зачем вообще вырезать маленькую картинку если можно сразу сравнивать на большой?
2. Можно для начала сравнивать только верхний ряд пикселей - если не совпал, то смысла продолжать сравнивание нету и переносим начало координат дальше.

Автор: Keeper89 20.5.2009, 16:29
Цитата(Crw @  20.5.2009,  16:22 Найти цитируемый пост)
Зачем вообще вырезать маленькую картинку если можно сразу сравнивать на большой?

Вроде бы такое задание, она вырезана и надо определить откуда.

Автор: Crw 20.5.2009, 19:31
Ну это понятно, просто по коду:
bPicture - оригинальное изображение
mPicture - искомое изображение
CMP_Picture - сюда копируется изображение (CopyRect) из bPicture для сравнения с mPicture. Такой подход вообще никуда не годиться. На больших изображений количество таких отрисовок может быть несколько тысяч.
А окончание кода это что-то. Вообще совершенно ничего не понятно. 
Код

p:=k;
k:=0;
//Находим минимальную разность
Lmin:=dLIGHT[1];
 for k:=1 to p do
   if dLIGHT[k]<Lmin then Lmin:=dLIGHT[k];
//Теперь, по номеру k надо найти координаты картинки, начиная с
// которых надо вырезать маленькую картинку из большой.
ii:=0; JJ:=0;
JJ:=(k div RIGHT_INF)+1;

Зачем ищется Lmin если оно нигде не используется?
В этом коде k всегда будет равно p (которое вначале равно k). Это такой трюк чтобы усложнить понимание алгоритма? smile
П.С. Только не говорите что это рабочий алгоритм.. smile

Автор: welt 1.6.2009, 18:39
Crw
Надо было написать как-то так
Код

   if dLIGHT[k]<Lmin then begin Lmin:=dLIGHT[k]; p:=k; end;


А потом уже по номеру k вырезать картинку.
Что-то я ссылки почитал на статьи, но не смог переделать через scanline

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)