Jump to content
Compvision.ru
Sign in to follow this  
Cfr

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

Recommended Posts

Ок спасибо большое, а в OpenCV есть ли примеры фильтра частиц или может быть у них как-нибудь класс называется

Share this post


Link to post
Share on other sites

Есть, но вроде сейчас не поддерживается разработчиками.

См. CvConDensation.

Посмотрите здесь: http://answers.ros.org/question/55316/using-the-opencv-particle-filter-condensation/

Share this post


Link to post
Share on other sites

спасибо за ссылку разбираюсь ниже прикрепляю код из ссылки


// Example of how to use the OpenCV Particle Filter.

// 

// Stolen largely from morethantechnical.com's nice mouse_kalman project.

//


#include <iostream>

#include <vector>


#include <opencv2/highgui/highgui.hpp>

#include <opencv2/video/tracking.hpp>

#include <opencv2/legacy/legacy.hpp>


using namespace std;


#define drawCross( center, color, d )                  \

  line( img, cv::Point( center.x - d, center.y - d ),           \

    cv::Point( center.x + d, center.y + d ), color, 2, CV_AA, 0);   \

  line( img, cv::Point( center.x + d, center.y - d ),           \

    cv::Point( center.x - d, center.y + d ), color, 2, CV_AA, 0 )



struct mouse_info_struct { int x,y; };

struct mouse_info_struct mouse_info = {-1,-1}, last_mouse;


vector<cv::Point> mouseV, particleV;

int counter = -1;


// Define this to proceed one click at a time.

//#define CLICK 1

#define PLOT_PARTICLES 1


void on_mouse(int event, int x, int y, int flags, void* param) 

{


#ifdef CLICK

  if (event == CV_EVENT_LBUTTONUP) 

#endif

  {

    last_mouse = mouse_info;

    mouse_info.x = x;

    mouse_info.y = y;

    counter = 0;

  }


}


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

