![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
как быстро сравнить 2 объекта типа tbitmap [D6, Win95/98, WinXP]
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> Как? Имеешь ввиду сделать цвет на единичное значение отличающимся?
Именно. А еще есть такая штука, как палитра.
Еще раз говорю - сравнивать два изображения, о содержании которых заранее ничего не известно - это задача для суперкомпов. Если известно, тогда, впрочем, другое дело. Сравнил размеры, потом пару пикселей из заранее заданных ключевых точек и все.