Перейти к содержимому
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 дня парюсь :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

попробуйте прогнать программу на кусках изображения размером 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 намного больше нуля!!! :(

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

cvCreateSeq

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

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

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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) и отпишусь! Тема не закрыта :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В исходнике 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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


/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)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

если не загонять в 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

если не загонять в 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;

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

OpenCv_homo.cpp

main.h

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

// Рисуем результат
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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Как-то видел статейку на хабре про 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]);

}

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

errornd.png

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×