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

Трекинг объектов.

Recommended Posts

прочитал первую тему ... у меня непонятности

что такое template matching и как им пользоваться?

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


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

Раз нужны только люди, то я бы поискал специфичные детекторы людей. Вычитание фона оно... так, способ универсальный, но не всегда корректный. В качестве основы не годится, а может использоваться как дополнительная информация для выделения областей для последующего анализа.

Итак:

1. Классика - детектор людей от Виолы-Джонса (Viola and Jones). В OpenCV есть реализация, смотри каскады: haarcascade_fullbody.xml, haarcascade_lowerbody.xml, haarcascade_mcs_upperbody.xml.

2. HOG из OpenCV. Есть примеры, есть обсуждение на форуме.

3. Посмотри примеры здесь.

4. Поищи "pedestrian detection".

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


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

что такое template matching и как им пользоваться?

есть изображение объекта и есть картинка на которой надо этот объект найти.

плюсы- быстро.

минусы- объект должен быть очень похож, нету инвариантности к повороту и размеру.

например можно выделить объект на видео рамкой(наверно можно и более точно, если фон занулить) и потом искать этот объект корреляцией.

http://www.compvision.ru/forum/index.php?showtopic=319

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


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

Спасибо mrgloom я скомпилировал код из книги, такую фигню конечно показывает непонятную этот template matching , ну да ладно, я если что - позже спрошу непонятности, сейчас я хочу заняться больше детектом лиц, как мне сказал Nuzhny. Думаю все таки в этом направлении двигаться.

Nuzhny, я открыл руководство Learning_Open_Cv (стр 511 в книге) , там код для " detecting and drawing faces" =) Я его скомпилировал, и попросил найти мне нос, глаз, лицо, ... че только не пробовал, он находит все что угодно только не меня (картинку прикрепил)

Вот код...

Где ошибка ? =((

#include "iostream"

#include <stdio.h>

#include "stdlib.h"

#include <cv.h>

#include <cxcore.h>

#include <highgui.h>

using namespace std;


int main( int argc, char** argv ) {

	CvCapture* input = cvCaptureFromCAM(0);


        if (!input)

	{cout<< "Can't open file" ; }

	IplImage* img;

		double scale = 1.3;


		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}}};

                   /*просто цвета чтоб рисовать прямоугольники*/


		CvHaarClassifierCascade* cascade = (CvHaarClassifierCascade*)cvLoad("E:\\OpenCv\\data\\haarcascades\\haarcascade_mcs_nose.xml", 0, 0, 0 );

		CvMemStorage* storage = cvCreateMemStorage(0);


		for (; {   //основной цикл , выход при нажатии ESC

		img=cvQueryFrame(input);

		cvShowImage("original",img);


		// IMAGE PREPARATION:

		//

		IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );

		IplImage* small_img = cvCreateImage(	cvSize( cvRound((img->width)/scale), cvRound((img->height)/scale)), 8, 1	);

			cvCvtColor( img, gray, CV_BGR2GRAY );

			cvResize( gray, small_img, CV_INTER_LINEAR );

			cvEqualizeHist( small_img, small_img );

				// DETECT OBJECTS IF ANY


			cvClearMemStorage( storage );

			CvSeq* objects = cvHaarDetectObjects(

					small_img,

					cascade,

					storage,

					1.1,

					2,

					0 /*CV_HAAR_DO_CANNY_PRUNING*/,

					cvSize(30, 30)

					);

				// LOOP THROUGH FOUND OBJECTS AND DRAW BOXES AROUND THEM


				for(int i = 0; i < (objects ? objects->total : 0); i++ ) {

					CvRect* r = (CvRect*)cvGetSeqElem( objects, i );

					cvRectangle(

						img,

						cvPoint(r->x,r->y),

						cvPoint(r->x+r->width,r->y+r->height),

						colors[i%8]

					);

				}

				cvShowImage("1",img);

				cvReleaseImage( &gray );

				cvReleaseImage( &small_img );


	char c = cvWaitKey(1); 

		if(c == 27)break; 

	}


	cvReleaseCapture(&input);

	return 0;

	}[/code]

post-4978-0-50893300-1333705052_thumb.jp

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


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

эти каскады может обучались на какой то другой выборке(не похожих на ваше изображение с камеры), попробуйте какие нибудь разные лица из интернета.

во всяком случае трэкать по лицу может и не самое хорошее решение, т.к. ориентация лица в реальной сцене может меняться.

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


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

Ответьте на эти вопросы пожалуйста ...

1 А есть код как обучать камеру используя какой нибудь шаблон?

2 И еще, такой вопрос - действительно, в реальной обстановке, человек может вообще спиной повернуться к камере, я ж его тогда каскадами не обнаружу? Тогда что делать? Лукасом Канаде или template matching по контуру?

p.s. на форуме в теме http://www.compvision.ru/forum/index.php?showtopic=814 mrgloom, Вы дали ссылку :

http://www.thecomputervision.com/resources-wall/?resource=293 . На странице рассказываются библиотеки как определить людей из массы

я скачал с этой страницы data-tud.zip , в этом архиве папки

- /det

- - / EPFL

- - / PETS2009

- - / TUD

- /gt

- - / PETS2009

- - / TUD

В каждой папке XML файлы , как их использовать?

P.P.S на данном этапе, я разбираюсь в некоторых фильтрах и в некоторых методах OpenCv но пока что не разбираюсь как использовать XML файлы, и что за циферки в них написано!

Help! WARNING нужен ликбез)))

Изменено пользователем Predatorxxx

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


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

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

про то как читать не знаю, но там написано

The annotations are saved in xml files using theCVML Specification, similar to the ground truth of the CAVIAR dataset.

и ссылки на спецификацию.

А есть код как обучать камеру используя какой нибудь шаблон?

что значит "обучать камеру"?

И еще, такой вопрос - действительно, в реальной обстановке, человек может вообще спиной повернуться к камере, я ж его тогда каскадами не обнаружу? Тогда что делать? Лукасом Канаде или template matching по контуру?

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

вообще получается имеем 3 проблемы

1. слияние с фоном.

2. разрыв одного объекта на несколько.

3. несколько объектов сливаются в один.

вообщем чтобы объект сопровождать я так понимаю его надо сначала выделить.

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

вот про игроков я имел ввиду что то такое.не знаю как там это сделано не читал.

http://www.cs.ubc.ca/~shervmt/

какие то работы есть еще по Multiple Target Tracking