{

  cv::Mat img(650, 650, CV_8UC3);

  char code = (char)-1;


  cv::namedWindow("mouse particle");

  cv::setMouseCallback("mouse particle", on_mouse, 0);


  cv::Mat_<float> measurement(2,1); 

  measurement.setTo(cv::Scalar(0));


  int dim = 2;

  int nParticles = 25;

  float xRange = 650.0;

  float yRange = 650.0;


  float minRange[] = { 0, 0 };

  float maxRange[] = { xRange, yRange };

  CvMat LB, UB;

  cvInitMatHeader(&LB, 2, 1, CV_32FC1, minRange);

  cvInitMatHeader(&UB, 2, 1, CV_32FC1, maxRange);


  CvConDensation* condens = cvCreateConDensation(dim, dim, nParticles);


  cvConDensInitSampleSet(condens, &LB, &UB);


  // The OpenCV documentation doesn't tell you to initialize this

  // transition matrix, but you have to do it.  For this 2D example, 

  // we're just using a 2x2 identity matrix.  I'm sure there's a slicker 

  // way to do this, left as an exercise for the reader.

  condens->DynamMatr[0] = 1.0;

  condens->DynamMatr[1] = 0.0;

  condens->DynamMatr[2] = 0.0;

  condens->DynamMatr[3] = 1.0;  


  for(;

  {


    if (mouse_info.x < 0 || mouse_info.y < 0) 

	{

      imshow("mouse particle", img);

      cv::waitKey(30);

      continue;

    }


    mouseV.clear();

    particleV.clear();


    for(;

	{

      code = (char)cv::waitKey(100);


      if( code > 0 ) break;


#ifdef CLICK

      if (counter++ > 0) {

    continue;

      } 

#endif


      measurement(0) = mouse_info.x;

      measurement(1) = mouse_info.y;


      cv::Point measPt(measurement(0),measurement(1));

      mouseV.push_back(measPt);


      // Clear screen

      img = cv::Scalar::all(100);


      for (int i = 0; i < condens->SamplesNum; i++) 

	  {


		float diffX = (measurement(0) - condens->flSamples[i][0])/xRange;

		float diffY = (measurement(1) - condens->flSamples[i][1])/yRange;


		condens->flConfidence[i] = 1.0 / (sqrt(diffX * diffX + diffY * diffY));


	// plot particles

#ifdef PLOT_PARTICLES

	cv::Point partPt(condens->flSamples[i][0], condens->flSamples[i][1]);

	drawCross(partPt , cv::Scalar(255,0,255), 2);

#endif


      }


      cvConDensUpdateByTime(condens);


      cv::Point statePt(condens->State[0], condens->State[1]);

      particleV.push_back(statePt);


      // plot points

      drawCross( statePt, cv::Scalar(255,255,255), 5 );

      drawCross( measPt, cv::Scalar(0,0,255), 5 );


      for (int i = 0; i < mouseV.size() - 1; i++) {

    line(img, mouseV[i], mouseV[i+1], cv::Scalar(255,255,0), 1);

      }

      for (int i = 0; i < particleV.size() - 1; i++) {

    line(img, particleV[i], particleV[i+1], cv::Scalar(0,255,0), 1);

      }


      imshow( "mouse particle", img );

    }


    if( code == 27 || code == 'q' || code == 'Q' )

      break;

  }


  return 0;

}

[/code]

не могли бы вы пояснить что такое тут

float xRange = 650.0;

float yRange = 650.0;

что это за диапазон такой.. не понятно...

и ещё я собрался попробовать заменить в программе выложенной выше фильтр Калмана на фильтр частиц, в связи с этим возникли следующие вопросы. Могу ли я вообще это делать ну т.к. на пример в случае с тараканами движущихся областей много не будет ли фильтр частиц запущенный для i-го таракана перескакивать на j-го таракана... или это в принципе невозможно?..

Share this post


Link to post
Share on other sites
не могли бы вы пояснить что такое тут

float xRange = 650.0;

float yRange = 650.0;

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

Могу ли я вообще это делать ну т.к. на пример в случае с тараканами движущихся областей много не будет ли фильтр частиц запущенный для i-го таракана перескакивать на j-го таракана... или это в принципе невозможно?

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

Share this post


Link to post
Share on other sites

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

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

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

если это возможно.. то задача значительно усложняется вроде бы...

Share this post


Link to post
Share on other sites

Вот смотрите, фильтр частиц действует так:

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

2) Для этого распределения генерируется N частиц.

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

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

5) Все частицы порождают новое поколение (с немного рандомизированными свойствами), причем каждый родитель порождает количество потомков, пропорциональное полученному на предыдущем шаге значению вероятности (N*P частиц). В сумме имеем опять N частиц.

5.а) Применяем переходный закон. Ну например если система механическая, то будет что то типа x1=x+v*dt; v1=v+a*dt; То есть частицы "знают" динамику объекта.

6) удаляем предыдущее поколение.

7) теперь наши частицы распределены согласно новому закону распределения (полученное на 4-м шаге).

8) считываем максимумы распределения (они и будут объектами).

9) идем на шаг 3.

Share this post


Link to post
Share on other sites

большое спасибо за разъяснения по работе фильтра:) вот ещё вопрос

я составляю класс ParticleFilter по аналогии с классом Kalman из вашей программы. Приведу заголовочный файл


class TKalmanFilter

{

public:

	KalmanFilter* kalman;

	double deltatime; //приращение времени

	Point2f LastResult;

	TKalmanFilter(Point2f p,float dt=0.2,float Accel_noise_mag=0.5);

	~TKalmanFilter();

	Point2f GetPrediction();

	Point2f Update(Point2f p, bool DataCorrect);

};

для класса ParticleFilter всё довольно похоже(там конечно свои параметры) метод GetPrediction() получается довольно просто cv::Point statePt(condens->State[0], condens->State[1]); и у нас есть точка. а вот метод Point2f Update(Point2f p, bool DataCorrect); пока ставит меня в тупик если смотреть на калмана, то там вызывается специальный метод внутреннего класса Калмана для коррекции

