Jump to content
Compvision.ru
TroyashkA

Проблемы с ExtractSURF() и CvMemStorage

Recommended Posts

Всем привет! Задача следующая: необходимо выделить особенности методом SURF из пары спутниковых снимков высокого разрешения (порядка 20000x20000).

Для этого разбиваю каждое изображение на кусочки и из каждого тайла выделяю keypoints & descriptors. Но проблема заключается вот в чем ...

Сразу оговорюсь, что в коде три раза используется одна и та же часть изображения, но это не важно - важно то, что компилятор на 2 шаге цикла ругается: думаю, что не хватает памяти, так как поле allStorage->free_space = 0.

Вот код:


IplImage * second = cvLoadImage("D:\\IMGS\\LANSAT\\2.bmp", CV_LOAD_IMAGE_GRAYSCALE);


// получаю часть изображения 5000х5000 ===================================================================

IplImage * part = cvCreateImage(cvSize(5000, 5000), 8, 1); 

cvSetImageROI(second, cvRect(0,0, 5000, 5000));

cvCopy(second, part);

cvResetImageROI(second);

// =======================================================================================================


CvMemStorage* allStorage = cvCreateMemStorage(0); // место хранения последовательностей

CvSeq *allKeypoints = 0, *allDescriptors = 0; // последовательности


CvSURFParams params = cvSURFParams(1000, 1); // расширенные дескрипторы 128 элементов каждый (объясните разницу между расширенными и обычными, если не затруднит)


for(int i=0;i<3;i++)

{

	if (i==0)

	{

		cvExtractSURF( part, 0, &allKeypoints, &allDescriptors, allStorage, params );

	}

	if (i>0) // на последующих шагах выделяю текущие особенности и добавляю их в общие

	{

		CvMemStorage* currentStorage = cvCreateMemStorage(0);

		CvSeq *currentKeypoints = 0, *currentDescriptors = 0;


		cvExtractSURF( part, 0, &currentKeypoints, &currentDescriptors, currentStorage, params );


		cvSeqPushMulti(allKeypoints, currentKeypoints, currentKeypoints->total); // собственно само добавление

		cvSeqPushMulti(allDescriptors, currentDescriptors, currentDescriptors->total); // <----- а вот тут эта самая ошибка - видимо уже не хватает памяти (allStorage->free_space = 0)


		cvReleaseMemStorage(&currentStorage);

	}

}


return 0;

Помогите с проблемой, уже 2 дня парюсь :(

Share this post


Link to post
Share on other sites

попробуйте прогнать программу на кусках изображения размером 640х480, 800х600 и так далее пока не глюкнется, если дело в размере изображения, то с меньшими кусками все будет работать.

По поводу вычисления дескрипторов, вот тут с картинками: http://pixhawk.ethz.ch/wiki/software/computer_vision/surf_features

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

Share this post


Link to post
Share on other sites

попробуйте прогнать программу на кусках изображения размером 640х480, 800х600 и так далее пока не глюкнется, если дело в размере изображения, то с меньшими кусками все будет работать.

По поводу вычисления дескрипторов, вот тут с картинками: http://pixhawk.ethz.ch/wiki/software/computer_vision/surf_features

Поставил размер части 800x600:

IplImage * part = cvCreateImage(cvSize(800, 600), 8, 1); 

cvSetImageROI(second, cvRect(0,0, 800, 600));

cvCopy(second, part);

cvResetImageROI(second);

На третьем шаге та же самая ошибка, причем allStorage->free_space намного больше нуля!!! :(

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

Моя последующая задача - вычисление матрицы преобразования гомографии, трансформация одного из снимков на основе полученной матрицы и объединение снимков воедино ... Правильно ли будет работать с уменьшенной копией снимков ? Что скажете ?

Share this post


Link to post
Share on other sites

По моему не хватает в этом коде:

cvCreateSeq

память под последовательности (allKeypoints и allDescriptors) не выделена , вот и глючит.

По поводу гомографии, точки еще надо будет сопоставить, недавно выкладывал проект с вычислением гомографии.

  • Like 1

Share this post


Link to post
Share on other sites

По моему не хватает в этом коде:

cvCreateSeq

память под последовательности (allKeypoints и allDescriptors) не выделена , вот и глючит.

Как я понимаю, при выделении памяти под каждую последовательность придется использовать 2 разных буфера (2 экземпляра CvMemStorage) ?

То есть вот как-то так?

CvMemStorage* storageOne = cvCreateMemStorage(0);

CvMemStorage* storageTwo = cvCreateMemStorage(0);


CvSeq *allKeypoints = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storageOne);

CvSeq *allDescriptors = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storageTwo);