Bayesian Multiple Target Tracking

http://users.eecs.northwestern.edu/~tingyu/research_ctmt.htm

http://users.iit.demokritos.gr/~amakris/Tracking.shtml

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


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

- а можете вкратце рассказать как вообще происходит процесс

1.загрузки XML файла в программу для обработки

2. ручное выделение рамки - я так понимаю выделяю сам рамку, а дальше любыми действенными методами пытаюсь следить за объектом который в этой рамке? получается трек.

3. сравнить это значит на одном и том же видео я должен получить результаты (конкретнее, координаты точек, трека) а далее сравнить эти результаты (ВАЖНО при одинаковых начальных условиях!) и... я не понимаю в XML файлах числа, которые что-то обозначают ,оокей пусть например это координаты двигающегося объекта, но оригинал видео, обстановки - его же не выкладывают... как я тогда могу сравнить алгоритмы если я не могу провести свой эксперимент над "ихним" видео. А если я буду у себя в лаборатории тестировать алгоритм слежения , то и результаты я получу применительно к своей лаборатории...

а если в общем посмотреть то я уяснил общую мысль - какие то люди записали полученные результаты, чтоб другие могли сравнить свои с "ихними"

что значит "обучать камеру"?

я имел ввиду, код (готовое решение или просто пример) - как мне самому

вариант а) сделать свой XML- каскад , чтоб в дальнейшем использовать его. Я представляю себе это таким образом, я гуляю перед камерой. то иду к ней, то от нее , то перед ней,... все это снимаю на видео, далее терпеливо на каждой картинке запоминаю "КАКИЕ ТО " характеристики себя, не знаю - форму головы и тд , а далее я применяю ПОЛУЧЕННЫЕ ЗНАНИЯ на других людях, и сразу их обнаруживаю! Я правильно думаю?

вариант б) использование чужих каскадов (в виде файлов XML) . Я так понял есть отличная функция cvHaarDetectObjects - ищет все объекты которые подходят под КАКИЕ ТО ХАРАКТЕРИСТИКИ записанные в файле(кстати что это за характеристики такие записаны в XML?). Да хорошо, я вроде научился. Это называется детектор Хаара. Окей! Но в продолжение вот того сайта, я решил узнать что за PETS2009 - нашел этот сайт и "понял что ничего не понял" - там много dataset'ов , каждый dataset ( в переводе "набор данных") что то ведь делает... а как его использовать?? какие функции использовать? они вообще , вот эти dataset для чего?

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

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


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

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

В другом топике нашел вот видео

хочется сделать как на картинке, почитал че предлагают, просмотрел коды.

Какие методы можно использоваться для решения моей задачи? Каскады Хаара не подойдут скорее всего, так как вид сверху.

Возможно использовать оптический поток функцией void calcOpticalFlowFarneback или Лукас Канаде?

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


Ссылка на сообщение
Поделиться на других сайтах
1.загрузки XML файла в программу для обработки

я с этим не работал, но наверно там парсится просто хмл файл и пишется во внутреннюю структуру.

каскады хаара например используют хмл, подробнее есть на форуме.

ручное выделение рамки - я так понимаю выделяю сам рамку, а дальше любыми действенными методами пытаюсь следить за объектом который в этой рамке? получается трек.

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

например есть tracking with active contours/snakes или как то так, там объект может так же и несколько видоизменяться в процессе его съемки.

3. сравнить это значит на одном и том же видео я должен получить результаты (конкретнее, координаты точек, трека) а далее сравнить эти результаты (ВАЖНО при одинаковых начальных условиях!) и... я не понимаю в XML файлах числа, которые что-то обозначают ,оокей пусть например это координаты двигающегося объекта, но оригинал видео, обстановки - его же не выкладывают... как я тогда могу сравнить алгоритмы если я не могу провести свой эксперимент над "ихним" видео. А если я буду у себя в лаборатории тестировать алгоритм слежения , то и результаты я получу применительно к своей лаборатории...

а если в общем посмотреть то я уяснил общую мысль - какие то люди записали полученные результаты, чтоб другие могли сравнить свои с "ихними"

да всё правильно, пока можете к этому не обращаться, это нужно только для сравнения хорошо ли работает свой алгоритм по сравнеию с ручным выделением.

тем более я думал, что тестовое видео они тоже выкладывали.

я имел ввиду, код (готовое решение или просто пример) - как мне самому

вариант а) сделать свой XML- каскад , чтоб в дальнейшем использовать его. Я представляю себе это таким образом, я гуляю перед камерой. то иду к ней, то от нее , то перед ней,... все это снимаю на видео, далее терпеливо на каждой картинке запоминаю "КАКИЕ ТО " характеристики себя, не знаю - форму головы и тд , а далее я применяю ПОЛУЧЕННЫЕ ЗНАНИЯ на других людях, и сразу их обнаруживаю! Я правильно думаю?

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

если просто трэкать блоб(движущееся нечто) это одно, если хотим находить где у человека голова где руки и т.д. это другое вроде называется pose estimation.

вариант б) использование чужих каскадов (в виде файлов XML) . Я так понял есть отличная функция cvHaarDetectObjects - ищет все объекты которые подходят под КАКИЕ ТО ХАРАКТЕРИСТИКИ записанные в файле(кстати что это за характеристики такие записаны в XML?). Да хорошо, я вроде научился. Это называется детектор Хаара. Окей! Но в продолжение вот того сайта, я решил узнать что за PETS2009 - нашел этот сайт и "понял что ничего не понял" - там много dataset'ов , каждый dataset ( в переводе "набор данных") что то ведь делает... а как его использовать?? какие функции использовать? они вообще , вот эти dataset для чего?

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

  • Like 1

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


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

2Predatorxxx: лучше тренируйся сразу на том видео, на котором будешь людей подсчитывать. Вы ложи немного его, секунд 30 хватит, чтобы посмотреть. А то не знаю даже, что советовать.

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


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

Добрый день. Вашему вниманию предлагаю готовый вариант сегментации изображения. Любая критика и советы по улучшению очень очень приветствуются!

Использую

- cvCreateFGDStatModel , т.е. как я понимаю это называется Adaptive Background Mixture (или Гауссианов Микшер)

Полный текст программы прикрепляю к этому посту, дабы не засорять свое сообщение. Также я прикрепляю 2 видео - ОРИГИНАЛ и РЕЗУЛЬТАТ ПРОГРАММЫ.

