Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

как быстро сравнить 2 объекта типа tbitmap [D6, Win95/98, WinXP]


Страницы:   1 2

truntaev ©   (2003-11-21 10:19:00) 

Мастера, буду весьма признателен за помощь в следующем вопросе.
Как можно сравнить два объекта типа Tbitmap. Сравнение только
на предмет - идентичны ли два рисунка.
Собственно вся проблема сделать это быстро.
Использование ScanLine,  а затем поэлементное сравнение массивов
работает весьма медленно. Может кто-то умеет это делать с
помощью GDI функций...
На всякий случай: ntruntaev@hotbox.ru


bolegator   (2004-02-27 08:20:00) [1]

> Что можно улучшить (ускорить) в этом коде???
>    for y := 0 to BMp.Height -1 do
>    begin
>      P := BMp.ScanLine[y];
>    end;

dx:=BMp.ScanLine[0]-BMp.ScanLine[1]; // dx>0
   for y := 0 to BMp.Height -1 do
   begin
     inc(integer(P),dx)
   end;


Карелин Артем   (2003-11-24 10:01:00) [2]

При использовани компонентов, указанных выше мной можно получить попиксельную отрисовку кучи битмапов на подложке 720*576 с эффектами прозрачности, вычисляющимися тут же (мой алгоритм, основанный на попиксельном доступе к битмапу) и записью этого в авишник(поддержка этого не входит в тот набор) со скоростью 5 кадров в секунду на 900 целероне.


MBo   (2003-11-24 08:55:00) [3]

Не первый раз пишешь это чудо:
begin
  P1:= Bmp1.ScanLine[y];
end;
может, какой тайный смысл в этом есть?

формат битмапов такой же, как у экрана.
7 миллисекунд на один прогон по битмапам на AXP1900+
если внести в цикл и получение снимка экрана (раскомментировать A, закомм. B) - 53 миллисек. Так что драйвер hands.sys, видимо, глючит.


procedure TForm1.Button1Click(Sender: TObject);
var b1,b2:TBitmap;
   x,y,k:Integer;
   w:Integer;
   Equal:Integer;
   dc:HDC;
   t:Cardinal;
   p1,p2:Pointer;
begin
b1:=TBitmap.Create;
b2:=TBitmap.Create;
b1.Width:=1024;
b1.Height:=768;
b1.PixelFormat:=pf32bit;
//A
//t:=GetTickCount;
//for k:=1 to 100 do begin
 DC:=GetDC(0);
 BitBlt(b1.Canvas.Handle,0,0,1024,768,dc,0,0,srccopy);
 ReleaseDC(0,DC);
 b2.Assign(b1);
 Equal:=1;
 w:=b1.width*4;

//B
t:=GetTickCount;
for k:=1 to 100 do begin

 for y := 0 to B1.Height -1 do  begin
   P1:= B1.ScanLine[y];
   P2:= B2.ScanLine[y];
   if not CompareMem(p1,p2,w) then begin
     Equal:=0;
     Break;
   end;
 end;
end;
Caption:=Format('Одинаковы: %d Время: %d',[Equal,(GetTickCount-t) div 100]);
end;


Mihey   (2003-11-23 23:15:00) [4]

Юзай Graphic32, и всё будет нормально.


truntaev   (2003-11-23 20:09:00) [5]

Уважаемый, MBo, и все кто может объяснить не специалисту по графике!
к сожалению красивое сравнение не работает :
   if not CompareMem(p1,p2,w) then begin
     Equal:=False;
а может от того, что я просто не знаю, что такое ByesPerPoint?
Буду признателен за объяснение, но это не совсем проблема.
Может я просто морочу голову мастерам, но проблема в следующем:

bmp1:=TBitmap.Create;
{bmp1.Height:=600;
bmp1.Width:=800;
}
Bmp1.LoadFromFile('wallp.bmp'); // файл какой-то картинки на р.стол
for y := 0 to BMp1.Height -1 do
 begin
   P1:= BMp1.ScanLine[y];
 end;
Действительно шустренько работает.
После этого и следующий код работает быстро:

DC:=GetDC(0);
bitblt(bmp1.Canvas.Handle, 0, 0, 800, 600,DC, 0, 0, SRCCOPY);
for y := 0 to Bmp1.Height -1 do
 begin
   P1:= Bmp1.ScanLine[y];
 end;