По поводу гомографии, точки еще надо будет сопоставить, недавно выкладывал проект с вычислением гомографии.

А точки я уже сопоставил, эту тему я обязательно еще подниму. Пока что только поделюсь работой моей программки:

pp2x.th.jpg

pp1.th.jpg

outg.th.jpg

p.s. Спасибо за помощь, как только освобожусь - попробую таким образом (выделить память под keys&desc) и отпишусь! Тема не закрыта :)

Share this post


Link to post
Share on other sites

В исходнике opencv (SURF.cpp) последовательности создаются так:

CvSeq* points = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSURFPoint), storage );

и так:

int descriptor_size = params.extended ? 128 : 64;

const int descriptor_data_type = CV_32F;

N = keypoints->total;

if( _descriptors )

{

descriptors = cvCreateSeq( 0, sizeof(CvSeq),

descriptor_size*CV_ELEM_SIZE(descriptor_data_type), storage );

cvSeqPushMulti( descriptors, 0, N );

}

  • Like 1

Share this post


Link to post
Share on other sites

Рано радовался ... Вообщем те же глюки. Вот весь код (В коде ничего особо сложного нет - просто берется одно большое изображение, из него копируется часть, из которой получаю ключевые особенности, далее выделяется еще часть и т.д. Иными словами картинка обрабатывается по частям):


/quote]

Причем заметил, что для Keypoints размер элемента равен 24, НО для Descriptors размер вовсе не 64 или 128, а 256 (а то и все 512, при флаге 1 в cvSURFParams) ! Поэтому в коде делаю вот так:
CvSeq *allKeypoints = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvSURFPoint), storageOne);

CvSeq *allDescriptors = cvCreateSeq(0, sizeof(CvSeq), 256, storageTwo);
p.s. а для типа CvSURFPoint делать вот так нельзя:
CvSeq *allKeypoints = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storageOne);

CvSeq *allDescriptors = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storageTwo);

p.p.s. Снимки прилагаются --->>> http://rghost.ru/download/4725080/63fd37b7c49675ce2eabaab462ea787a1e500e72/LANSAT.rar (~35MB)

Share this post


Link to post
Share on other sites

Вот это : descriptor_size*CV_ELEM_SIZE(descriptor_data_type) из поста выше объяснит размер элемента дескриптора.

Подстановки: descriptor_size*sizeof(float)=64*(32/8)=64*4=256 для обычного дескриптора и в два раза больше для расширенного.

  • Like 1

Share this post


Link to post
Share on other sites

Вот это : descriptor_size*CV_ELEM_SIZE(descriptor_data_type) из поста выше объяснит размер элемента дескриптора.

Спасибо! Я сегодня рассеянный ... учту это в дальнейшем ... а сейчас хотелось бы узнать что я делаю не так :(

Share this post


Link to post
Share on other sites

Сейчас загружу картинки, и посмотрю что там глючит :)

Share this post


Link to post
Share on other sites

Сейчас загружу картинки, и посмотрю что там глючит :)

Ого! Отлично - гляньте что там, а то у меня уже мозг отказывается работать - подсказывает, что утро вечера мудренее. Я обязательно прочту ваще сообщение завтра утром! Спасибо - Вы весь день мне помогаете :)