Итак, примерно очерчу алгоритм.

-1 получаю изображение с файла

-2 ВНИМАНИЕ применяю медианную фильтрацию 9х9 на полученный фрейм оригинала

-3 создаю bg_model (функцией, указанной выше) от изображения, полученнного в верхнем пункте (медианно профильтрованного)

-4 получаю два изображения фон и маску для переднего плана

-5 ВНИМАНИЕ bg_model (как я понимаю, вследствии своего алгоритма, создает кучу гауссианов на каждый пиксель, далее как только появляется движение она добавляет гауссианы соответствующие этому движению, а уже ненужные убирает. И получается очень хорошее выделение переднего плана. Далее когда человек уходит из кадра, она убирает эти гауссианы и тут начинается глюк метода, он выдает мерцающие точки, из за того что он убрал некоторые гауссианы похоже) [спасибо mr gloom за ссылочку про вычитание фона, там все очень хорошо написано про этот алгоритм]. На видео, которое показывает результат очень хорошо видно в самом начале неведомую огромную белую фигню которая убирается методом описанном ниже. Также она описывается комментарием в коде.

-6 чтобы убрать глюки bg_model я каждые 10 кадров беру "вычитание фона" то есть разность между текущим кадром и фоном, полученным от bg_model. Если bg_model дает "глюк" то это позиционируется как будто бы есть движение, но на самом деле движения нет, что доказывается вычитанием фона. Еще раз - если реально ничего не двигается, а bg_model выдает маску переднего плана, то сравнивая (каждые 10 кадров) картинку полученную вычитанием фона и передний план выделенный bg_model и если между ними СИЛЬНОЕ различие, я тупо обнуляю bg_model. Подробнее в комментариях в коде

-7 Далее уже "почти без глюков" картинку я подвергаю вначале операции эрозии с кол-вом итераций 6 , таким образом убираю маленькие точки , а потом операцией дилатации (расширения) наращиваю большие контуры, кол-во итераций 15.

-8 Полученную маску накладываю на оригинал - получаю выделенный передний план

Уважаемые форумчане, большая просьба напишите Ваше мнение по поводу след. пунктов

1) стоит ли применять медианную фильтрацию в пункте 2 перед тем как пользоваться bg_model

2) какое кол-во итераций применять в пункте 7 для эрозии и расширения? сразу оговорюсь - пробовал операция закрытия, не получается избавится от маленьких точек

3) как мне дальше вести трекинг, т.е. следить за объектов - у меня возникают проблемы - это контуры не постоянны по форме и меняются (как видно из видео), может быть цветовая гистограмма? может быть оптический поток LK ?

ОЧЕНЬ ЖДУ ВАШИХ КОММЕНТАРИЕВ И ЖЕЛАТЕЛЬНО ОТВЕТОВ НА ВОПРОСЫ. ЗАРАНЕЕ ОГРОМНОЕ СПАСИБО!

segment_v_1_0.txt

  • Like 2

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


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

не знаю что там с Adaptive Background Mixture

насчет дальнейшего сопровождения тут обсуждалось.

http://www.compvision.ru/forum/index.php?showtopic=254

через LK и через Blob tracking сопровождение рассматривалось.

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


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

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

прошу помочь, четвертый час смотрю в программу и не понимаю почему на шаге

cvConvertImage(segment_picture,gray_img,CV_RGB2GRAY); у меня переворачивается изображение?.. а когда выхожу из программы выдает

bad argument (unrecognized or unsuppoorted array type) in unknown function , file ...

а си++ выдает ошибку типа "произошел доступ к ячейке у которой только статус "чтение""

HELP! кто может скомпилируйте программу, или может есть какое то готовое решение уже для трекинга?

и второй вопрос, - может стоит особые точки ставить не один раз как только объект появился а при каждой следующей итерации -

посмотрели куда передвинулся центр масс

сделали прямоугольник

опять заполнили точками

и т.д. А в текущей программе точками прямоугольник заполняется только когда объект впервые обнаруживается, и кол-во точек стремительно уменьшается! Вот как вам моя идея?

p.s. Nuzhny, это же ваша программа - что скажете?

#include "stdafx.h"

#include "iostream"

#include "stdlib.h"

#include "cv.h"

#include "highgui.h"

#include "E:\Станислав\background_segm.hpp"


using namespace std;


bool detect_face(IplImage *gray_img, CvMemStorage *mem_storage, CvRect &face_rect)

{

	cvClearMemStorage(mem_storage);

	//CvSeq *faces = cvHaarDetectObjects(gray_img, haar_cascade, mem_storage, 1.1, 2, 0, cvSize(20, 20));

	CvSeq* faces = 0;

	cvFindContours(gray_img, mem_storage, &faces, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );

	if (!faces || !faces->total)

		return false;

	face_rect = cvBoundingRect(faces, 0);

	return true;

	//Возвращаем первое найденное   


	/*

	face_rect = cvBoundingRect(faces, 0);

	for( ; faces!=0 ; faces = faces->h_next )

	{

		if (faces->total > 100)

		face_rect = cvBoundingRect(faces, 0);

		return true;

	}

	return false;*/

	//cvDrawRect(gray_img, cvPoint(face_rect.x, face_rect.y), cvPoint(face_rect.x + face_rect.width, face_rect.y + face_rect.height), cvScalar(255, 0, 0));


}



class LKData

{

private:

	//Всякие данные

	IplImage *curr_img;

	IplImage *prev_img;

	IplImage *curr_pyramid_img;

	IplImage *prev_pyramid_img;


	int points_count;

	CvPoint2D32f *curr_points;

	CvPoint2D32f *prev_points;

	char *status;


	CvTermCriteria tc;

	int flags;


public:

	LKData()

		: curr_img(NULL), prev_img(NULL), curr_pyramid_img(NULL), prev_pyramid_img(NULL),

		points_count(0), flags(0), curr_points(NULL), prev_points(NULL), status(NULL)

	{

		tc = cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03);

