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

Доска почета


Popular Content

Showing most liked content on 28.12.2011 во всех областях

  1. 1 point
    Не судите строго, я недавно начал заниматься 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. 1 point
    Спешим сообщить, что открыта регистрация на студенческий Конкурс Microsoft Research по Компьютерному Зрению 2012. Успейте зарегистрироваться до 15 января! Участникам предлагается разработать прототипы программных приложений и сервисов с использованием библиотеки Kinect for Windows. Подача работ до 28 февраля. Пятеро победителей конкурса будут приглашены в Кембридж (Великобритания) на летнюю школу Microsoft Research! Просим преподавателей донести информацию до студентов и аспирантов. Подробности - на сайте http://summerschool2011.graphicon.ru/ru/contest
×