Share this post


Link to post
Share on other sites

Выяснилось вот что:

если не загонять в currentDescriptors больше определенного числа элементов за раз (надо копать, с чем связано не знаю), то все проходит нормально. Вот если поставить такое условие:

if(currentDescriptors->total<235)

(цифру подобрал близкую к рабочему максимуму), то все работает.

Может там ограничение по объему передаваемых данных.

ЗЫ: И еще MaxPart... надо привести к действительному виду, иначе ерунда при делении будет. Должно быть так:

		// получаем количество шагов ===============================
int stepY = ceil((double)image->height/(double)MaxPartHeight);
int stepX = ceil((double)image->width/(double)MaxPartWidth);
// =========================================================[/code]

  • Like 1

Share this post


Link to post
Share on other sites

Выяснилось вот что:

если не загонять в currentDescriptors больше определенного числа элементов за раз (надо копать, с чем связано не знаю), то все проходит нормально. Вот если поставить такое условие:

if(currentDescriptors->total<235)

(цифру подобрал близкую к рабочему максимуму), то все работает.

Может там ограничение по объему передаваемых данных.

ЗЫ: И еще MaxPart... надо привести к действительному виду, иначе ерунда при делении будет. Должно быть так:

		// получаем количество шагов ===============================

                int stepY = ceil((double)image->height/(double)MaxPartHeight);

                int stepX = ceil((double)image->width/(double)MaxPartWidth);

                // =========================================================
Упс, забыл привести к типу double ... Еще исправил ошибку:

                        //Неправильно --->

                          X+=MaxPartHeight;

                        }

                        Y+=MaxPartWidth;
Надо так:
				//X+=MaxPartHeight;

				X+=MaxPartWidth;

			}

			//Y+=MaxPartWidth;

			Y+=MaxPartHeight;

Теперь попробую затестить ...

Share this post


Link to post
Share on other sites

Выделил особенности, но вот беда - получаю неправильные значения матрицы преобразования гомографии :( Попробую немного другим способом ...

Share this post


Link to post
Share on other sites

Вот тот проект, о котором говорил. Посмотрите, может пригодится.

И еще вопрос, вы склеиваете большие куски? Если да, то координаты найденных точек смещать надо (добавить координаты куска в общем полотне).

OpenCv_homo.cpp

main.h

  • Like 1

Share this post


Link to post
Share on other sites

Вот тот проект, о котором говорил. Посмотрите, может пригодится.

И еще вопрос, вы склеиваете большие куски? Если да, то координаты найденных точек смещать надо (добавить координаты куска в общем полотне).

Интересный код ... а склеиваю я эти большие куски 1.bmp и 2.bmp. То есть, при получении тайла (кусочка) и выделения из него особенностей - эти особенности надо редактировать (смещать координаты)?

Только вот я не знаю, где в них хранятся координаты точек (еще плохо знаю тип CvSeq).

Share this post


Link to post
Share on other sites

Я рисовал точки так:

// Рисуем результат
for(int i = 0; i < (imageKeypoints ? imageKeypoints->total : 0); i++ )
{
CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( imageKeypoints, i );
int r=r1->size/2;
cvCircle( Grab, cvPointFrom32f(r1->pt), 3, CV_RGB(0,255,0));
cvLine( Grab, cvPointFrom32f(r1->pt),
cvPoint(r1->pt.x+r*cos(r1->dir*M_PI/180.0),
r1->pt.y+r*sin(r1->dir*M_PI/180.0)),
CV_RGB(255,0,0), 1, 8 );
}[/code]

  • Like 1

Share this post


Link to post
Share on other sites

Как-то видел статейку на хабре про SURF + надо почитать то, что Вы скинули, а то теория у меня не прокачана :) Пойду читать теорию!

UPD:

Почитал статейку про SURF, нашел вот что:

После нахождения ключевых точек, SURF формирует их дескрипторы. Дескриптор представляет собой набор из 64(либо 128) чисел для каждой ключевой точки.