		cvNamedWindow("points", 1);

	}

	////////////////////////////////////////////////////////////////////////////

	~LKData()

	{

		deinit();

		cvDestroyWindow("points");

	}

	////////////////////////////////////////////////////////////////////////////

	//Инициализация данных для сопровождения

	void init(const IplImage *gray_img, const CvRect &face_rect)

	{

		deinit();


		curr_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1);

		prev_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1);

		curr_pyramid_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1);

		prev_pyramid_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1);


		//Покроем прямоугольник лица равномерной сеткой из точек

		const int step_x = face_rect.width / 16;

		const int step_y = face_rect.height / 16;

		points_count = (face_rect.width / step_x + 1) * (face_rect.height / step_y + 1);

		curr_points = new CvPoint2D32f[points_count];

		prev_points = new CvPoint2D32f[points_count];

		status = new char[points_count];


		size_t pc = 0;

		for (int i = face_rect.y, stop_i = face_rect.y + face_rect.height; i < stop_i; i += step_y)

		{

			for (int j = face_rect.x, stop_j = face_rect.x + face_rect.width; j < stop_j; j += step_x)

			{

				curr_points[pc] = cvPoint2D32f((float)j, (float)i);

				++pc;

			}

		}

		points_count = (int)pc;


		cvCopyImage(gray_img, curr_img);

		cvFindCornerSubPix(curr_img, curr_points, points_count, cvSize(3, 3), cvSize(-1, -1), tc);


		//Смена указателей на параметры

		std::swap(prev_img, curr_img);

		std::swap(prev_pyramid_img, curr_pyramid_img);

		std::swap(prev_points, curr_points);

	}

	////////////////////////////////////////////////////////////////////////////

	//Деинициализация данных для сопровождения

	void deinit()

	{

		if (curr_img)

		{

			cvReleaseImage(&curr_img);

			curr_img = NULL;

		}

		if (prev_img)

		{

			cvReleaseImage(&prev_img);

			prev_img = NULL;

		}

		if (curr_pyramid_img)

		{

			cvReleaseImage(&curr_pyramid_img);

			curr_pyramid_img = NULL;

		}

		if (prev_pyramid_img)

		{

			cvReleaseImage(&prev_pyramid_img);

			prev_pyramid_img = NULL;

		}


		points_count = 0;

		flags = 0;


		if (curr_points)

		{

			delete []curr_points;

			curr_points = NULL;

		}

		if (prev_points)

		{

			delete []prev_points;

			prev_points = NULL;

		}

		if (status)

		{

			delete []status;

			status = NULL;

		}

	}

	////////////////////////////////////////////////////////////////////////////

	//Сопровождение лица

	bool tracking_face(IplImage *gray_img, CvRect &face_rect)

	{

		cvCopyImage(gray_img, curr_img);


		//Вычисление нового положения точек с помощью пирамидального алгоритма анализа оптического потока Лукаса-Канаде

		cvCalcOpticalFlowPyrLK(prev_img, curr_img, prev_pyramid_img, curr_pyramid_img,

			prev_points, curr_points, points_count, cvSize(20, 20), 3, status, 0, tc, flags);

		flags |= CV_LKFLOW_PYR_A_READY;


		if (!points_count)

			return false;


		//Удаление не найденных точек, а также вычисление координат описывающего прямоугольника

		float left = std::numeric_limits<float>::max();

		float top = std::numeric_limits<float>::max();

		float right = std::numeric_limits<float>::min();

		float bottom = std::numeric_limits<float>::min();


		//Центр масс

		CvPoint2D32f mc = cvPoint2D32f(0.f, 0.f);


		int k = 0;

		for (int i = 0; i < points_count; ++i)

		{

			if (status[i])

			{

				curr_points[k] = curr_points[i];


				if (curr_points[k].x < left)

					left = curr_points[k].x;

				if (curr_points[k].x > right)

					right = curr_points[k].x;


				if (curr_points[k].y < top)

					top = curr_points[k].y;

				if (curr_points[k].y > bottom)

					bottom = curr_points[k].y;


				mc.x += curr_points[k].x;

				mc.y += curr_points[k].y;


				++k;

			}

		}

		points_count = k;


		mc.x /= (float)points_count;

		mc.y /= (float)points_count;


		//Вычисление расстояния от центра масс, до ближайших сторон описывающего прямоугольника

		float min_x = std::min(mc.x - left, right - mc.x);

		float min_y = std::min(mc.y - top, bottom - mc.y);


		//Границы описывающего прямоугольника пересчитываются с учётом полученных минимальных значений + небольшой отступ на всякий случай

		left = mc.x - min_x - min_x / 4.f;

		right = mc.x + min_x + min_x / 4.f;

		top = mc.y - min_y - min_y / 4.f;

		bottom = mc.y + min_y + min_y / 4.f;


		//Удаление точек, которые не попали в новый      прямоугольник

		k = 0;

		for (int i = 0; i < points_count; ++i)

		{

			if (curr_points[i].x > left &&

				curr_points[i].x < right &&

				curr_points[i].y > top &&

				curr_points[i].y < bottom)

			{

				curr_points[k] = curr_points[i];


				//Вывод точек

				cvDrawCircle(gray_img, cvPoint((int)curr_points[k].x, (int)curr_points[k].y), 1, cvScalar(255, 0, 255));

				++k;

			}

		}

		points_count = k;


		printf("points_count = %i\n", points_count);


		face_rect.x = (int)left;

		face_rect.y = (int)top;

		face_rect.width = (int)(right - left);

		face_rect.height = (int)(bottom - top);


		//Смена указателей на параметры

		std::swap(prev_img, curr_img);

		std::swap(prev_pyramid_img, curr_pyramid_img);

		std::swap(prev_points, curr_points);


		cvShowImage("points", gray_img);


		return true;

	}

};


int main(int argc, char* argv[])

