Перейти к содержимому
Compvision.ru

milk3d

Пользователи
  • Количество публикаций

    28
  • Зарегистрирован

  • Посещение

  • Days Won

    1

Все публикации пользователя milk3d

  1. Не судите строго, я недавно начал заниматься OpenCV и Компьютерным зрением в целом, да и статьи не умею толком писать. Данная статья, хотя это скорее тезис, явилась промежуточным итогом моей работы. Мне бы очень было бы интересно услышать ваши мнения без разнице какие. Код программы приведенной в статье написан для Microsoft Visual C++. Поиск объектов на изображении является одной из важнейших составляющих компьютерного зрения. На сегодняшний момент существует множество способов выделения объектов на изображении, таких как выделение по цвету, по яркости, по структуре. В этой статье описывается попытка создания компьютерной программы которая могла бы выделять зелёные объекты на изображении в реальном времени. Рассмотрим в начале задачу, в которой программа ищет только один объект. Изображение состоит из множества отдельных частей, пикселей и наша задача сводится к нахождению массива пикселей одного цвета, в нашем случае зелёного. Будем считать, что зелёный пиксель это такой пиксель у которого зелёная составляющая его цвета (в пространстве RGB) превышает остальные составляющие в k раз. Коэффициент может варьироваться в зависимости от освещённости и от яркости зелёного цвета более устойчивого распознавания объекта. Проверив все пиксели по указанному выше критерию, можно получить массив G всех зелёных пикселей на изображении. Предположим, что на изображении всего один объект, тогда массив G содержит только пиксели принадлежащие этому объекту. Координаты центра масс, который ввиду равномерной плотности (веса точек одинаковы) совпадает с геометрическим центром, можно определить сложив между собой координаты всех его составляющих и разделив полученную сумму на их количество. Такой способ определения зелёного объекта является простым и как показали опыты работоспособным, но его можно усложнить, введя вероятность принадлежности пикселя к объекту. Алгоритм нахождения нескольких объектов ни чем не отличается от алгоритма нахождения одного объекта. Просто в этом случае массив G будет содержать элементы всех объектов, а не только одного. По этому задача сводится к разделению массива G на отдельные массивы I1, I2, … , In которые содержали бы в себе элементы отдельных объектов. Если в качестве массива G использовать само изображение, то отделить зелёные пиксели от остальных можно просто погасив все пиксели, а зелёные сделать белыми, что приведёт к получению двухцветной картинки (бинаризация). Следующий шаг в этом процессе, найти отдельные объекты для этого можно организовать цикл по всем пикселям дабы найти все белые пиксели, и при нахождении такого пикселя производить заливку всей белой области другим цветом(цветом объекта), и продолжать поиск далее с этого же места. Для более детального понимания алгоритма ниже приведен исходный код программы. Программа написана на языке C++ и использует библиотеку OpenCV 1.1 для работы с изображениями и камерой. #include <cv.h> #include <highgui.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <vector> using namespace std; // Размер картинки int width; int height; //Класс объекта class ob{ public: char id; //Цвет int M00,M10,M01; int Xc,Yc; ob(){ M00=M10=M01=0; } void addPoint(int x, int y){ M00++; M10+=x; M01+=y; } CvPoint getCenter(){ Xc=int(M10/M00); Yc=int(M01/M00); return cvPoint(Xc,Yc); } }; //---Три функции алгоритма заливки void NearPix(uchar** ptr,int x, int y, int *numStack, CvPoint *Stack, ob &Obj){ if(ptr[y][3*x]==255){ ptr[y][3*x] = 0; ptr[y][3*x+1] = 255; ptr[y][3*x+2] = 0; Stack[*numStack].x=x; Stack[*numStack].y=y; (*numStack)++; Obj.addPoint(x,y); } } void OneStep(uchar** ptr, int *numSrc, int *numDest, CvPoint *Src, CvPoint *Dest, ob &Obj){ int x,y,i; *numDest=0; for(i=0; i<*numSrc;i++){ x=Src[i].x; y=Src[i].y; NearPix(ptr,x+1,y,numDest,Dest,Obj); NearPix(ptr,x-1,y,numDest,Dest,Obj); NearPix(ptr,x,y+1,numDest,Dest,Obj); NearPix(ptr,x,y-1,numDest,Dest,Obj); } } void WaveFill(uchar** ptr,int xst, int yst, ob &Obj){ Obj.addPoint(xst,yst); ptr[yst][3*xst] = 0; ptr[yst][3*xst+1] = Obj.id; ptr[yst][3*xst+2] = 0; int numA, numB; CvPoint *stackA, *stackB; stackA=new CvPoint[10000]; stackB=new CvPoint[10000]; numA=1; stackA[0].x=xst; stackA[0].y=yst; numB=0; while(1){ if(numA>0)OneStep(ptr,&numA,&numB,stackA,stackB,Obj); else break; if(numB>0)OneStep(ptr,&numB,&numA,stackB,stackA,Obj); else break; } delete [] stackB; delete [] stackA; } //---Начало программы int main(int argc, char* argv[]) { vector<ob> bufOb; //Буфер объектов cvNamedWindow( "Example2", CV_WINDOW_AUTOSIZE ); CvCapture* capture = cvCreateCameraCapture(0); IplImage* frame; width = (int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH); height = (int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT); IplImage* buf = cvCreateImage( cvSize(width,height), 8, 3 ); uchar** ptra=new uchar*[height]; while(1){ frame = cvQueryFrame( capture ); if( !frame ) break; cvCopy(frame,buf); cvSmooth( frame, frame, CV_GAUSSIAN, 5, 5 ); uchar* ptr; //Первый прход по всем пикселям for( int y=0; y<height; y++ ){ ptr = (uchar*)(frame->imageData + y * frame->widthStep); for( int x=0; x<width; x++ ){ //Гасим всё кроме зелёного bool bGreen = ptr[3*x]+15<ptr[3*x+1]&&ptr[3*x+2]+15<ptr[3*x+1]; ptr[3*x] = ptr[3*x+1] = ptr[3*x+2] = bGreen*255; } ptra[y]=ptr; } //Рисуем рамку чёрного цвета по границе изображения //для ограничения заливки cvRectangle(frame, cvPoint(0,0), cvPoint(width-1,height-1), cvScalar(0,0,0) ); //Второй проход по всем пикселям в котором применяется заливка //для разделения объектов, причём шаг цикла это ограничение //на размер объекта for( int y=0; y<height; y+=1 ){ for( int x=0; x<width; x+=1 ){ if(ptra[y][3*x]==255){ ob newOb(); bufOb.push_back(newOb); WaveFill(ptra,x,y,bufOb[bufOb.size()-1]); } } } for(int i=0; i<bufOb.size(); i++){ cvCircle (frame,bufOb[i].getCenter(),5,cvScalar(0,0,255),3,2); } //Очистка буфера объектов bufOb.clear(); cvShowImage( "Example2", frame ); char c = cvWaitKey(33); if( c == 27 ) break; } cvReleaseCapture( &capture ); cvDestroyWindow( "Example2" ); }
  2. Недавно столкнулся с такой задачей, поиск прямоугольной рамки на фотографии. Что важно это определить её углы и узнать какой это именно угол. Рамка может быть так же затемнена и на неё можно смотреть под разными углами, т.е. на некоторых изображениях она может выглядеть как ромб. Я знаю точно, что эту задачу можно решить с помощью OpenCV, я уже начал с ней разбираться. Но хотелось бы узнать в каком направлении нужно работать, что бы это сделать и подходит ли представленный рисунок для этого? До этого положение центров цветных прямоугольников я находил по их центрам масс, но при этом не учитывал вероятности принодлежности точек к ним. Для очень контрастных изображений результат был довольно хороший, а вот для фотографий всё сложнее. Примерный вид рамки:
  3. Мне необходимо решить систему уравнений, при обработке экспериментальных данных, в которой число уравнений превышает число неизвестных. Данная задача решается просто если уравнения линейные, методом наименьших квадратов, как описывается в этой статье http://ru.wikipedia.org/wiki/Метод_наименьших_квадратов. Но у меня уравнения более сложного вида, содержат тригонометрию. Если кто знает способ по которому можно решить подобную систему, пожалуйста подскажите.
  4. MS Visual C++ и OpenCV

    Спасибо огромное вам за помощь. Очень хотелось довести до логического конца эту программу. Не поверите ваш проект компелируется, создал новый с тем же исходным кодом, что и у вас никакие библиотеки не подключал больше, поставил MT и снова тоже самое, ни как не хочет. Видимо и впрямь нужно пользоваться 2005.
  5. MS Visual C++ и OpenCV

    Спасибо за библиотеки, но все равно тоже самое. Я попробовал на другом компьютере и тоже ничего. Непонятно почему такое происходит. Скорее всего надо использовать Microsoft Visual 2005, версия 1.1 разрабатывалсь на нем, наверное в более поздние версии были внесены какие то критичные для библиотеки изменения. Постараюсь установить 2005й, хотя может что то не то всё же я сделал. Список библиотек которые я подключаю: cv.lib cvaux.lib cvauxd.lib cvd.lib cvhaartraining.lib cxcore.lib cxcored.lib cxts.lib cxtsd.lib highgui.lib highguid.lib ml.lib mld.lib Может быть что-то лишнее? Если вам не трудно не могли бы вы скомпелировать мою программу, вот исходный код. Эта маленькая программа демонстрирующая работу генетического алгоритма.
  6. MS Visual C++ и OpenCV

    Если вам несложно то скиньте.
  7. MS Visual C++ и OpenCV

    Библиотеки LIBCMT в input нету. Может быть какая то ошибка при компиляции библиотек, потому что он когда я компилировал их повторно возникли ошибки. При компиляции проекта cvaux он выводит Rebuild All: 1 succeeded, 2 failed, 0 skipped. Такого же не должно быть? Я даже не представляю почему такое происходит. А какую версию microsoft visual вы используете?
  8. MS Visual C++ и OpenCV

    Спасибо за помощь я просто никогда не работал с большими библиотеками на С++. когда я ставлю в проекте MT то он мне выдает Если поставить MDd то всё нормально работает. Может я где то не так сделал, попробую ещё раз всё с начала. Я сейчас использую 1.1 может быть лучше будет использовать OpenCV 2.0?
  9. MS Visual C++ и OpenCV

    Я наверное безнадежен=) Проделал все что вы сказали. Для каждого проекта сделал полную перекомпеляцию, но вот когда начинаю компелировать свой проект с опцией "Multi threaded", он мне выдает ошибку связанную с LINK. Что мы сделали поменяв настройку "Multi threaded"? Теперь к проекту нужно подключить dll?
  10. MS Visual C++ и OpenCV

    Спасибо большое за ответ. С первой частью я справился А насчет dll, не могли бы вы подробнее описать?
  11. MS Visual C++ и OpenCV

    Я извиняюсь за повторный вопрос, но что то я не могу сделать это в одиночку. Недавно я написал маленькую программу с использованием OpenCV 1.1 и мне бы хотелось ее выложить в интернет. Но я ни как не могу понять, что нужно сделать для того что-бы она запускалась и у других людей у кого не установлена OpenCV. Если можете скажите как это сделать. Использовал я Microsoft Visual c++ Express.
  12. Я любитель и мне эта тема очень интересна, жаль что я не могу послушать лекцию=( Если вам не трудно не могли бы вы посоветовать материал по этой теме?
  13. А что вы думаете о задаче дополнения реальности (Augmented reality)? Недавно обнаружил, что большое количество маленьких и довольно больших проектов начинает выпускаться в которых используется дополнение реальности. К примеру тот проект от PleyStation о котором я писал на форуме http://www.compvision.ru/forum/index.php?showtopic=143. На западе идет активное изучение данной темы. Многие крупные компании так же ведут разработку, судя по их рекламным роликам.
  14. Очень интересно, где в России занимаются разработками в области компьютерного зрения, и где готовят специалистов связанных с этой областью? И если может кто знает, каковы дела в общем с компьютерным зрением, да и не только с ним, а со всей робототехникой в целом в России?
  15. Недавно перед собой поставил задачу определить координат и углы пзиционировния камеры по проекциям известных точек на изображении. Мне удалось зная координаты трех точек в мире и координаты их проекций определить позицию камеры. Для этого я составил систему из шести уравнений с шестью неизвестными рукаводствуясь этим материалом http://en.wikipedia.org/wiki/3D_projection. Найдя неизвестные я получил искомый результат. Вот только такая систем очень реагирует на точность входных данных и для экспериментальных значений ответ сильно долек от правды. Если кто то занимался подобной проблемой, посоветуйте если можете более оптимальное решение или просто направление в котором надо работать.
  16. Всего то шесть неизвестных три точки у каждой по две координаты проекции, параметры камеры мне были известны. Спасибо большое направление задали, буду капать, а то без теории сложновато.
  17. В конце этого года на PlayStation выйдет игра, которая должна стать самым серьезным проектом для консоли использующим для игры камеру. Тема расширения реальности становится все более и более актуальной, и начинает входить в массы. Официальный сайт игры http://www.eyepet.com Информация на wiki http://en.wikipedia.org/wiki/EyePet И немного на моем блоге http://blog.vsreality.ru/?p=72
  18. Недавно меня спросили о коде получившейся программы. Я вот и подумал, что он может пригодиться еще кому то, и хотя эта программа всего лишь переделанный пример из OpenCV архива, под работу с видео. Я ничего не менял касающегося SURF алгоритма, только добавил работу с видео. Программа написана для MV С++. image.bmp - имя файла картинки, которая обводится рамкой. #include <cv.h> #include <highgui.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <vector> #define ZOOM 2 using namespace std; IplImage *image = 0; double compareSURFDescriptors( const float* d1, const float* d2, double best, int length ) { double total_cost = 0; assert( length % 4 == 0 ); for( int i = 0; i < length; i += 4 ) { double t0 = d1[i] - d2[i]; double t1 = d1[i+1] - d2[i+1]; double t2 = d1[i+2] - d2[i+2]; double t3 = d1[i+3] - d2[i+3]; total_cost += t0*t0 + t1*t1 + t2*t2 + t3*t3; if( total_cost > best ) break; } return total_cost; } int naiveNearestNeighbor( const float* vec, int laplacian, const CvSeq* model_keypoints, const CvSeq* model_descriptors ) { int length = (int)(model_descriptors->elem_size/sizeof(float)); int i, neighbor = -1; double d, dist1 = 1e6, dist2 = 1e6; CvSeqReader reader, kreader; cvStartReadSeq( model_keypoints, &kreader, 0 ); cvStartReadSeq( model_descriptors, &reader, 0 ); for( i = 0; i < model_descriptors->total; i++ ) { const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr; const float* mvec = (const float*)reader.ptr; CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader ); CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader ); if( laplacian != kp->laplacian ) continue; d = compareSURFDescriptors( vec, mvec, dist2, length ); if( d < dist1 ) { dist2 = dist1; dist1 = d; neighbor = i; } else if ( d < dist2 ) dist2 = d; } if ( dist1 < 0.6*dist2 ) return neighbor; return -1; } void findPairs( const CvSeq* objectKeypoints, const CvSeq* objectDescriptors, const CvSeq* imageKeypoints, const CvSeq* imageDescriptors, vector<int>& ptpairs ) { int i; CvSeqReader reader, kreader; cvStartReadSeq( objectKeypoints, &kreader ); cvStartReadSeq( objectDescriptors, &reader ); ptpairs.clear(); for( i = 0; i < objectDescriptors->total; i++ ) { const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr; const float* descriptor = (const float*)reader.ptr; CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader ); CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader ); int nearest_neighbor = naiveNearestNeighbor( descriptor, kp->laplacian, imageKeypoints, imageDescriptors ); if( nearest_neighbor >= 0 ) { ptpairs.push_back(i); ptpairs.push_back(nearest_neighbor); } } } /* a rough implementation for object location */ int locatePlanarObject( const CvSeq* objectKeypoints, const CvSeq* objectDescriptors, const CvSeq* imageKeypoints, const CvSeq* imageDescriptors, const CvPoint src_corners[4], CvPoint dst_corners[4] ) { double h[9]; CvMat _h = cvMat(3, 3, CV_64F, h); vector<int> ptpairs; vector<CvPoint2D32f> pt1, pt2; CvMat _pt1, _pt2; int i, n; findPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs ); n = ptpairs.size()/2; if( n < 4 ) return 0; pt1.resize(n); pt2.resize(n); for( i = 0; i < n; i++ ) { pt1[i] = ((CvSURFPoint*)cvGetSeqElem(objectKeypoints,ptpairs[i*2]))->pt; pt2[i] = ((CvSURFPoint*)cvGetSeqElem(imageKeypoints,ptpairs[i*2+1]))->pt; } _pt1 = cvMat(1, n, CV_32FC2, &pt1[0] ); _pt2 = cvMat(1, n, CV_32FC2, &pt2[0] ); if( !cvFindHomography( &_pt1, &_pt2, &_h, CV_RANSAC, 5 )) return 0; for( i = 0; i < 4; i++ ) { double x = src_corners[i].x, y = src_corners[i].y; double Z = 1./(h[6]*x + h[7]*y + h[8]); double X = (h[0]*x + h[1]*y + h[2])*Z; double Y = (h[3]*x + h[4]*y + h[5])*Z; dst_corners[i] = cvPoint(cvRound(X), cvRound(Y)); } return 1; } int main(int argc, char** argv) { const char* object_filename = argc == 3 ? argv[1] : "image.bmp"; CvMemStorage* storage = cvCreateMemStorage(0); cvNamedWindow("Object", 1); cvNamedWindow("Object Correspond", 1); static CvScalar colors[] = { {{0,0,255}}, {{0,128,255}}, {{0,255,255}}, {{0,255,0}}, {{255,128,0}}, {{255,255,0}}, {{255,0,0}}, {{255,0,255}}, {{255,255,255}} }; IplImage* object = cvLoadImage( object_filename, CV_LOAD_IMAGE_GRAYSCALE ); IplImage* object_color = cvCreateImage(cvGetSize(object), 8, 3); cvCvtColor( object, object_color, CV_GRAY2BGR ); CvSeq *objectKeypoints = 0, *objectDescriptors = 0; int i; CvSURFParams params = cvSURFParams(500, 1); cvExtractSURF( object, 0, &objectKeypoints, &objectDescriptors, storage, params ); CvPoint src_corners[4] = {{0,0}, {object->width,0}, {object->width, object->height}, {0, object->height}}; CvPoint dst_corners[4]; for( i = 0; i < objectKeypoints->total; i++ ) { CvSURFPoint* r = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, i ); CvPoint center; int radius; center.x = cvRound(r->pt.x); center.y = cvRound(r->pt.y); radius = cvRound(r->size*1.2/9.*2); cvCircle( object_color, center, radius, colors[0], 1, 8, 0 ); } cvShowImage( "Object", object_color ); CvCapture* capture = cvCreateCameraCapture(0); IplImage* frame; //Размеры входного изображения int width = (int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_WIDTH); int height= (int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_HEIGHT); CvSize size = cvSize(width,height); //Для серого изображения IplImage* image1 = cvCreateImage(size, 8, 1); //Для уменьшенного в ZOOM раз серого изображения IplImage* image2 = cvCreateImage(cvSize((int)(width/ZOOM),(int)(height/ZOOM)), 8, 1); while(1){ frame = cvQueryFrame( capture ); if( !frame ) break; //Делаем входное изображение серым cvCvtColor( frame, image1, CV_RGBA2GRAY ); //Уменьшаем серое изображение cvResize(image1,image2,CV_INTER_LINEAR); CvSeq *imageKeypoints = 0, *imageDescriptors = 0; cvExtractSURF( image2, 0, &imageKeypoints, &imageDescriptors, storage, params ); if( locatePlanarObject( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, src_corners, dst_corners )) { //Рисуем линии контура рамки на входном изображении(frame) for( i = 0; i < 4; i++ ) { CvPoint r1 = dst_corners[i%4]; CvPoint r2 = dst_corners[(i+1)%4]; cvLine( frame, cvPoint(r1.x*ZOOM, r1.y*ZOOM), cvPoint(r2.x*ZOOM, r2.y*ZOOM), colors[8] ); } } //Выводим входное изображение(frame) в окно программы cvShowImage( "Object Correspond", frame ); char c = cvWaitKey(33); if( c == 27 ) break; } cvReleaseCapture( &capture ); cvDestroyWindow("Object"); cvDestroyWindow("Object Correspond"); return 0; }
  19. Поле огромное конечно, Россия в целом отстает от мира в целом по разработкам. И вы правильно заметили тот факт, что многое держится на энтузиазме. Я иногда читаю форумы по робототехнике так люди делают общие заказ деталей из Америки, так как в России достать комплектующие просто не реально. Поле для развития робототехники в России действительно большое. Вот только не знаю насчет спроса, есть ли у нас в спрос на высокие технологии. А то одна нефть и газ=)
  20. Не знал о таком=) С праздником!!!=)
  21. Спасибо за информацию, я недавно в этой области и со многим ещё не ознакомился. Я знал, что я изобретаю велосипед, но это больше для тренировки как лабораторная работа.
  22. Никогда не работал с HSV и зря=) Действительно удобнее.
  23. Мне очень приятно, что вам понравилось. Я буду рад если вы ее подправите=)
  24. У меня обычная камера, подключаемая к компьютеру через DV. Её разрешение 720 на 576, довольно большое. Я уменьшил его в два раза до 360 на 288, производительность выросла примерно до того уровня что и у вас 15-20 фпс. Насчёт IPP я не могу понять, он бесплатный или нет? На сайте Интела я нашел вот это http://software.intel.com/en-us/intel-ipp это оно? Если не трудно, дайте прямую ссылку. Спасибо.
  25. Не знаю точно почему но у меня эта программа не работает. Но я переделал стандартный пример, под видеокамеру. Только вот как и думал скорости мало Зато различает разные рамки, а так же полу закрытые и повернутые до угла 45 градусов. Это хороший но медленный алгоритм, хотя процессор при его выполнении не нагружается по полной. Продолжаем работать. Если вы не против я буду писать сюда небольшие отчеты о продвижении.
×