Да и только сейчас заметил вот это:

descriptor_size*CV_ELEM_SIZE(descriptor_data_type) из поста выше объяснит размер элемента дескриптора.

Подстановки: descriptor_size*sizeof(float)=64*(32/8)=64*4=256 для обычного дескриптора и в два раза больше для расширенного.

И еще вопрос, вы склеиваете большие куски? Если да, то координаты найденных точек смещать надо (добавить координаты куска в общем полотне).

Сделал вот так:

cvExtractSURF( part, 0, &currentKeypoints, &currentDescriptors, currentStorage, params );


for (int i = 0;i<currentKeypoints->total; i++)

{

	CvSURFPoint* point = (CvSURFPoint*)cvGetSeqElem( currentKeypoints, i );


	point->pt.x += X;

	point->pt.y += Y;


	cvSeqPush(allKeypoints, point);

}


for (int i = 0;i<currentDescriptors->total; i++)

{

	cvSeqPush(allDescriptors, &currentDescriptors[i]);

}

И получаю неправильный результат :(

Share this post


Link to post
Share on other sites

Можешь выложить свой последний вариант кода с вычислением матрицы гомографии?

Share this post


Link to post
Share on other sites

Запустил стандартный пример с твоими изображениями "find_obj.exe object.jpg image.jpg" - соответствия между дескрипторами находятся верно.

Share this post


Link to post
Share on other sites

Запустил стандартный пример с твоими изображениями "find_obj.exe object.jpg image.jpg" - соответствия между дескрипторами находятся верно.

Да я даже не сомневался, так как часть кода у меня из примеров OpenCV. Проблема в другом - мне необходимо обрабатывать изображения с высоким разрешением. И если вы запустите тот же find_obj.exe с двумя другими изображениями с высоким разрешением, которые я выкладывал тут

то результат будет такой:

errornd.png

Не хватает памяти, приходится обрабатывать изображение по частям. А при выделении ключевых точек/дескрипторов методом SURF "по частям" особенности получаются неправильно :( Задачка то банальная - разделение изображения на тайлы и выделение из каждого особенностей.

Share this post


Link to post
Share on other sites

небось cvReleaseImage(&img); забываешь

сколько памяти на компе?

так же интересует вопросы:

1.Как реализовывается своп на хард если действительно не хватает памяти? (я так понимаю это надо делать сторонними методами)

2.Opencv работает многопоточно?если нет то как это реализовать?(а то у меня все выполняется на 1 ядре походу)

попозже постараюсь выложить свой проект с SURF на opencv2.1

Share this post


Link to post
Share on other sites

небось cvReleaseImage(&img); забываешь

сколько памяти на компе?

Спутниковые снимки сейчас весят ~100MB. Хотя в реале размер будет доходить до ~1GB. Сама функция cvExtractSURF() не справляется с такими большими изображениями.

ОЗУ 4GB, Система Windows 7 конечно же x64, виртуальной памяти выделено ~30GB

з.ы. проект можно скачать тут

Share this post


Link to post
Share on other sites

и да еще вопрос я так понимаю, что снимки то потом будут склеиваться? (если так то можно не по всему изображению искать, а только по предполагаемой области перекрытия)

cvExtractSURF() сколько точек находит?

Share this post


Link to post
Share on other sites

и да еще вопрос я так понимаю, что снимки то потом будут склеиваться? (если так то можно не по всему изображению искать, а только по предполагаемой области перекрытия)

Да, снимки будут трансформироваться в соответствии с полученной матрицей преобразования гомографии, а потом склеиватся. А область еще найти нужно. А как найти? Тем же выделением особенностей. И опять приходим к тому, что необходимо делить картинку на тайлы и из каждого получать точки&дескрипторы.

cvExtractSURF() сколько точек находит?

По-разному, зависит от размера тайла. Но одно ясно - при разделении на тайлы, в результате находит он их (точки) не верно.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×