Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.05.16;
Скачать: CL | DM;

Вниз

как быстро сравнить 2 объекта типа tbitmap   Найти похожие ветки 

 
truntaev   (2003-11-21 10:19) [0]

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


 
MBo ©   (2003-11-21 13:32) [1]

Какая необходима скорость?


 
Карелин Артем ©   (2003-11-21 15:52) [2]

g32.org работает ну очень быстро с графикой.


 
miek ©   (2003-11-21 16:45) [3]

Никак. Быстро только кошки родятся, а распознавание образов не фунт изюма.


 
Mihey ©   (2003-11-21 19:50) [4]

>Быстро только кошки родятся, а распознавание образов не фунт изюма.

Зря наругал человека. Он же ясно пишет:

>Сравнение только на предмет - идентичны ли два рисунка.


 
miek ©   (2003-11-21 20:33) [5]

Извиняюсь, если что. Но идентичность понятие тоже ОЧЕНЬ растяжимое. Может быть два битмапа, в которых ни один байт не совпадет, а на вид будут идентичны. Догадались, как, или пример привести? Задача решается только примеами распознавания образов. Кто сумеет сделать быстро и качественно - пускай идет давать зайвку на нобелевку.


 
Mihey ©   (2003-11-21 20:43) [6]

>Догадались, как, или пример привести?

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


 
wicked ©   (2003-11-21 21:13) [7]

навскидку, т. е. могуть быть неправильными или недостаточно быстрыми:
1. проксорить с помощью BitBlt, подсчитать количество 0 пикселей...
2. ScanLine + REP CMPSD...


 
Думкин ©   (2003-11-22 05:41) [8]


> [5] miek ©   (21.11.03 20:33)

Этой фразой сказано все:

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

Ни о каких образах речь не идет.
Можно посмотреть:
http://www.delphimaster.ru/articles/pixels/index.html
и ответить на вопрос МВо - он по ускоренной работе с графикой - дока.


 
miek ©   (2003-11-22 11:11) [9]

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

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

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


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

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


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

function BitmapOfBitmap(B1, B2: TBitmap): Boolean;
var x, y, n: Integer;
   p1, p2: pByteArray;
begin
 Result := False;
 if (B1.Width <> B2.Width) or (B1.Height <> B2.Height) then Exit;
 B1.PixelFormat := pf24Bit;
 B2.PixelFormat := pf24Bit;
 for y := 0 to B1.Height - 1 do begin
   p1 := B1.ScanLine[y];
   p2 := B2.ScanLine[y];
   for x := 0 to B1.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]) then Exit;
   end;
 end;
 Result := True;
end;


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


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

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

набросок для 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;


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


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

Читаем:

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


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

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

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

function BOB2(B1, B2: TBitmap): Boolean;
var x, y, n, h, hend: Integer;
   p1, p2, p3, p4: pByteArray;
begin
 Result := False;
 if (B1.Width <> B2.Width) or (B1.Height <> B2.Height) then Exit;
 B1.PixelFormat := pf24Bit;
 B2.PixelFormat := pf24Bit;
 h := B1.Height;
 hend := h div 2 + h mod 2;
 Dec(h);
 for y := 0 to hend do begin
   p1 := B1.ScanLine[y];
   p2 := B2.ScanLine[y];
   p3 := B1.ScanLine[h - y];
   p4 := B2.ScanLine[h - y];
   for x := 0 to B1.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]) then Exit;
   end;
 end;
 Result := True;
end;


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


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

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

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


 
miek ©   (2003-11-22 17:56) [16]

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

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

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

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

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


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

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


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


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

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


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

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


 
MBo ©   (2003-11-23 08:01) [19]

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

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


 
miek ©   (2003-11-23 09:49) [20]

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


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

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

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

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


 
MBo ©   (2003-11-23 12:13) [22]

>Если 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;


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


> [21] truntaev   (23.11.03 10:44)

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


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

Уважаемый, 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
В чем тут дело?


 
Mihey ©   (2003-11-23 23:15) [25]

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


 
MBo ©   (2003-11-24 08:55) [26]

Не первый раз пишешь это чудо:
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;



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

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


 
bolegator ©   (2004-02-27 08:20) [28]

> Что можно улучшить (ускорить) в этом коде???
>    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;



Страницы: 1 вся ветка

Текущий архив: 2004.05.16;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.031 c
4-1080393046
Deb
2004-03-27 16:10
2004.05.16
Изменение размеров и перетаскивание объектов на форме


8-1077984929
Spartak
2004-02-28 19:15
2004.05.16
TMediaPlayer


1-1083261874
Nous Mellon
2004-04-29 22:04
2004.05.16
Нестандартный ЛистВью


3-1082482969
neVIP.
2004-04-20 21:42
2004.05.16
Посоветуйте с SQL запросом...


1-1083225554
Dysan
2004-04-29 11:59
2004.05.16
опредиление кодировки