{

	CvCapture *input;

	input = cvCaptureFromAVI("E:\\Станислав\\T_CAMERA.avi");

	if (!input)	{ cout << "Can't open file" ; }


	IplImage* colourImage = cvQueryFrame(input);

	CvSize imgSize = cvGetSize(colourImage);

	cvZero(colourImage);


	bool update_bg_model = false;

	CvBGStatModel* bg_model = 0;


	LKData lk_data;

	enum detector_states //Состояния нашего детектора

	{		find_face,		track_face	};

	detector_states state = find_face;


	int fr;

	int was_update = 5;


	IplImage* segment_picture= cvCreateImage( imgSize, IPL_DEPTH_8U, 3);

	IplImage* difference =cvCreateImage( imgSize, IPL_DEPTH_8U, 3) ;

	IplImage* greyImage = cvCreateImage( imgSize, IPL_DEPTH_8U, 1);

	IplImage* temp = cvCreateImage( imgSize, IPL_DEPTH_8U, 3);

	IplImage* gray_img = cvCreateImage(imgSize, IPL_DEPTH_8U, 1);

	IplImage* mask=cvCreateImage( imgSize, IPL_DEPTH_8U, 1);

	uchar* ptrFON;

	uchar* ptrFG;

	int i,j,k,j1;

	CvRect face_rect;

	CvMemStorage *mem_storage = cvCreateMemStorage(0);

	for(;

	{

		cvZero(segment_picture);

		colourImage = cvQueryFrame(input);

		if( !colourImage )		{			break;		}

		cvShowImage("ORIGINAL", colourImage);


		cvCvtColor(colourImage, gray_img, CV_RGB2GRAY);


		cvSmooth(colourImage,temp, CV_MEDIAN,9,9,5,5);

		cvShowImage("smooth",temp);

		if(!bg_model)

		{

			bg_model = cvCreateFGDStatModel(temp);

			continue;

		}


		//double t = (double)cvGetTickCount();

		cvUpdateBGStatModel(temp, bg_model, /*update_bg_model ? -1 : 0 */ -1);

	//	t = (double)cvGetTickCount() - t;

		//printf( "%d. %.1f\n", fr, t/(cvGetTickFrequency()*1000.) );


		cvShowImage("BG", bg_model->background);//задний план

		cvCopy(bg_model->foreground,mask);//передний план

		cvShowImage("fg0",mask);

		cvErode(mask, mask, 0, 6);

		cvDilate(mask, mask, 0, 15);


	if (was_update % 10 ==0) 

			{

			cvAbsDiff(colourImage,bg_model->background,difference);

			cvCvtColor(difference,greyImage,CV_RGB2GRAY);

			cvThreshold(greyImage, greyImage, 70, 255, CV_THRESH_BINARY);

			cvDilate(greyImage, greyImage, 0, 9);

			cvErode(greyImage, greyImage, 0, 5);

			ptrFON = (uchar*) (greyImage->imageData);

			ptrFG = (uchar*) (mask->imageData);

			k=0;

			for(i=0;i<mask->height;i++)

				for(j=0;j<mask->width;j++)

				{

				for(j1=0;j1<3;j1++)

						k+=abs(ptrFON[j*3+i*mask->widthStep+j1]-ptrFG[j*3+i*mask->widthStep+j1]);

				}

				if (k>= 90000000)

				{

					bg_model = 0;

					printf("Background NULLED! k = %d \n", k);

					was_update=0;

				}

			}

			was_update++;


			cvCopy(colourImage,segment_picture,mask);

			cvShowImage("segment_picture",segment_picture);


			//cvConvertImage(segment_picture,gray_img,CV_RGB2GRAY);

			//cvConvertImage(gray_img,gray_img);

			cvZero(greyImage);

			cvZero(gray_img);

			cvConvertImage(segment_picture,gray_img,CV_RGB2GRAY);

			cvShowImage("12468",gray_img);

				switch (state)

				{

				case find_face: //Поиск лица

					if (detect_face(gray_img, mem_storage, face_rect))

					{

						//Лицо найдено, инициализируем данные для сопровождения и меняем состояние

						lk_data.init(gray_img, face_rect);


						state = track_face;

					}

					break;


				case track_face: //Сопровождение лица

					if (!lk_data.tracking_face(gray_img, face_rect))

					{

						//Лицо потеряно, деинициализируем данные сопровождения и меняем состояние

						lk_data.deinit();

						state = find_face;

					}

					break;

				}


				cvDrawRect(segment_picture, cvPoint(face_rect.x, face_rect.y), cvPoint(face_rect.x + face_rect.width, face_rect.y + face_rect.height), cvScalar(255, 0, 0));

				cvShowImage("frame!!!!!!!!!!!!!!!!!!!!!!!!!", segment_picture);




			CHAR c = cvWaitKey(0); 

			if(c == 27)break;

		/*	if( c == '1' )

			{

			    update_bg_model = !update_bg_model;

				if(update_bg_model)

					printf("Background update is on\n");

				else

					printf("Background update is off\n");

			}*/

	}


	cvReleaseCapture(&input);

	cvClearMemStorage(mem_storage);

	cvReleaseImage(&segment_picture);

	cvReleaseImage(&difference);

	cvReleaseImage(&greyImage);

	cvReleaseImage(&gray_img);

	cvReleaseImage(&mask);

	cvReleaseImage(&temp);

	cvReleaseImage(&colourImage);




	return 0;


}[/code]

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


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

По поводу переворота, может быть параметр IplImage->origin поменять?

origin:

0 - top-left origin, 1 - bottom-left origin (Windows bitmap style)

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

По поводу ошибки при закрытии, то это скорее всего связано с освобождением colourImage, чего делать не нужно, так как не Вы его выделяли.

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


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

По поводу переворота: Вот так нельзя писать cvConvertImage(segment_picture,gray_img,CV_RGB2GRAY);

Надо просто cvConvertImage(segment_picture,gray_img); Он автоматически преобразует первый аргумент во второй, смотря скольки канальные изображения.

p.s. можно добавить третий аргумент в эту функцию тогда она будет переворачивать изображение по вертикали. собственно cvConvertImage(segment_picture,gray_img,CV_RGB2GRAY); в таком варианте она и будет переворачивать)) B)

Сейчас я попробую добавлять точки по мере их уменьшения, или просто на каждом кадре заново засеивать точками изображение

Все же решил засеивать заново на каждом кадре... Кстати намного лучше стало трекать!

Итого - вычитание фона гауссиановым микшером, далее нахожу объект у которого пикселей много , всякие шумы меня типо не интересуют

потом засеиваю точками - смотрю куда передвинулись, рисую линию между ними, опять засеиваю точками!

:thumbsu: вот так получается!!! попробуйте

#include "stdafx.h"

#include "iostream"

#include "stdlib.h"

#include "cv.h"

#include "highgui.h"

#include "E:\Станислав\background_segm.hpp"


using namespace std;


bool detect_face(IplImage *gray_img, CvMemStorage *mem_storage, CvRect &face_rect)