Однако, если я пишу просто такой код, он тормозит со страшной силой:
Procedure proba;
Begin
 bmp1:=TBitmap.Create;
 bmp1.Height:=600;
 bmp1.Width:=800;
 DC:=GetDC(0);
 bitblt(bmp1.Canvas.Handle, 0, 0, 800, 600,DC, 0, 0, SRCCOPY);
 for y := 0 to Bmp1.Height -1 do
 begin
   P1:= Bmp1.ScanLine[y];
 end;
End
В чем тут дело?


Думкин   (2003-11-23 15:02:00) [6]


> [21] truntaev   (23.11.03 10:44)

МВо и является одним из авторов той статьи.


MBo   (2003-11-23 12:13:00) [7]

>Если bmp.Width=800, а BMp.Height=600 этот код и работает
пару секунд.

Чудеса рассказываешь...

Вот набросок сравнения:

Equal:=true;
w:=bmp.width*ByesPerPoint;
for y := 0 to BMp.Height -1 do
  begin
    P1:= BMp.ScanLine[y];
    P2:= BMp2.ScanLine[y];
    if not CompareMem(p1,p2,w) then begin
      Equal:=False;
      Break;
    end;
  end;


truntaev   (2003-11-23 10:44:00) [8]

Я прочитал, что MBo - дока в вопросах графики. Поэтому
вопрос конкретный. Что можно улучшить (ускорить) в этом
коде???
   for y := 0 to BMp.Height -1 do
   begin
     P := BMp.ScanLine[y];
   end;

Если bmp.Width=800, а BMp.Height=600 этот код и работает
пару секунд.

А вообще приятно и любопытно почитать высказывания умных
людей по этому вопросу. Спасибо.
Думкину > Пойду почитаю предложенную статью. Я сначала ссылку
пропустил - теперь время.


miek   (2003-11-23 09:49:00) [9]

Если сравнение одно, то да, а вот когда ему надо их десятками сравнивать, то где-то так и должно быть.


MBo   (2003-11-23 08:01:00) [10]

>Попробуйте просто отработать с двумя битмапами
800х600. Это секунды 2-3 на 1Гц процессоре. Медленно это

Так я и подозревал...
Дело не в ScanLine, а в твоем коде - на гигагерцовой машине скорость со Scanline будет при правильном подходе в десятки-сто раз больше.


Думкин   (2003-11-22 19:28:00) [11]


> [16] miek ©   (22.11.03 17:56)
> Думкин, не переходи на личности.

А я имею дело не с личностью? Извини. Кстати и не переходил - простот - вопрос почитай и подумамй. Без обид.
Человек конкретно спросил - не мути воду в Байкале.


> [17] truntaev   (22.11.03 18:47)
> К сожалению все три примера построены на работе пресловутой ScanLine.

Эти примеры - да. Но статью глянь - там несколько иначе. Почитай - не пожалеешь.


truntaev   (2003-11-22 18:47:00) [12]

Мужики, благодарю за внимание к вопросу и помощь.
К сожалению все три примера построены на работе пресловутой
ScanLine. Попробуйте просто отработать с двумя битмапами
800х600. Это секунды 2-3 на 1Гц процессоре. Медленно это...
Хотя бы 300 Мс получить.


miek   (2003-11-22 17:56:00) [13]

Думкин, не переходи на личности.

И вообще, вы все свихнулись на сканлиниях, что ли? Типа круто?

---------
M> Как? Имеешь ввиду сделать цвет на единичное значение отличающимся?

Именно. А еще есть такая штука, как палитра.

Еще раз говорю - сравнивать два изображения, о содержании которых заранее ничего не известно - это задача для суперкомпов. Если известно, тогда, впрочем, другое дело. Сравнил размеры, потом пару пикселей из заранее заданных ключевых точек и все.


Fenik   (2003-11-22 15:56:00) [14]

>Думкин ©  (22.11.03 13:44) [13]

Хотя, конечно, для еще большего ускорения нужно воспользоваться вышеуказанной статьей.


Fenik   (2003-11-22 15:52:00) [15]

>Думкин ©  (22.11.03 13:44) [13]

Тогда можно эту усовершенствовать. Сверяем строки снизу и сверху одновременно, сходясь к середине.
Т.о. вероятност обнаружить разницу больше, и разные картинки отсеиваются быстро.

