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

MD. KirkA

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

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

  • Посещение

Сообщения, опубликованные пользователем MD. KirkA


  1. Мде, печально. Чувак убил кучу времени, причём он имел готовые базы из инета.

    То есть самому на собственных экспериментах в отдельно взятом помещении сделать такое практически нереально...(

    А были ли какие то источники самообучающихся программ по распознаванию? Или это из жанра фантастики?


  2. Есть ли обученные каскады для распознавания лица с углом около 45 градусов над лицом, т.е. если камера висит выше лица где-то на метр-полтора?

    И если нет, то дайте пожалуйста почитать литературу по обучению каскадов в opencv.


  3. С августа текущего года начал программировать.

    С августа и решаю задачу подсчета посетителей. Сейчас нахожусь на этапе оптимизации программы. Не поленился и прочитал данную тему целиком. Жалко, что в ней так редко пишут, но надеюсь мой пост увидят и обсуждение не затянется на месяц, потому что нужен ваш совет - работаю один, и весьма тяжко без коллективного мышления. Выкладываю свои наработки не только потому, что нужен совет, а ещё и потому, что данный форум мне много раз помогал, хочу теперь и я как то помочь вам, поделиться своими соображениями.

    После прочтения темы первый вопрос - на кой черт располагать камеры сверху, если это подсчет посетителей. Обратите внимание на тот пример, где куча людей выделяется на улице. От расположения камеры очень многое зависит, в частности, использование каскадов. Поэтому в моем варианте камера располагается напротив входа, а не над ним.

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

    1.1 Я сам представлял кадр с камеры как матрицу коэффициентов свечения пикселей, потом пробовал пересчитывать смещение отдельных групп элементов. Не углубляясь в дальнейшее объяснение скажу, что это хрень получается, особенно, если делать это в одиночку.

    1.2 Метод статичного фона из примеров опенцэвэ. Очень много шумов, нет границ объектов, да и вычленение отдельных объектов - задача практически невыполнимая, овчинка выделки не стоит.

    2. Меня весьма спас метод кодовой книги (codebook). Действенная штука, шаблоны движения, всё такое. Но опять же - даже если подбирать определенные параметры среднестатистического человека и ставить ограничение по размерам движущихся областей с учетом масштаба и расстояния от камеры до объекта слежения - всё равно очень сильно косячит. В счетчике посетителей не должно быть деление одного объекта на два. Программа должна четко распознавать одного человека как один объект, и тут только один выход - третий пункт моих экспериментов, каскады

    3. Каскады. В моём случае каскады Хаара, а именно распознавание лиц. Программа делает дополнительную фишечку - через область интересов распознанное каскадами лицо сохраняется в базу данных посетителей. Так вот на нем я и остановился.

    Теперь особенности разработки: в моем случае используются 6 IP камер от шведов (Axis). Быстродействие, даже с самым современным компьютером, тут играет огромную роль, поэтому сразу отбрасываю вариант использования Лукаса-Канаде, ибо он, по отзывам, жрет очень много ресурсов.

    Итак, есть лица или же upperbody\lowerbody. Проблема с подсчетом заключается только в трекинге.

    Реализация моего счетчика идет через пересечение объектом границы, проведенной через весь кадр горизонтально приблизительно посередине.

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

    Следовательно, мои соображения сделать временнОй дедлайн для нахождения в кадре посетителя (это считается чисто логически - сколько здравомыслящий человек может простоять на входе в торговый центр, где люди обычно не задерживаются, а так же учитвать среднюю скорость движения человека и расстояние с учетом масштаба от верхнего края плоскости, по которой ходят посетители, до нижнего). Это определит максимальное количество кадров для работы "отсеивателя", который будет работать для уничтожения схожих объектов.

    Отсеиватель я сейчас думаю построить на SURF\SIFT, поскольку фактически для трех-пяти кадров проблема эта позволяет использовать область интересов лица и само лицо как плоский объект для вычленения похожих.

    Уважаемые знатоки, внимание, вопрос: я правильно думаю или мне надо думать в другую сторону?


  4. Вот пример функции update_mhi:

    void update_mhi1( IplImage* img, IplImage* dst, int diff_threshold, int sb4pos, int sb5pos)
    
    {
    
    	double timestamp = (double)clock()/CLOCKS_PER_SEC; // get current time in seconds
    
    	CvSize size = cvSize(img->width,img->height); // get current frame size
    
    	int i, idx1 = last1, idx2;
    
    	IplImage* silh=0;
    
    	CvSeq* seq=0;
    
    	CvRect comp_rect;
    
    	double count;
    
    	double angle;
    
    	CvPoint center;
    
    	double magnitude;
    
    	CvScalar color;
    
    
    // number of cyclic frame buffer used for motion detection
    
    // (should, probably, depend on FPS)
    
    
    	// allocate images at the beginning or
    
    	// reallocate them if the frame size is changed
    
    	if( !mhi1 || mhi1->width != size.width || mhi1->height != size.height ) 
    
    	{
    
    		if( buf1 == 0 ) 
    
    		{
    
    			buf1 = (IplImage**)malloc(N*sizeof(buf1[0]));
    
    			memset( buf1, 0, N*sizeof(buf1[0]));
    
    		}
    
    		for( i = 0; i < N; i++ ) 
    
    		{
    
    			cvReleaseImage( &buf1[i] );
    
    			buf1[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
    
    			cvZero( buf1[i] );
    
    		}
    
    	  cvReleaseImage( &mhi1 );
    
    	  cvReleaseImage( &orient1 );
    
    	  cvReleaseImage( &segmask1 );
    
    	  cvReleaseImage( &mask1 );
    
    	  mhi1 = cvCreateImage( size, IPL_DEPTH_32F, 1 );
    
    	  cvZero( mhi1 ); // clear MHI at the beginning
    
    	  orient1 = cvCreateImage(size, IPL_DEPTH_32F, 1 );
    
    	  segmask1 = cvCreateImage(size, IPL_DEPTH_32F, 1 );
    
    	  mask1 = cvCreateImage(size, IPL_DEPTH_8U, 1 );
    
    	}
    
    	cvCvtColor( img, buf1[last1], CV_BGR2GRAY ); // convert frame to grayscale
    
    	idx2 = (last1 + 1) % N; // index of (last - (N-1))th frame
    
    	last1 = idx2;
    
    	silh = buf1[idx2];
    
    	cvAbsDiff( buf1[idx1], buf1[idx2], silh ); // get difference between frames
    
    	cvThreshold( silh, silh, diff_threshold, 1, CV_THRESH_BINARY ); // and threshold it
    
    	cvUpdateMotionHistory( silh, mhi1, timestamp, MHI_DURATION ); // update MHI
    
    	// convert MHI to blue 8u image
    
    	cvCvtScale( mhi1, mask1, 255./MHI_DURATION,
    
    	(MHI_DURATION - timestamp)*255./MHI_DURATION );
    
    	cvZero( dst );
    
    	cvCvtPlaneToPix( mask1, 0, 0, 0, dst );
    
    	// calculate motion gradient orientation and valid orientation mask
    
    	cvCalcMotionGradient( mhi1, mask1, orient1, MAX_TIME_DELTA, MIN_TIME_DELTA, 3 );
    
    	if( !storage1 )
    
    	storage1 = cvCreateMemStorage(0);
    
    	else
    
    	cvClearMemStorage(storage1);
    
    	// segment motion: get sequence of motion components
    
    	// segmask is marked motion components map. It is not used further
    
    	seq = cvSegmentMotion( mhi1, segmask1, storage1, timestamp, MAX_TIME_DELTA );
    
    	// iterate through the motion components,
    
    	// One more iteration (i == -1) corresponds to the whole image (global motion)
    
    	for( i = -1; i < seq->total; i++ ) 
    
    	{
    
    		if( i < 0 ) 
    
    		{ // case of the whole image
    
    			comp_rect = cvRect( 0, 0, size.width, size.height );
    
    			color = CV_RGB(255,255,255);
    
    			magnitude = 100;
    
    		}
    
    		else 
    
    		{ // i-th motion component
    
    		comp_rect = ((CvConnectedComp*)cvGetSeqElem( seq, i ))->rect;
    
    		if( (comp_rect.width + comp_rect.height > sb4pos ) && (comp_rect.width + comp_rect.height < sb5pos) ) 
    
    			// reject very small and very big components
    
    		continue;
    
    		color = CV_RGB(0,255,0);
    
    		magnitude = 100;
    
    		}
    
    	// select component ROI
    
    	cvSetImageROI( silh, comp_rect );
    
    	cvSetImageROI( mhi1, comp_rect );
    
    	cvSetImageROI( orient1, comp_rect );
    
    	cvSetImageROI( mask1, comp_rect );
    
    	// calculate orientation
    
    	angle = cvCalcGlobalOrientation( orient1, mask1, mhi1, timestamp,MHI_DURATION);
    
    	//angle = 360.0 - angle; // adjust for images with top-left origin
    
    	count = cvNorm( silh, 0, CV_L1, 0 ); // calculate number of points within silhouette ROI
    
    	cvResetImageROI( mhi1 );
    
    	cvResetImageROI( orient1 );
    
    	cvResetImageROI( mask1 );
    
    	cvResetImageROI( silh );
    
    	// check for the case of little motion
    
    
    	if( count < comp_rect.width*comp_rect.height * 0.05 )
    
    	continue;
    
    	// draw a clock with arrow indicating the direction
    
    	center = cvPoint( (comp_rect.x + comp_rect.width/2),(comp_rect.y + comp_rect.height/2) );
    
    	cvCircle( dst, center, cvRound(magnitude*1.2), color, 3, CV_AA, 0 );
    
    	cvLine( dst, center, cvPoint( cvRound( center.x + magnitude*cos(angle*CV_PI/180)),
    
    	cvRound( center.y - magnitude*sin(angle*CV_PI/180))), color, 3, CV_AA,0 );
    
    	cvLine(dst,cvPoint(0,trackleft1pos),cvPoint(640, trackright1pos), color, 2, CV_AA,0);
    
    	if (onkey)
    
    	if (((center.x*k1+trackleft1pos<center.y+2)&&((center.x*k1+trackleft1pos>center.y-2)))&&(angle>-1)&&(angle<181))
    
    	{incount1++;
    
    	allcount=allcount++;}
    
    	if (onkey)
    
    	if (((center.x*k1+trackleft1pos<center.y+2)&&((center.x*k1+trackleft1pos>center.y-2)))&&(angle>180)&&(angle<360))
    
    	{outcount1++;
    
    	allcount=allcount++;}
    
      }
    
    }
    
    


  5. А куда смотреть то конкретно?

    Лучше один раз увидеть, поэтому...

    В прикрепленном: проект под OpenCV 2.4 в MVS 2010

    6 реализаций update_mhi в отдельности для каждой камеры. Вызов функции из первого таймера.

    Работает с файлом 18.avi, производит сохранение на D:\

    Вот целиком проект:

    Скачать (~350Mb)

    Скачать с другого файлообменника (~350Mb)


  6. По данному сабжу возникла проблема. :unsure:

    При использовании update_mhi потребовалось изменять размеры захватываемых объектов в пикселях.

    Причина в том, что на одном и том же человеке (речь об алгоритме пересечения границы) выделяются от двух и более точек движения.

    Идея в том, чтобы ограничить comp_rect, чтобы не менее 100 пикселей и не более 300 пикселей.

    конкретно в этом условии стандартной функции:

    if( (comp_rect.width + comp_rect.height > sb4pos ) && (comp_rect.width + comp_rect.height < sb5pos) ) 

    Проблема в том, что возвращаемое значение comp_rect.width превышает 3 миллиона, а comp_rect.height=1920.

    Вопрос: почему так происходит и что необходимо исправить, чтобы всё заработало? :rolleyes:


  7. вообще для отладки таких проблем можете использовать профилировщики, если работаете в линуксе valgrind, если в windows, конечно, посложнее найти бесплатное, либо gprof прикрутить, но он не очень информативен, либо, например, VTune. С сайта интел можно скачать пробную версию на месяц.

    попробую. Но моя проблема пока что актуальна.


  8. Проблема появилась при разработке проекта в финальной его стадии. После 6,5 минут программа вылетает с повреждением стека. Последний кадр стека указывает на использование хранилища памяти типа CvMemStorage в функции update_mhi1 где то тут:

    cvCalcMotionGradient( mhi1, mask1, orient1, MAX_TIME_DELTA, MIN_TIME_DELTA, 3 );
    
    if( !storage1 )
    
      storage1 = cvCreateMemStorage(0);
    
    else
    
      cvClearMemStorage(storage1);

    Долго искал соответствующую тему - так и не нашел. Пожалуйста, помогите.

    З.Ы.: в прикрепленном файле листинг (Visual C++, MS VS 2010 с использованием MFC и OpenCV 2.4.2). Для его создания использовалось руководство от Smorodov и maximator по OpenCV+MFC (без использования потоков, но с таймером) + книга O'Reilly и пример по кодовой книге (update_mhi). Ошибка возникает при Release версии, при Debug может и не вылезти. Но тут, как понимаете, итоговой программы не будет без Release.

    code-cpp.txt

×