{

	cvClearMemStorage(mem_storage);

	//CvSeq *faces = cvHaarDetectObjects(gray_img, haar_cascade, mem_storage, 1.1, 2, 0, cvSize(20, 20));

	CvSeq* faces = 0;

	cvFindContours(gray_img, mem_storage, &faces, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );

	if (!faces || !faces->total)

		return false;

	//face_rect = cvBoundingRect(faces, 0);

//	return true;

	//Возвращаем первое найденное   



	face_rect = cvBoundingRect(faces, 0);

	for( ; faces!=0 ; faces = faces->h_next )

	{

		if (faces->total > 200)

		face_rect = cvBoundingRect(faces, 0);

		return true;

	}

	return false;

	//cvDrawRect(gray_img, cvPoint(face_rect.x, face_rect.y), cvPoint(face_rect.x + face_rect.width, face_rect.y + face_rect.height), cvScalar(255, 0, 0));


}



class LKData

{

private:

	//Всякие данные

	IplImage *curr_img;

	IplImage *prev_img;

	IplImage *curr_pyramid_img;

	IplImage *prev_pyramid_img;


	int points_count;

	CvPoint2D32f *curr_points;

	CvPoint2D32f *prev_points;

	char *status;


	CvTermCriteria tc;

	int flags;


public:

	LKData()

		: curr_img(NULL), prev_img(NULL), curr_pyramid_img(NULL), prev_pyramid_img(NULL),

		points_count(0), flags(0), curr_points(NULL), prev_points(NULL), status(NULL)

	{

		tc = cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03);

		cvNamedWindow("points", 1);

	}

	////////////////////////////////////////////////////////////////////////////

	~LKData()

	{

		deinit();

		cvDestroyWindow("points");

	}

	////////////////////////////////////////////////////////////////////////////

	//Инициализация данных для сопровождения

	void init(const IplImage *gray_img, const CvRect &face_rect)

	{

		deinit();


		curr_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1);

		prev_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1);

		curr_pyramid_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1);

		prev_pyramid_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1);


		//Покроем прямоугольник лица равномерной сеткой из точек

		//сразу записываются в массв prev_points с их координатами

		const int step_x = face_rect.width / 16;

		const int step_y = face_rect.height / 16;


		points_count = (face_rect.width / step_x + 1) * (face_rect.height / step_y + 1);

		curr_points = new CvPoint2D32f[points_count];

		prev_points = new CvPoint2D32f[points_count];

		status = new char[points_count];


		size_t pc = 0;

		for (int i = face_rect.y, stop_i = face_rect.y + face_rect.height; i < stop_i; i += step_y)

		{

			for (int j = face_rect.x, stop_j = face_rect.x + face_rect.width; j < stop_j; j += step_x)

			{

				curr_points[pc] = cvPoint2D32f((float)j, (float)i);

				++pc;

			}

		}

		points_count = (int)pc;


		cvCopyImage(gray_img, curr_img);

		cvFindCornerSubPix(curr_img, curr_points, points_count, cvSize(3, 3), cvSize(-1, -1), tc);


		//Смена указателей на параметры

		std::swap(prev_img, curr_img);

		std::swap(prev_pyramid_img, curr_pyramid_img);

		std::swap(prev_points, curr_points);

	}

	////////////////////////////////////////////////////////////////////////////

	//Деинициализация данных для сопровождения

	void deinit()

	{

		if (curr_img)

		{

			cvReleaseImage(&curr_img);

			curr_img = NULL;

		}

		if (prev_img)

		{

			cvReleaseImage(&prev_img);

			prev_img = NULL;

		}

		if (curr_pyramid_img)

		{

			cvReleaseImage(&curr_pyramid_img);

			curr_pyramid_img = NULL;

		}

		if (prev_pyramid_img)

		{

			cvReleaseImage(&prev_pyramid_img);

			prev_pyramid_img = NULL;

		}


		points_count = 0;

		flags = 0;


		if (curr_points)

		{

			delete []curr_points;

			curr_points = NULL;

		}

		if (prev_points)

		{

			delete []prev_points;

			prev_points = NULL;

		}

		if (status)

		{

			delete []status;

			status = NULL;

		}

	}

	////////////////////////////////////////////////////////////////////////////

	//Сопровождение лица

	bool tracking_face(IplImage *gray_img, CvRect &face_rect)

	{

		cvCopyImage(gray_img, curr_img);


		//Вычисление нового положения точек с помощью пирамидального алгоритма анализа оптического потока Лукаса-Канаде

		cvCalcOpticalFlowPyrLK(prev_img, curr_img, prev_pyramid_img, curr_pyramid_img,

			prev_points, curr_points, points_count, cvSize(20, 20), 3, status, 0, tc, flags);

		flags |= CV_LKFLOW_PYR_A_READY;


		if (!points_count)

			return false;


		//Удаление не найденных точек, а также вычисление координат описывающего прямоугольника

		float left = std::numeric_limits<float>::max();

		float top = std::numeric_limits<float>::max();

		float right = std::numeric_limits<float>::min();

		float bottom = std::numeric_limits<float>::min();


		//Центр масс

		CvPoint2D32f mc = cvPoint2D32f(0.f, 0.f);


		int k = 0;

		for (int i = 0; i < points_count; ++i)

		{

			if (status[i])

			{

				curr_points[k] = curr_points[i];


				if (curr_points[k].x < left)

					left = curr_points[k].x;

				if (curr_points[k].x > right)

					right = curr_points[k].x;


				if (curr_points[k].y < top)

					top = curr_points[k].y;

				if (curr_points[k].y > bottom)

					bottom = curr_points[k].y;


				mc.x += curr_points[k].x;

				mc.y += curr_points[k].y;


				++k;

			}

		}

		points_count = k;


		mc.x /= (float)points_count;

		mc.y /= (float)points_count;


		//Вычисление расстояния от центра масс, до ближайших сторон описывающего прямоугольника

		float min_x = std::min(mc.x - left, right - mc.x);

		float min_y = std::min(mc.y - top, bottom - mc.y);


		//Границы описывающего прямоугольника пересчитываются с учётом полученных минимальных значений + небольшой отступ на всякий случай

		/*left = mc.x - min_x - min_x / 4.f;

		right = mc.x + min_x + min_x / 4.f;

		top = mc.y - min_y - min_y / 4.f;

		bottom = mc.y + min_y + min_y / 4.f;*/

		left = mc.x - min_x ;

		right = mc.x + min_x;

		top = mc.y - min_y;

		bottom = mc.y + min_y;



		//Удаление точек, которые не попали в новый      прямоугольник

		k = 0;

		for (int i = 0; i < points_count; ++i)

		{

			if (curr_points[i].x > left &&

				curr_points[i].x < right &&

				curr_points[i].y > top &&

				curr_points[i].y < bottom)

			{

				curr_points[k] = curr_points[i];


				//Вывод точек

				cvDrawCircle(gray_img, cvPoint((int)curr_points[k].x, (int)curr_points[k].y), 1, cvScalar(255, 0, 255));

				++k;

			}

		}


		points_count = k;

			if (k!=0) {

		face_rect.x = (int)left;

		face_rect.y = (int)top;

		face_rect.width = (int)(right - left);

		face_rect.height = (int)(bottom - top);

		if (curr_points)		{			delete []curr_points;			curr_points = NULL;		}

		if (prev_points)		{			delete []prev_points; 			prev_points = NULL; 		}

		if (status)		{			delete []status; 			status = NULL;		}


		const int step_x = face_rect.width / 16;

		const int step_y = face_rect.height / 16;

		if (step_x==0||step_y==0) return false;

		points_count = (face_rect.width / step_x + 1) * (face_rect.height / step_y + 1);

		curr_points = new CvPoint2D32f[points_count];

		prev_points = new CvPoint2D32f[points_count];

		status = new char[points_count];


			//curr_points = NULL;

		size_t pc = 0;



		for (int i = face_rect.y, stop_i = face_rect.y + face_rect.height; i < stop_i; i += step_y)

		{

			for (int j = face_rect.x, stop_j = face_rect.x + face_rect.width; j < stop_j; j += step_x)

			{

				curr_points[pc] = cvPoint2D32f((float)j, (float)i);

				++pc;

			}

		}

		points_count = (int)pc;

		cvFindCornerSubPix(curr_img, curr_points, points_count, cvSize(3, 3), cvSize(-1, -1), tc);

			}

		printf("points_count = %i\n", points_count);




		//Смена указателей на параметры

		std::swap(prev_img, curr_img);

		std::swap(prev_pyramid_img, curr_pyramid_img);

		std::swap(prev_points, curr_points);


		cvShowImage("points", gray_img);


		return true;

	}

};


int main(int argc, char* argv[])

{

	CvCapture *input;

	input = cvCaptureFromAVI("E:\\Станислав\\T_CAMERA.avi");

	if (!input)	{ cout << "Can't open file" ; }


	IplImage* colourImage = cvQueryFrame(input);

	CvSize imgSize = cvGetSize(colourImage);

	cvZero(colourImage);


	bool update_bg_model = false;

	CvBGStatModel* bg_model = 0;


	LKData lk_data;

	enum detector_states //Состояния нашего детектора

	{		find_face,		track_face	};

	detector_states state = find_face;


	int fr;

	int was_update = 5;


	IplImage* segment_picture= cvCreateImage( imgSize, IPL_DEPTH_8U, 3);

	IplImage* segment_picture1= cvCreateImage( imgSize, IPL_DEPTH_8U, 3);

	IplImage* difference =cvCreateImage( imgSize, IPL_DEPTH_8U, 3) ;

	IplImage* greyImage = cvCreateImage( imgSize, IPL_DEPTH_8U, 1);

	IplImage* temp = cvCreateImage( imgSize, IPL_DEPTH_8U, 3);

	IplImage* gray_img = cvCreateImage(imgSize, IPL_DEPTH_8U, 1);

	IplImage* mask=cvCreateImage( imgSize, IPL_DEPTH_8U, 1);

	uchar* ptrFON;

	uchar* ptrFG;

	int i,j,k,j1;

	CvRect face_rect;

	CvRect prev_face_rect;

	CvMemStorage *mem_storage = cvCreateMemStorage(0);

	for(;

	{

		cvZero(segment_picture);

		colourImage = cvQueryFrame(input);

		if( !colourImage )		{			break;		}

		cvShowImage("ORIGINAL", colourImage);


		//cvCvtColor(colourImage, gray_img, CV_RGB2GRAY);


		cvSmooth(colourImage,temp, CV_MEDIAN,9,9,5,5);

		cvShowImage("smooth",temp);

		if(!bg_model)

		{

			bg_model = cvCreateFGDStatModel(temp);

			continue;

		}


		//double t = (double)cvGetTickCount();

		cvUpdateBGStatModel(temp, bg_model, /*update_bg_model ? -1 : 0 */ -1);

	//	t = (double)cvGetTickCount() - t;

		//printf( "%d. %.1f\n", fr, t/(cvGetTickFrequency()*1000.) );


		cvShowImage("BG", bg_model->background);//задний план

		cvCopy(bg_model->foreground,mask);//передний план

		cvShowImage("fg0",mask);

		cvErode(mask, mask, 0, 6);

		cvDilate(mask, mask, 0, 15);


	if (was_update % 10 ==0) 

			{

			cvAbsDiff(colourImage,bg_model->background,difference);

			cvCvtColor(difference,greyImage,CV_RGB2GRAY);

			cvThreshold(greyImage, greyImage, 70, 255, CV_THRESH_BINARY);

			cvDilate(greyImage, greyImage, 0, 9);

			cvErode(greyImage, greyImage, 0, 5);

			ptrFON = (uchar*) (greyImage->imageData);

			ptrFG = (uchar*) (mask->imageData);

			k=0;

			for(i=0;i<mask->height;i++)

				for(j=0;j<mask->width;j++)

				{

				for(j1=0;j1<3;j1++)

						k+=abs(ptrFON[j*3+i*mask->widthStep+j1]-ptrFG[j*3+i*mask->widthStep+j1]);

				}

				if (k>= 90000000)

				{

					bg_model = 0;

					printf("Background NULLED! k = %d \n", k);

					was_update=0;

				}

			}

			was_update++;


			cvCopy(colourImage,segment_picture,mask);

			cvShowImage("segment_picture",segment_picture);


			//cvConvertImage(segment_picture,gray_img,CV_RGB2GRAY);

			//cvConvertImage(gray_img,gray_img);

			cvZero(greyImage);

			cvZero(gray_img);

			cvConvertImage(segment_picture,gray_img);


			cvShowImage("12468",gray_img);


			//****************************************************************


				switch (state)

				{

				case find_face: //Поиск лица

					if (detect_face(gray_img, mem_storage, face_rect))

					{

						//Лицо найдено, инициализируем данные для сопровождения и меняем состояние

						lk_data.init(gray_img, face_rect);

						prev_face_rect=face_rect;

						state = track_face;

					}

					break;


				case track_face: //Сопровождение лица

					if (!lk_data.tracking_face(gray_img, face_rect))

					{

						//Лицо потеряно, деинициализируем данные сопровождения и меняем состояние

						lk_data.deinit();

						state = find_face;

						prev_face_rect.width=0;

						cvZero(segment_picture1);

					}

					break;

				}

				if (prev_face_rect.width!=0){

				cvLine(segment_picture1,cvPoint(prev_face_rect.x+prev_face_rect.width/2 , prev_face_rect.y+prev_face_rect.height/2),cvPoint(face_rect.x+face_rect.width/2,face_rect.y+face_rect.height/2),cvScalar(100,100,100),3);

				prev_face_rect=face_rect;}


				cvDrawRect(segment_picture, cvPoint(face_rect.x, face_rect.y), cvPoint(face_rect.x + face_rect.width, face_rect.y + face_rect.height), cvScalar(255, 0, 0));

				cvShowImage("frame!!!!!!!!!!!!!!!!!!!!!!!!!", segment_picture);

			cvShowImage("treking", segment_picture1);



			CHAR c = cvWaitKey(1); 

			if(c == 27)break;

		/*	if( c == '1' )

			{

			    update_bg_model = !update_bg_model;

				if(update_bg_model)

					printf("Background update is on\n");

				else

					printf("Background update is off\n");

			}*/

	}


	cvReleaseCapture(&input);

	cvClearMemStorage(mem_storage);

	cvReleaseImage(&segment_picture);

	cvReleaseImage(&difference);

	cvReleaseImage(&greyImage);

	cvReleaseImage(&gray_img);

	cvReleaseImage(&mask);

	cvReleaseImage(&temp);




	return 0;


}[/code]

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


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

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

1.Вначале я делаю выделение переднего плана Гауссиановым микшером.

2.Далее я использую метод "Шаблонов движения". этот метод нам выдает некоторые точки которые движутся.

3.Далее я анализирую эти точки - относятся ли они к одному контуру. Для этого из переднего плана я выделяю все контуры. Далее проверяю каждую точку найденную методом Motion Templates.

4. Если в контуре находятся много точек , я беру их центр масс (среднюю точку)

5. ЧТобы понять куда передвинулся контур на следующем кадре я опять нахожу центры масс контуров и анализирую на предмет близости (если точка была с координатами (2,2) то из точек (6,8) и (10,20) я выберу (6,8) , т.е мой объект передвинулся из (2,2) в (6,8) . Также проверка на "не резкое" изменение вектора скорости.

Уважаемые форумчане подскажите пожалуйста имеет ли смысл реализовывать такой алгоритм?

PS

Напомню, моя задача состоит в том чтобы посчитать сколько людей проходит через заданную горизонтальную линию в одном направлении и в другом , например поток людей входящих и выходящих из комнаты. Так как моя в конце моя программа должна будет записана на микропроцессор, то мне приходится заботиться чтобы программа не задействовала много памяти и имела высокое быстродействие. Поэтому я решил попробовать использовать не оптический поток а немного попроще. Как вы считаете стоит ли сейчас думать над выше представленным методом или оставить оптический поток? Уважаемые форумчане, Вы несомненно больше знаете по этой тематике прошу дайте совет. ^_^

post-4978-0-64273700-1340363692_thumb.jp

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


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

Спасибо большое! Я его посмотрю в ближайшее время

а сегодня я реализовал трекер следующего плана:

1) выделяю передний план гауссиановым микшером

ПЕРВЫЙ КАДР

2) выделяю все контуры (описываю каждый из найденных ПРЯМОУГОЛЬНИКОМ)

3) регистрирую их (в первый раз), т.е. координаты центров масс сую в массив

ВТОРОЙ ПЛЮС КАДР

4) выделяю все контуры

5) если контур очень далеко находится от всех ранее зарегистрированных контуров то регистрирую его как новый контур

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

7) таким образом у меня есть три типа объектов

новые объекты - те у которых есть новая координата , но нет предыдущей

продолжающие - те у кого есть и старая и новая координата, получается трек

удаляемые - те у кого новой координаты нет а старая есть

на этом принципе построил трекер - и очень хорошо подходит для 1 человека который ходит туда сюда через проход. 2 человека не определит так как прямоугольники сольются и 2 разных объекта будут считаться как за один ... вот

p.s

дальнейшие планы : посмотреть трекер который мне прислал уважаемый mrgloom, и то что ранее было в этой теме. :thumbsu:

С blob_track до сих пор как то не очень разобрался, но постараюсь.

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


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

Добрый день! mrgloom, я посмотрел http://www.codeproject.com/Articles/22243/Real-Time-Object-Tracker-in-C

Ну во-первых, это не трекер. Суть его программы в том, что он

1. фотографирует фон

2. вычитает из фона текущее изображение, получает передний план

3. разбивает на квадратики все изображение, и каждой компактной области дает свой порядковый номер.

И это происходит на каждом кадре, как же он определяет что

1) первая область действительно передвигается на то место а не на другое. то есть нет связи никакой между предыдущим и текущим положением

2) если два объекта в обнимку пойдут, то он их определит как за один.

Дабы не занимать много места кодом я свою программу, которую описал в предыдущем посте прикрепляю в виде текстового документа сюда (в архиве docx).

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

Какие функции можно использовать?

Пример который в OpenCv blob tracks я не понимаю, кто нибудь может мне объяснить? как он работает?

КОД2 - ТРЕКИНГ ПРЯМОУГОЛЬНИКОВ.rar

post-4978-0-15615700-1341228313_thumb.jp

post-4978-0-27072100-1341228331_thumb.jp

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


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

Вот здесь что означают параметры? Я сколько не читал мануал найти не могу...

post-4978-0-82074800-1341230543_thumb.jp

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


Ссылка на сообщение
Поделиться на других сайтах
Вот идут два человека в обнимку, как их разделить друг от друга.

очевидно, что никак, если мы не знаем, что ищем людей, т.е. не определили, что такое человек и не обучили программу.

есть вроде какие то наработки по поиску людей по туловищу или отдельных частей тел.

вот тут посмотрите

http://graphics.cs.msu.ru/en/science/research/machinelearning/hough

http://www.vision.ee.ethz.ch/~gallju/projects/houghforest/index.html

есть еще подход типа bag of words\bag of features, т.е. типа если мы нашли нос и руку(утрированно), то можно с какой то % вероятностью сказать, что это человек.

если такие как у вас картинки, то можно по головам.

с какой версии блобтрэк? раньше помоему простой был всего лишь по цвету.

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

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

×