functionBOB2(B1, B2: TBitmap): Boolean;
varx, y, n, h, hend: Integer;
   p1, p2, p3, p4: pByteArray;
begin
 Result := False;
  if(B1.Width <> B2.Width) or(B1.Height <> B2.Height) thenExit;
 B1.PixelFormat := pf24Bit;
 B2.PixelFormat := pf24Bit;
 h := B1.Height;
 hend := h div2 + h mod2;
 Dec(h);
  fory := 0 tohend do begin
   p1 := B1.ScanLine[y];
   p2 := B2.ScanLine[y];
   p3 := B1.ScanLine[h - y];
   p4 := B2.ScanLine[h - y];
    forx := 0 toB1.Width - 1 do begin
     n := x*3;
      if(p1[n]<>p2[n]) or(p1[n+1]<>p2[n+1]) or(p1[n+2]<>p2[n+2]) or
        (p3[n]<>p4[n]) or(p3[n+1]<>p4[n+1]) or(p3[n+2]<>p4[n+2]) thenExit;
    end;
  end;
 Result := True;
end;


Кстати, если это поисковик иконок, который отсеивает одинаковые, то можно сортировать иконки, например, по цвету цетрального пикселя, и сверять уже только соответствующие экземпляры. Думаю, идея понятна.


Думкин   (2003-11-22 13:44:00) [16]


> [11] Fenik ©   (22.11.03 12:07)

Читаем:

> Собственно вся проблема сделать это быстро.
> Использование ScanLine,  а затем поэлементное сравнение
> массивов работает весьма медленно.


Dima1   (2003-11-22 13:16:00) [17]

Это не мое, когдато уже встречалось в форуме.
Может поможет
---------

набросок для 24-битных картинок (для других форматов еще проще),
результат от 0 до 1 при полном совпадении

function CompareBmp24(bmp1, bmp2: TBitmap): Double;
var
i, j, Sum: Integer;
SLine1, SLine2: PByteArray;
begin
Assert((bmp1.PixelFormat = pf24bit) and (bmp2.PixelFormat = pf24bit),
  '24bit only!');
Assert((bmp1.Width <> 0) and (bmp1.Height <> 0), 'Empty bitmap!');
if (bmp1.Height <> bmp2.Height) or (bmp1.Width <> bmp2.Width) then
begin
  Result := 0;
  Exit;
end;
Sum := 0;
for i := 0 to bmp1.Height - 1 do
begin
  SLine1 := bmp1.ScanLine[i];
  SLine2 := bmp2.ScanLine[i];
  for j := 0 to bmp1.Width - 1 do
    if (PInteger(@SLine1[j * 3])^ and $FFFFFF00) =
      (PInteger(@SLine2[j * 3])^ and $FFFFFF00) then
        inc(Sum);
end;
Result := Sum / (bmp1.Width * bmp1.Height);
end;


Fenik   (2003-11-22 12:07:00) [18]

functionBitmapOfBitmap(B1, B2: TBitmap): Boolean;
varx, y, n: Integer;
   p1, p2: pByteArray;
begin
 Result := False;
  if(B1.Width <> B2.Width) or(B1.Height <> B2.Height) thenExit;
 B1.PixelFormat := pf24Bit;
 B2.PixelFormat := pf24Bit;
  fory := 0 toB1.Height - 1 do begin
   p1 := B1.ScanLine[y];
   p2 := B2.ScanLine[y];
    forx := 0 toB1.Width - 1 do begin
     n := x*3;
      if(p1[n]<>p2[n]) or(p1[n+1]<>p2[n+1]) or(p1[n+2]<>p2[n+2]) thenExit;
    end;
  end;
 Result := True;
end;


True, если растры абсолютно одинаковые,
False - если отличаются хоть на один пиксель.


Думкин   (2003-11-22 11:17:00) [19]

> [9] miek ©   (22.11.03 11:11)
Ты вопрос почитай и остальное. Ты как глухой на дискотеке.
Тебе про Фому, а ты все про Ерему. Какие образы?


miek   (2003-11-22 11:11:00) [20]

M> Как? Имеешь ввиду сделать цвет на единичное значение отличающимся?

Именно. А еще есть такая штука, как палитра.

Еще раз говорю - сравнивать два изображения, о содержании которых заранее ничего не известно - это задача для суперкомпов. Если известно, тогда, впрочем, другое дело. Сравнил размеры, потом пару пикселей из заранее заданных ключевых точек и все.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо