Здравствуйте Аноним, Вы писали:
А>упс, вопрос — "N2 в N1" ?
Поиск вхождения должен быть точным или приблизительным (тоесть имеется полное совпадение пикселей или нет)?
Если нужно найти точно сопадающее вхождение, то самый простой вариант — делается GetDIBits для обоих картинок и делается последовательное сравнение картинок (поиск массива первой картинки в массиве второй картинки). Разумеется нужно учитывать размеры (геометрические) обоих картинок и использовать эти данные при поиске. Также необходимо учесть что картинки могут быть с индексироваными цветами (4, 8 BPP) тогда надо сравнивать не пиксели а их цвета в палитре.
Это все справедливо для случая, когда картинки имеют одинаковую глубину цвета и одна из них полностью идентична региону другой картинки, причем прямоугольному, а не произвольному.
Однако когда нет 100% вхождения, алгоритм поиска усложняется на порядки. Пример программы реализуещей такой подход — FineReader.
Re[3]: как сделать поиск одного битмапа в другом?
От:
Аноним
Дата:
06.06.02 07:36
Оценка:
Здравствуйте IgorK, Вы писали:
IK>Поиск вхождения должен быть точным или приблизительным (тоесть имеется полное совпадение пикселей или нет)?
здесь всё правильно — нужно найти точное вхождение прямоугольника N2 в прямоугольник N1
IK>Если нужно найти точно сопадающее вхождение, то самый простой вариант — делается GetDIBits для обоих картинок и делается последовательное сравнение картинок (поиск массива первой картинки в массиве второй картинки). Разумеется нужно учитывать размеры (геометрические) обоих картинок и использовать эти данные при поиске. Также необходимо учесть что картинки могут быть с индексироваными цветами (4, 8 BPP) тогда надо сравнивать не пиксели а их цвета в палитре.
вот здесь мне очень интересно как учитывать геометрические параметры. Судя по MSDN, GetDIBits копирует участок с некой строчки битмапа Nx с количеством y строк. Но ведь второй битмап отличается не только по длине, но и по ширине! Получается, максимум чего мы добьёмся — это сузим поиск по вертикали. А как его дальше осуществлять по горизонтали ? :???:
Здравствуйте Аноним, Вы писали:
А>вот здесь мне очень интересно как учитывать геометрические параметры. Судя по MSDN, GetDIBits копирует участок с некой строчки битмапа Nx с количеством y строк. Но ведь второй битмап отличается не только по длине, но и по ширине! Получается, максимум чего мы добьёмся — это сузим поиск по вертикали. А как его дальше осуществлять по горизонтали ? :???:
Зачем заранее сужать поиск вообще? Этим можно отрезать часть искомого вхождения :)
Просто получаем полные массивы на обе картинки и начиная с первого пикселя ищем вхождение.
Пусть I (от image) — это большая картинка, а P (от part) — это кусочек, который мы ищем в большой картинке. Также нам известны размеры картинок (sxI, syI, sxP, syP). Зададимся еще счетчиками xI, yI, xP, yP. pI и pP — указатели на массивы большой и маленькой картинок соотвественно.
Алгоритм примерно такой (псевдокод, почти С++ :) ):
Здравствуйте IgorK, Вы писали:
IK>Зачем заранее сужать поиск вообще? Этим можно отрезать часть искомого вхождения :) IK>Просто получаем полные массивы на обе картинки и начиная с первого пикселя ищем вхождение.
[skipped] IK>Ну вот и все вроде-бы...
ага, спасибочки. Алгоритм понятен. В общем, попиксельное сравнивание в циклах. Получается GetDIBits даже и не надо использовать. :-\
Есть одна проблема в таком случае. Сложность такого алгоритма будет sxI*syI*sxP*syP. При скромных размерах картинки 500х500 и её маленькой части 100х100 мы получаем порядка 10^10 шагов. Боюсь я, что это будет не совсем быстро даже на современных компьютерах :-\
Хорошо бы было использовать какой-нибудь API или стандартную (вылизанную) функцию. Например, как приятно искать вхождение подстроки в строку ;-) — strstr() и ни о чём не заботишься....
А>ага, спасибочки. Алгоритм понятен. В общем, попиксельное сравнивание в циклах. Получается GetDIBits даже и не надо использовать.
GetDIBits как раз вернет указатель на скопированный массив пикселей, это упрощает задачу.
А>Есть одна проблема в таком случае. Сложность такого алгоритма будет sxI*syI*sxP*syP. При скромных размерах картинки 500х500 и её маленькой части 100х100 мы получаем порядка 10^10 шагов. Боюсь я, что это будет не совсем быстро даже на современных компьютерах
При наихудшем стечении обстоятельств, алгоритм сделает (sxI-sxP)*(syI-syP)*sxP*syP итераций, но на самом деле все зависит от того, какая у тебя картинка. Да чего там говорить — это же проверить несложно. Ты реализуй — а потом нам раскажешь быстро это или нет
А>Хорошо бы было использовать какой-нибудь API или стандартную (вылизанную) функцию. Например, как приятно искать вхождение подстроки в строку — strstr() и ни о чём не заботишься....
Ну вот например интеловский код (точнее, кусочек кода) для Motion Estimation (MPEG). Я когда-то читал на сайте Интела.
В даннном алгоритме выполняется поиск макроблока, "подобного" требуемому, т.е. используется функция ошибки.
int PLogarithmicSearch(uint8* currentBlock,uint8* prev,int by,int bx,int* motionY,int* motionX)
{
int bestdifc=0x7fffffff,difc;
int bestdifm=0x7fffffff,difm;
int bestdifmm=0x7fffffff,difmm;
int upperMY, bottomMY;
int leftMX, rightMX;
int tempBottomMY, tempRightMX;
int spacing;
int centerX, centerY;
int newCenterX, newCenterY;
int newCenterXc, newCenterYc;
int newCenterXm, newCenterYm;
int newCenterXmm, newCenterYmm;
int mx, my;
int bestDiff = 0x7fffffff;
spacing = (logsearchRange+1)/2;
upperMY =0;
leftMX =0;
bottomMY=FRAME_HEIGHT - BLOCK_SIZE;
rightMX=FRAME_WIDTH - BLOCK_SIZE;
centerX = bx;
centerY = by;
while ( spacing >= stepSize )
{
newCenterY = centerY;
newCenterX = centerX;
tempBottomMY = bottomMY;
if ( centerY+spacing+1 < tempBottomMY )
{
tempBottomMY = centerY+spacing+1;
}
tempRightMX = rightMX;
if ( centerX+spacing+1 < tempRightMX )
{
tempRightMX = centerX+spacing+1;
}
for ( my = centerY-spacing; my < tempBottomMY; my += spacing )
{
if ( my < upperMY )
{
continue;
}
for ( mx = centerX-spacing; mx < tempRightMX; mx += spacing )
{
if ( mx < leftMX )
{
continue;
}
difmm= MotionErrorXMM(prev,currentBlock,mx,my,bestdifmm);
#ifdef C_MMX
difc= MotionErrorC(prev,currentBlock,mx,my,bestdifc);
difm= MotionErrorMMX(prev,currentBlock,mx,my,bestdifm);
if(difc < bestdifc)
{
newCenterYc = my;
newCenterXc = mx;
bestdifc=difc;
}
if(difm < bestdifm)
{
newCenterYm = my;
newCenterXm = mx;
bestdifm=difm;
}
#endif
if(difmm < bestdifmm)
{
newCenterYmm = my;
newCenterXmm = mx;
bestdifmm=difmm;
}
#ifdef C_MMX
if((bestdifc!=bestdifm)||(bestdifc != bestdifmm)||(bestdifm != bestdifmm))
{
fprintf(stderr, " EstBlock(%d,%d),refblock(%d,%d): bestdifc=%d,bestdifm=%d,
bestdifmm=%d \n",by,bx,my,mx,bestdifc,bestdifm,bestdifmm);
exit(1);
}
if((newCenterXc!=newCenterXm)||(newCenterXc!=newCenterXmm)||
(newCenterYc!= newCenterYm)||(newCenterYc!= newCenterYmm))
{
fprintf(stderr, "EstBlock(%d,%d),refblock(%d,%d):newCenterXc=%d,newCenterYc=%d,newCenterXm=%d,
newCenterYm=%d,newCenterXmm=%d,newCenterYmm=%d \n",
by,bx,my,mx,newCenterXc,
newCenterYc,newCenterXm,newCenterYm,newCenterXmm,newCenterYmm);
exit(1);
}
#endif
newCenterY = newCenterYmm;
newCenterX = newCenterXmm;
bestDiff = bestdifmm;
}
}
//moving center to best match block location
centerY = newCenterY;
centerX = newCenterX;
// update the spacing if ( spacing == 1 )
{
spacing = 0;
}
else
{
spacing = (spacing+1)/2;
}
}//while
*motionY = centerY;
*motionX = centerX;
return bestDiff;
}
Здравствуйте IgorK, Вы писали:
IK>При наихудшем стечении обстоятельств, алгоритм сделает (sxI-sxP)*(syI-syP)*sxP*syP итераций, но на самом деле все зависит от того, какая у тебя картинка. Да чего там говорить — это же проверить несложно. Ты реализуй — а потом нам раскажешь быстро это или нет
короче чего-то я накропал, вот только одна проблема — оно не работает
зря волновался, ищет достаточно быстро — при размерах картинок 640*480 и 80*80 соответственно успевает обработать где-то за 50мс. Правда думаю, что так как вхождение не находится, алгоритм лажается еще на первой строке маленького изображения.
вот собственно код на основе твоего псевдокода с исправленными неточностями :
Функции для работы с DIB взяты из чудного примера WINCAP.
Еще раз повторюсь — одна осталась проблема — ничего не находится. Даже на самом простом примере где и первая и вторая картинки просто одноцветная заливка, оно вторую не находит Битмапы цветные 24b. Нутром чувствую, где-то баг Но где ?
Здравствуйте visitant, Вы писали:
V>Ну вот например интеловский код (точнее, кусочек кода) для Motion Estimation (MPEG). Я когда-то читал на сайте Интела. V>В даннном алгоритме выполняется поиск макроблока, "подобного" требуемому, т.е. используется функция ошибки.
ой, как-то там всё сложно мне-бы чего попроще, а если сложное то чтобы сразу работало только подставь туда параметры да еще и знать какие
может ты хотя бы обьяснишь простым языком чего там происходит в этой процедуре ?
когда цикл в isEntry переходит на вторую строчку, то есть yP == 1, то вся синхронихация массива почему-то теряется — может +1 или -1 байт надо сдвигать ? тогда почему ?
Или вот какая идея — может в битмапе информация разверткой по вертикали а не по горизонтали ? :???: