TroyashkA 12 Report post Posted March 11, 2011 Всем привет! Задача следующая: необходимо выделить особенности методом 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, ¤tKeypoints, ¤tDescriptors, currentStorage, params ); cvSeqPushMulti(allKeypoints, currentKeypoints, currentKeypoints->total); // собственно само добавление cvSeqPushMulti(allDescriptors, currentDescriptors, currentDescriptors->total); // <----- а вот тут эта самая ошибка - видимо уже не хватает памяти (allStorage->free_space = 0) cvReleaseMemStorage(¤tStorage); } } return 0; Помогите с проблемой, уже 2 дня парюсь Share this post Link to post Share on other sites
Smorodov 579 Report post Posted March 11, 2011 попробуйте прогнать программу на кусках изображения размером 640х480, 800х600 и так далее пока не глюкнется, если дело в размере изображения, то с меньшими кусками все будет работать. По поводу вычисления дескрипторов, вот тут с картинками: http://pixhawk.ethz.ch/wiki/software/computer_vision/surf_features И еще можно предварительно уменьшить изображение, и найти дескрипторы. Все равно надо будет как то уменьшать их количество, а так останутся самые сильные. Share this post Link to post Share on other sites
TroyashkA 12 Report post Posted March 11, 2011 попробуйте прогнать программу на кусках изображения размером 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
Smorodov 579 Report post Posted March 11, 2011 По моему не хватает в этом коде: cvCreateSeq память под последовательности (allKeypoints и allDescriptors) не выделена , вот и глючит. По поводу гомографии, точки еще надо будет сопоставить, недавно выкладывал проект с вычислением гомографии. 1 Share this post Link to post Share on other sites
TroyashkA 12 Report post Posted March 11, 2011 По моему не хватает в этом коде: 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); По поводу гомографии, точки еще надо будет сопоставить, недавно выкладывал проект с вычислением гомографии. А точки я уже сопоставил, эту тему я обязательно еще подниму. Пока что только поделюсь работой моей программки: p.s. Спасибо за помощь, как только освобожусь - попробую таким образом (выделить память под keys&desc) и отпишусь! Тема не закрыта Share this post Link to post Share on other sites
Smorodov 579 Report post Posted March 11, 2011 В исходнике 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 ); } 1 Share this post Link to post Share on other sites
TroyashkA 12 Report post Posted March 11, 2011 Рано радовался ... Вообщем те же глюки. Вот весь код (В коде ничего особо сложного нет - просто берется одно большое изображение, из него копируется часть, из которой получаю ключевые особенности, далее выделяется еще часть и т.д. Иными словами картинка обрабатывается по частям): /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
Smorodov 579 Report post Posted March 11, 2011 Вот это : descriptor_size*CV_ELEM_SIZE(descriptor_data_type) из поста выше объяснит размер элемента дескриптора. Подстановки: descriptor_size*sizeof(float)=64*(32/8)=64*4=256 для обычного дескриптора и в два раза больше для расширенного. 1 Share this post Link to post Share on other sites
TroyashkA 12 Report post Posted March 11, 2011 Вот это : descriptor_size*CV_ELEM_SIZE(descriptor_data_type) из поста выше объяснит размер элемента дескриптора. Спасибо! Я сегодня рассеянный ... учту это в дальнейшем ... а сейчас хотелось бы узнать что я делаю не так Share this post Link to post Share on other sites
Smorodov 579 Report post Posted March 11, 2011 Сейчас загружу картинки, и посмотрю что там глючит Share this post Link to post Share on other sites
TroyashkA 12 Report post Posted March 11, 2011 Сейчас загружу картинки, и посмотрю что там глючит Ого! Отлично - гляньте что там, а то у меня уже мозг отказывается работать - подсказывает, что утро вечера мудренее. Я обязательно прочту ваще сообщение завтра утром! Спасибо - Вы весь день мне помогаете Share this post Link to post Share on other sites
Smorodov 579 Report post Posted March 11, 2011 Выяснилось вот что: если не загонять в currentDescriptors больше определенного числа элементов за раз (надо копать, с чем связано не знаю), то все проходит нормально. Вот если поставить такое условие: if(currentDescriptors->total<235) (цифру подобрал близкую к рабочему максимуму), то все работает. Может там ограничение по объему передаваемых данных. ЗЫ: И еще MaxPart... надо привести к действительному виду, иначе ерунда при делении будет. Должно быть так: // получаем количество шагов =============================== int stepY = ceil((double)image->height/(double)MaxPartHeight); int stepX = ceil((double)image->width/(double)MaxPartWidth); // =========================================================[/code] 1 Share this post Link to post Share on other sites
TroyashkA 12 Report post Posted March 12, 2011 Выяснилось вот что: если не загонять в 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
TroyashkA 12 Report post Posted March 12, 2011 Выделил особенности, но вот беда - получаю неправильные значения матрицы преобразования гомографии Попробую немного другим способом ... Share this post Link to post Share on other sites
Smorodov 579 Report post Posted March 12, 2011 Вот тот проект, о котором говорил. Посмотрите, может пригодится. И еще вопрос, вы склеиваете большие куски? Если да, то координаты найденных точек смещать надо (добавить координаты куска в общем полотне).OpenCv_homo.cppmain.h 1 Share this post Link to post Share on other sites
TroyashkA 12 Report post Posted March 12, 2011 Вот тот проект, о котором говорил. Посмотрите, может пригодится. И еще вопрос, вы склеиваете большие куски? Если да, то координаты найденных точек смещать надо (добавить координаты куска в общем полотне). Интересный код ... а склеиваю я эти большие куски 1.bmp и 2.bmp. То есть, при получении тайла (кусочка) и выделения из него особенностей - эти особенности надо редактировать (смещать координаты)? Только вот я не знаю, где в них хранятся координаты точек (еще плохо знаю тип CvSeq). Share this post Link to post Share on other sites
Smorodov 579 Report post Posted March 12, 2011 Я рисовал точки так: // Рисуем результат 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] 1 Share this post Link to post Share on other sites
TroyashkA 12 Report post Posted March 12, 2011 Как-то видел статейку на хабре про 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, ¤tKeypoints, ¤tDescriptors, 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, ¤tDescriptors[i]); } И получаю неправильный результат Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted March 15, 2011 Можешь выложить свой последний вариант кода с вычислением матрицы гомографии? Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted March 16, 2011 Запустил стандартный пример с твоими изображениями "find_obj.exe object.jpg image.jpg" - соответствия между дескрипторами находятся верно. Share this post Link to post Share on other sites
TroyashkA 12 Report post Posted March 17, 2011 Запустил стандартный пример с твоими изображениями "find_obj.exe object.jpg image.jpg" - соответствия между дескрипторами находятся верно. Да я даже не сомневался, так как часть кода у меня из примеров OpenCV. Проблема в другом - мне необходимо обрабатывать изображения с высоким разрешением. И если вы запустите тот же find_obj.exe с двумя другими изображениями с высоким разрешением, которые я выкладывал тут то результат будет такой: Не хватает памяти, приходится обрабатывать изображение по частям. А при выделении ключевых точек/дескрипторов методом SURF "по частям" особенности получаются неправильно Задачка то банальная - разделение изображения на тайлы и выделение из каждого особенностей. Share this post Link to post Share on other sites
mrgloom 242 Report post Posted March 17, 2011 небось cvReleaseImage(&img); забываешь сколько памяти на компе? так же интересует вопросы: 1.Как реализовывается своп на хард если действительно не хватает памяти? (я так понимаю это надо делать сторонними методами) 2.Opencv работает многопоточно?если нет то как это реализовать?(а то у меня все выполняется на 1 ядре походу) попозже постараюсь выложить свой проект с SURF на opencv2.1 Share this post Link to post Share on other sites
TroyashkA 12 Report post Posted March 17, 2011 небось cvReleaseImage(&img); забываешь сколько памяти на компе? Спутниковые снимки сейчас весят ~100MB. Хотя в реале размер будет доходить до ~1GB. Сама функция cvExtractSURF() не справляется с такими большими изображениями. ОЗУ 4GB, Система Windows 7 конечно же x64, виртуальной памяти выделено ~30GB з.ы. проект можно скачать тут Share this post Link to post Share on other sites
mrgloom 242 Report post Posted March 17, 2011 и да еще вопрос я так понимаю, что снимки то потом будут склеиваться? (если так то можно не по всему изображению искать, а только по предполагаемой области перекрытия) cvExtractSURF() сколько точек находит? Share this post Link to post Share on other sites
TroyashkA 12 Report post Posted March 17, 2011 и да еще вопрос я так понимаю, что снимки то потом будут склеиваться? (если так то можно не по всему изображению искать, а только по предполагаемой области перекрытия) Да, снимки будут трансформироваться в соответствии с полученной матрицей преобразования гомографии, а потом склеиватся. А область еще найти нужно. А как найти? Тем же выделением особенностей. И опять приходим к тому, что необходимо делить картинку на тайлы и из каждого получать точки&дескрипторы. cvExtractSURF() сколько точек находит? По-разному, зависит от размера тайла. Но одно ясно - при разделении на тайлы, в результате находит он их (точки) не верно. Share this post Link to post Share on other sites