// Коррекция

		Mat estimated = kalman->correct(measurement);

		LastResult.x=estimated.at<float>(0);  //уточняем, используя данные измерений

		LastResult.y=estimated.at<float>(1);

ничего похожего у CvConDensation я не нашёл... но как-то же надо обновлять координаты...

Share this post


Link to post
Share on other sites

Тут, как я понял из кода примера фильтра частиц приведенного выше, нужно сначала задать степень вероятности для каждой частицы (не обязательно чтобы они суммировались в 1, нормирование, судя по всему производится фильтром):

condens->flConfidence[i] = 1.0 / (sqrt(diffX * diffX + diffY * diffY));
,затем уточнить состояние фильтра:
cvConDensUpdateByTime(condens);

Share this post


Link to post
Share on other sites

Спасибо за ответ ниже даю ссылки на ролики работы трекера с разными фильтрами, фильтром частиц и фильтром Калмана

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


//condens->flConfidence[i] = exp(1.0 / (sqrt(diffX * diffX + diffY * diffY)));

//condens->flConfidence[i] = exp(-(sqrt(diffX * diffX + diffY * diffY)));

//condens->flConfidence[i] = exp(-((diffX*diffX)/(2*diffX * diffX + 2*diffY * diffY)))*exp(-((diffY*diffY)/(2*diffX * diffX + 2*diffY * diffY)));

//condens->flConfidence[i] = exp(-((diffX*diffX)/(2*xRange *yRange)))*exp(-((diffY*diffY)/(2*xRange *yRange)));

condens->flConfidence[i] = 1.0 / (sqrt(diffX * diffX + diffY * diffY));

ParticleFilter.h

ParticleFilter.cpp

  • Like 2

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

а вот то что периодически возникают полосы от трека в разные стороны это из-за того, что на частицы влияют другие движущиеся объекты?...

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Да, трек живет некоторое время после потери объекта (это задается вроде maximum_allowed_skip_frames или что-то в этом духе).

Это делается для того чтобы он мог "поймать" объект после пропуска детекта.

Т.к. система линейная, то и летит трек по прямой. Эти линии, я полагаю, Вы и имеете ввиду.

Share this post


Link to post
Share on other sites

Да да их они в фильтре частиц очень видны поэтому я подумал, что это выбросы самого фильтра) спасибо за подсказку попробую подправить

Share this post


Link to post
Share on other sites

Пока удалить эти полосы не получилось.. странно ещё то, что для фильтра Калмана их нету, а для фильтра частиц они есть...

Share this post


Link to post
Share on other sites

Еще один трекер с исходниками (не OpenCV):

Домашняя страница: http://perso.ensta-paristech.fr/~garrigues/video_extruder.html

Видео оттуда:

Репозиторий:

Используемая либа: https://github.com/matt-42/cuimg

Сам проект: https://github.com/matt-42/cuimg/tree/master/samples/tracking

  • Like 1

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Думаю, что очень даже можно.

Ещё из интереса можно попробовать подсунуть выход трекера в pcl.

Share this post


Link to post
Share on other sites

что то разговор зашел уже не о трекере

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

http://photosynth.net/discussion.aspx?cat=ceca0f30-0f7c-4468-811a-32b623ea8563&dis=38fa4600-62ec-4c86-94c3-35c1b118766d

но у меня кадры получались смазанными.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

просто есть подозрение, что это зависит от формата в котором храниться видео, почему при проигрывании видео не видно смазанных кадров? потому что они быстро проскакивают?

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

там пишут

due to video compression and camera motion during capture, often video frames will be too blurry or have too much of the visual texture of objects removed in compression for Photosynth to have enough image features to lock onto to form an excellent point cloud.

Share this post


Link to post
Share on other sites

Любые промышленные камеры и почти все камеры для охранного видеонаблюдения. Там важны именно детали на видео, а не красота кадра и сочность картинки. Плохое освещение? Ставьте ИК-прожекторы и ли прожекторы видимого диапазона.

кодеки, конечно, портят видео, добавляя артефакты сжатия, но они специально не делают ни дефокус, ни motion blur. Да и основные потери лежат в основном в цветовых составляющих.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×