Jump to content
Compvision.ru
RinOS

Фильтр Калмана

Recommended Posts

Всем привет!

В книжке по OpenCV есть пример по фильтру Калмана, несколько раз пытался понять листинг, но ни чего непонял...

К тому же тут еще не понятно зачем введены шумы (x_k).

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

#define phi2xy(mat)												  \

  cvPoint( cvRound(img->width/2 + img->width/3*cos(mat->data.fl[0])),\

	cvRound( img->height/2 - img->width/3*sin(mat->data.fl[0])) )


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


	// Initialize, create Kalman Filter object, window, random number

	// generator etc.

	//

	cvNamedWindow( "Kalman", 1 );

	CvRandState rng;

	cvRandInit( &rng, 0, 1, -1, CV_RAND_UNI );


	IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 );

	CvKalman* kalman = cvCreateKalman( 2, 1, 0 );

	// state is (phi, delta_phi) - angle and angular velocity

	// Initialize with random guess.

	//

	CvMat* x_k = cvCreateMat( 2, 1, CV_32FC1 );

	cvRandSetRange( &rng, 0, 0.1, 0 );

	rng.disttype = CV_RAND_NORMAL;

	cvRand( &rng, x_k );


	// process noise

	//

	CvMat* w_k = cvCreateMat( 2, 1, CV_32FC1 );


	// measurements, only one parameter for angle

	//

	CvMat* z_k = cvCreateMat( 1, 1, CV_32FC1 );

	cvZero( z_k );


	// Transition matrix 'F' describes relationship between

	// model parameters at step k and at step k+1 (this is 

	// the "dynamics" in our model.

	//

	const float F[] = { 1, 1, 0, 1 };

	memcpy( kalman->transition_matrix->data.fl, F, sizeof(F));

	// Initialize other Kalman filter parameters.

	//

	cvSetIdentity( kalman->measurement_matrix,	cvRealScalar(1) );

	cvSetIdentity( kalman->process_noise_cov,	 cvRealScalar(1e-5) );

	cvSetIdentity( kalman->measurement_noise_cov, cvRealScalar(1e-1) );

	cvSetIdentity( kalman->error_cov_post,		cvRealScalar(1));


	// choose random initial state

	//

	cvRand( &rng, kalman->state_post );


	while( 1 ) {

		// predict point position

		const CvMat* y_k = cvKalmanPredict( kalman, 0 );


		// generate measurement (z_k)

		//

		cvRandSetRange( 

			&rng, 

			0, 

			sqrt(kalman->measurement_noise_cov->data.fl[0]), 

			0 

		);

		cvRand( &rng, z_k );

		cvMatMulAdd( kalman->measurement_matrix, x_k, z_k, z_k );

		// plot points (eg convert to planar co-ordinates and draw)

		//

		cvZero( img );

		cvCircle( img, phi2xy(z_k), 4, CVX_YELLOW );   // observed state

		cvCircle( img, phi2xy(y_k), 4, CVX_WHITE, 2 ); // "predicted" state

		cvCircle( img, phi2xy(x_k), 4, CVX_RED );	  // real state

		cvShowImage( "Kalman", img );

		// adjust Kalman filter state

		//

		cvKalmanCorrect( kalman, z_k );


		// Apply the transition matrix 'F' (eg, step time forward)

		// and also apply the "process" noise w_k.

		//

		cvRandSetRange( 

			&rng, 

			0, 

			sqrt(kalman->process_noise_cov->data.fl[0]), 

			0 

			);

		cvRand( &rng, w_k );

		cvMatMulAdd( kalman->transition_matrix, x_k, w_k, x_k );


		// exit if user hits 'Esc'

		if( cvWaitKey( 100 ) == 27 ) break;

	}

Share this post


Link to post
Share on other sites

Листинг попытаюсь пояснить (что сам понял) потом. А пока вот что перевел (очень сырой вариант), может чего добавите :)

Фильтр_Кальмана.rar

Share this post


Link to post
Share on other sites
Листинг попытаюсь пояснить (что сам понял) потом. А пока вот что перевел (очень сырой вариант), может чего добавите :)

Фильтр_Кальмана.rar

Есть еще такой класс для двумерных координат, откопал на просторах и-нета (перевел часть комментов, но не тестил правда пока):

Вот файл: Kalman2.rar,

А вот что внутри:

class KalmanFilter
{
public:
KalmanFilter();
~KalmanFilter();

virtual void predictionBegin(float x,float y);
virtual void predictionUpdate(float x,float y);
virtual void predictionReport(CvPoint &pnt);

private:
CvKalman *m_pKalmanFilter;
CvRandState rng;
CvMat* state;
CvMat* process_noise;
CvMat* measurement;
CvMat* measurement_noise;
bool m_bMeasurement;
clock_t m_timeLastMeasurement;
CRITICAL_SECTION mutexPrediction;
};

// Инициализация фильтра Кальмана

KalmanFilter::KalmanFilter()
{
m_timeLastMeasurement = clock();
int dynam_params = 4; // x,y,dx,dy
int measure_params = 2;
m_pKalmanFilter = cvCreateKalman(dynam_params, measure_params);
state = cvCreateMat( dynam_params, 1, CV_32FC1 );

// Генератор случайных чисел
cvRandInit( &rng, 0, 1, -1, CV_RAND_UNI );
cvRandSetRange( &rng, 0, 1, 0 );
rng.disttype = CV_RAND_NORMAL;
cvRand( &rng, state );

process_noise = cvCreateMat( dynam_params, 1, CV_32FC1 ); // (w_k)
measurement = cvCreateMat( measure_params, 1, CV_32FC1 ); // two parameters for x,y (z_k)
measurement_noise = cvCreateMat( measure_params, 1, CV_32FC1 ); // two parameters for x,y (v_k)
cvZero(measurement);

// F matrix data
// F is transition matrix. It relates how the states interact
// For single input fixed velocity the new value
// depends on the previous value and velocity- hence 1 0 1 0
// on top line. Новое значение скорости не зависит от предыдущего
// значения координаты, и зависит только от предыдущей скорости- поэтому 0 1 0 1 on second row
const float F[] =
{
1, 0, 1, 0,//x + dx
0, 1, 0, 1,//y + dy
0, 0, 1, 0,//dx = dx
0, 0, 0, 1,//dy = dy
};
memcpy( m_pKalmanFilter->transition_matrix->data.fl, F, sizeof(F));
cvSetIdentity( m_pKalmanFilter->measurement_matrix, cvRealScalar(1) ); // (H)
cvSetIdentity( m_pKalmanFilter->process_noise_cov, cvRealScalar(1e-5) ); // (Q)
cvSetIdentity( m_pKalmanFilter->measurement_noise_cov, cvRealScalar(1e-1) ); // (R)
cvSetIdentity( m_pKalmanFilter->error_cov_post, cvRealScalar(1));

// choose random initial state
cvRand( &rng, m_pKalmanFilter->state_post );

InitializeCriticalSection(&mutexPrediction);
}

KalmanFilter::~KalmanFilter()
{
// Деструктор
cvReleaseMat( &state );
cvReleaseMat( &process_noise );
cvReleaseMat( &measurement );
cvReleaseMat( &measurement_noise );
cvReleaseKalman( &m_pKalmanFilter );

DeleteCriticalSection(&mutexPrediction);
}



// Устанавливаем значения переменных фильтра на первом шаге
// Если этого не сделать, то объект не будет трекаться
void KalmanFilter::predictionBegin(float x,float y)
{
//В переменной m_pKalmanFilter->state_post хранится предыдущее состояние

m_pKalmanFilter->state_post->data.fl[0] = x; //координата x
m_pKalmanFilter->state_post->data.fl[1] = y; //координата y
m_pKalmanFilter->state_post->data.fl[2] = (float)0; //dx - скорость по x
m_pKalmanFilter->state_post->data.fl[3] = (float)0; //dy - скорость по y
}

void KalmanFilter::predictionUpdate(float x,float y)
{
EnterCriticalSection(&mutexPrediction);
state->data.fl[0] = x; //center x
state->data.fl[1] = y; //center y
m_bMeasurement = true;
LeaveCriticalSection(&mutexPrediction);
}

void KalmanFilter::predictionReport(CvPoint &pnt)
{
clock_t timeCurrent = clock();

EnterCriticalSection(&mutexPrediction);

const CvMat* prediction = cvKalmanPredict( m_pKalmanFilter, 0 );
pnt.x = prediction->data.fl[0];
pnt.y = prediction->data.fl[1];
// Если мы получили действительные данные недавно, тогда используем полученные данные для корректировки
// состояния фильтра. Если мы не получили данные, тогда корректируем состояние фильтра, используя предсказанные значения
if (m_bMeasurement) //(timeCurrent - m_timeLastMeasurement < TIME_OUT_LOCATION_UPDATE) // используем действительные данные
{
m_bMeasurement = false;

}
// Обычно фильтр работает быстрее чем поступают данные измерений..
// Таким образом, можно дать фильтру брать данные из предсказанных значений в промежутках между измерениями
// (делает работу трекера более плавной)
else // используем предсказанные данные
{
state->data.fl[0] = pnt.x;
state->data.fl[1] = pnt.y;
}

// генерируем шум измерения noise(z_k)
cvRandSetRange( &rng, 0, sqrt(m_pKalmanFilter->measurement_noise_cov->data.fl[0]), 0 );
cvRand( &rng, measurement_noise );

// zk = Hk * xk + vk
// measurement = measurement_error_matrix * current_state + measurement_noise
cvMatMulAdd( m_pKalmanFilter->measurement_matrix, state, measurement_noise, measurement );

// уточняем состояние фильтра
cvKalmanCorrect( m_pKalmanFilter, measurement );

// гененрируем шум процесса(w_k)
cvRandSetRange( &rng, 0, sqrt(m_pKalmanFilter->process_noise_cov->data.fl[0]), 0 );
cvRand( &rng, process_noise );

// xk = F * xk-1 + B * uk + wk
// state = transition_matrix * previous_state + control_matrix * control_input + noise
cvMatMulAdd( m_pKalmanFilter->transition_matrix, state, process_noise, state );
LeaveCriticalSection(&mutexPrediction);
}[/code]

Share this post


Link to post
Share on other sites
Есть еще такой класс для двумерных координат, откопал на просторах и-нета (перевел часть комментов, но не тестил правда пока):

За пример спасибо) С помощью него я понял что не могу использовать фильтр Кальмана в моём случае(

Моя цель была найти объект в следующем кадре... Но что бы передать фильтру Кальмана predictionUpdate() надо знать где этот объект находиться...

Share this post


Link to post
Share on other sites

Пример фильтра Кальмана + запись видео в файл. Используется OpenCV2.0. Его DLL надо покидать в видное программе место (можно к exe-шнику в папку)

Kalman_puck.jpg

Архив с проектом: kalman_track.rar

У меня путь к нему: C:\Program Files\Borland\CBuilder6\Projects\Cv2Programs\kalman_track\

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
Пример фильтра Кальмана + запись видео в файл. Используется OpenCV2.0. Его DLL надо покидать в видное программе место (можно к exe-шнику в папку)

Спасибо, пример очень порадовал!

Как бы его переделать под VS2008...

Share this post


Link to post
Share on other sites
Как бы его переделать под VS2008...
Если автор не против, то выложу переделку - делал как-то для себя, поиграть. Немного перегруппировал код, отформатировал по своему вкусу, но всё работает также как и в оригинале:
#include "stdafx.h"
#include <highgui.h>
#include <cv.h>

#pragma comment(lib, "cv.lib")
#pragma comment(lib, "cxcore.lib")
#pragma comment(lib, "highgui.lib")
////////////////////////////////////////////////////////////////////////////
//function to find the biggest blob and to get the top left position
CvPoint2D32f findBigBlob(IplImage *mask)
{
int maxval = 0;
int minval = 100;

//начинаем поиск контуров
CvMemStorage *storage = cvCreateMemStorage(0);
CvContourScanner traverse = cvStartFindContours(mask, storage, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE);

//находим контуры с длиной периметра между minval и maxval
CvSeq *mContour = 0;
for (CvSeq *contour = cvFindNextContour(traverse); contour; contour = cvFindNextContour(traverse))
{
int contourarea = (int)abs(cvContourArea(contour, CV_WHOLE_SEQ));
if (contourarea > maxval)
{
mContour = contour;
maxval = contourarea;
}
}

CvPoint2D32f ret_val = cvPoint2D32f(-1.0, -1.0);
if (maxval > minval)
{
//находим центр масс
CvMoments moments;
cvMoments(mContour, &moments, 0);
ret_val.x = (float)(moments.m10 / moments.m00);
ret_val.y = (float)(moments.m01 / moments.m00);
}

//освобождаем память
cvEndFindContours(&traverse);
cvReleaseMemStorage(&storage);

return ret_val;
}
////////////////////////////////////////////////////////////////////////////
//находим участки, подходящие нам по цвету (шайба)
void region_color_range(const IplImage *color, IplImage *mask, uchar bmin, uchar bmax, uchar gmin, uchar gmax, uchar rmin, uchar rmax)
{
uchar *dst_ptr = (uchar *)mask->imageData;
for (const uchar *src_ptr = (uchar *)color->imageData, *stop = src_ptr + color->imageSize; src_ptr != stop; src_ptr += color->nChannels)
{
uchar b = src_ptr[0];
uchar g = src_ptr[1];
uchar r = src_ptr[2];
//проверяем диапазон составляющих цвета
if (b <= bmax && b >= bmin &&
g <= gmax && g >= gmin &&
r <= rmax && r >= rmin)
*dst_ptr = 255;
else
*dst_ptr = 0;

++dst_ptr;
}
}
////////////////////////////////////////////////////////////////////////////
int main()
{
//параметры, для идентификации шайбы по цвету
uchar bmin = 0;
uchar bmax = 51;
uchar gmin = 120;
uchar gmax = 225;
uchar rmin = 102;
uchar rmax = 235;

CvMat *measurement = cvCreateMat(2, 1, CV_32FC1);
cvZero(measurement);

CvRNG rng = cvRNG(-1);

CvMat *state = cvCreateMat(4, 1, CV_32FC1); // (x, y, deltax, deltay)
cvRandArr(&rng, state, CV_RAND_NORMAL, cvRealScalar(0), cvRealScalar(0.1));

//стандартный набор функций для фильтра кальмана
CvKalman *kalman = cvCreateKalman(4, 2, 0); //4 переменных состояния, 2 переменных измерения

float deltatime = 50.f; //приращение времени
float transition_matrix[] = { 1, 0, deltatime, 0, 0, 1, 0, deltatime, 0, 0, 1, 0, 0, 0, 0, 1}; //transition matrix
memcpy(kalman->transition_matrix->data.fl, transition_matrix, sizeof(transition_matrix));

cvSetIdentity(kalman->measurement_matrix, cvRealScalar(1));
cvSetIdentity(kalman->process_noise_cov, cvRealScalar(1e-5));
cvSetIdentity(kalman->measurement_noise_cov, cvRealScalar(1e-1));
cvSetIdentity(kalman->error_cov_post, cvRealScalar(1));
//выбираем случайное начальное состояние
cvRandArr(&rng, kalman->state_post, CV_RAND_NORMAL, cvRealScalar(0), cvRealScalar(0.1));

cvNamedWindow("frame", 1);
cvNamedWindow("color_segm", 1);
cvNamedWindow("contours", 1);

CvCapture *video = cvCaptureFromAVI("vid1.avi");
IplImage *mask = NULL;
for (IplImage *frame = cvQueryFrame(video); frame; frame = cvQueryFrame(video))
{
if (!mask)
mask = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 1);
//находим положение шайбы, используя поиск по цвету
region_color_range(frame, mask, bmin, bmax, gmin, gmax, rmin, rmax);

cvShowImage("color_segm", mask);

CvPoint2D32f position = findBigBlob(mask);

cvShowImage("contours", mask);

const CvMat *kalman_predict = cvKalmanPredict(kalman, 0);
float predict_x = kalman_predict->data.fl[0];
float predict_y = kalman_predict->data.fl[1];
if (position.x < 0.0)
{
//уточняем используя предсказание
measurement->data.fl[0] = predict_x;
measurement->data.fl[1] = predict_y;
}
else
{
//уточняем, используя данные измерений
measurement->data.fl[0] = position.x;
measurement->data.fl[1] = position.y;
}

//Предсказанное и измеренное положение центра объекта
cvDrawCircle(frame, cvPoint((int)position.x, (int)position.y), 3, cvScalar(255, 255, 255), -1, 8, 0);
cvDrawCircle(frame, cvPoint((int)predict_x, (int)predict_y), 3, cvScalar(0, 0, 0), -1, 8, 0);
//обновляем состояние фильтра
cvKalmanCorrect(kalman, measurement);

cvWaitKey(100);

cvShowImage("frame", frame);
}

cvReleaseCapture(&video);
if (mask)
cvReleaseImage(&mask);
cvDestroyWindow("frame");
cvDestroyWindow("color_segm");
cvDestroyWindow("contours");

return 0;
}
////////////////////////////////////////////////////////////////////////////[/codebox]

Share this post


Link to post
Share on other sites
Если автор не против, то выложу переделку - делал как-то для себя, поиграть. Немного перегруппировал код, отформатировал по своему вкусу, но всё работает также как и в оригинале:

Спасибо большое за помощь!

Буду теперь пытаться решить поставленную задачу:

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

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

Буду пробовать :)

Share this post


Link to post
Share on other sites

Презентация с хорошим описанием есть здесь: http://www.probabilistic-robotics.org/

(книжка, кстати тоже интересная :) )

Из объяснения понятно, что для корректного использования фильтра нужна динамическая модель системы, которая затем преобразуется в матрицу переходов.Матрица переходов содержит вероятности переходов из состояния A в состояние Б. См. Марковские процессы.

Для фильтрации координат, обычно, в качестве модели используют линеаризованные дифференциальные уравнения движения. В случае линейных перемещений они тривиальны X'=X'+X"*dt; X=X+X'*dt;. В случае добавления вращения лучше перейти к плюккеровым (Plukker) координатам и винтовому исчислению. Вот тут уже посложнее будет :) и матрицы будут 6х6.

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

Share this post


Link to post
Share on other sites

>В случае добавления вращения

Наверно глубины? (третье измерение)

Буквально прям сейчас нашел реализацию, вроде 3D но матрица создается 6х3, оно ли это))?

#ifndef _KALMAN_FILTER_H_

#define _KALMAN_FILTER_H_



#include <vector>



#include <cv.h>

#include "base.h"



#include "Structures/Vector.h"

#include "Structures/Calibration.h"



namespace windage

{

        namespace Algorithms

        {

                /**

                 * @defgroup Algorithms Algorithm classes

                 * @brief

                 *              algorithm classes

                 * @addtogroup Algorithms

                 * @{

                 */



                /**

                 * @defgroup AlgorithmsPoseEstimator Pose Estimator

                 * @brief

                                camera pose estimator in 3D

                 * @addtogroup AlgorithmsPoseEstimator

                 * @{

                 */



                /**

                 * @brief       class for kalman filtering to prevent zitering

                 * @author      Woonhyuk Baek

                 */

                class DLLEXPORT KalmanFilter

                {

                private:

                        /** Tx, Ty, Tz, dTx, dTy, dTz */

                        CvKalman* kalman;

                        CvMat* measurement;



                public:

                        virtual char* GetFunctionName(){return "KalmanFilter";};

                        KalmanFilter()

                        {

                                kalman = cvCreateKalman( 6, 3, 0 );

                                measurement = cvCreateMat( 3, 1, CV_32FC1 );

                                this->Initialize();

                        }

                        ~KalmanFilter()

                        {

                                if(kalman) cvReleaseKalman(&kalman);

                                if(measurement) cvReleaseMat(&measurement);

                        }



                        void Initialize();

                        windage::Vector3 Predict();

                        bool Correct(windage::Vector3 T);

                };

                /** @} */ // addtogroup AlgorithmsPoseEstimator

                /** @} */ // addtogroup Algorithms

        }

}

#endif // _KALMAN_FILTER_H_


#include "Algorithms/KalmanFilter.h"

using namespace windage;

using namespace windage::Algorithms;



void KalmanFilter::Initialize()

{

        const float A[] = { 1, 0, 0, 1, 0, 0,

                                                0, 1, 0, 0, 1, 0,

                                                0, 0, 1, 0, 0, 1,

                                                0, 0, 0, 1, 0, 0,

                                                0, 0, 0, 0, 1, 0,

                                                0, 0, 0, 0, 0, 1,};



        memcpy( this->kalman->transition_matrix->data.fl, A, sizeof(A));

        cvSetIdentity( this->kalman->measurement_matrix, cvRealScalar(1) );

        cvSetIdentity( this->kalman->process_noise_cov, cvRealScalar(1e-5) );

        cvSetIdentity( this->kalman->measurement_noise_cov, cvRealScalar(1e-1) );

        cvSetIdentity( this->kalman->error_cov_post, cvRealScalar(1));

}



windage::Vector3 KalmanFilter::Predict()

{

        windage::Vector3 prediction;



        const CvMat* predictionMat = cvKalmanPredict( this->kalman, 0 );



        prediction.x = (double)predictionMat->data.fl[0];

        prediction.y = (double)predictionMat->data.fl[1];

        prediction.z = (double)predictionMat->data.fl[2];



        return prediction;

}



bool KalmanFilter::Correct(windage::Vector3 T)

{

        measurement->data.fl[0] = (float)T.x;

        measurement->data.fl[1] = (float)T.y;

        measurement->data.fl[2] = (float)T.z;



        cvKalmanCorrect( kalman, measurement );

        return true;

}

  • Like 1

Share this post


Link to post
Share on other sites

Извиняюсь, напутал матрицы с учетом вращения будут матрица А например 12х12 (если не учитывать ускорения). Три линейных координаты это как раз тот тривиальный случай. Если Напишите уравнения по этим матрицам, то и получите для каждой координаты то что я написал выше. Только без учета ускорения:

Вот строка из матрицы А: 1, 0, 0, 1, 0, 0 означает x=1*x+0*y+0*z+1*vx+0*vy+0*vz => x=x+vx*dt здесь (dt = 1), аналогично для y и z. Все скорости равны сами себе vx=vx; vy=vy; vz=vz;

Так же видно что все координаты независимы, что не верно в случае учета поворота.

Share this post


Link to post
Share on other sites

Потестил этот код, неплохо ведет цель.


X  Y  Z


predict -0.466858  0.808474  2.26073

real    -0.309018  0.486225  1.53683


-0.423659  0.684607  2.0921

-0.296634  0.412955  1.49816


-0.358051  0.502584  1.80924

-0.284429  0.322137  1.45931


-0.302884  0.319587  1.56944

-0.24458  0.255752  1.44207


-0.23795  0.192976  1.43535

-0.23719  0.200144  1.42542


-0.211506  0.116637  1.37693

-0.21606  0.155456  1.42932


-0.190204  0.0749303  1.37846

-0.202409  0.0838827  1.41801


-0.178239  0.0161604  1.38489

-0.193323  0.047973  1.42875


-0.173382  -0.0163037  1.40925

-0.185071  -0.00390054  1.43147


-0.170241  -0.0576007  1.42664

-0.18052  -0.0539902  1.43713


-0.169671  -0.103587  1.43971

-0.185037  -0.0819764  1.44412


-0.177794  -0.130038  1.4502

-0.20676  -0.128047  1.44989


-0.205006  -0.169031  1.45739

-0.239146  -0.156521  1.45426


-0.247401  -0.196648  1.46161

-0.260618  -0.190315  1.46437


-0.280221  -0.226259  1.47075

-0.27879  -0.215011  1.47307

Хочу реализовать мультитрекинг, есть у кого ни будь примеры или инфа?

Свой уже написал но довольно косячно работает путает цели которые пересекаются.

Share this post


Link to post
Share on other sites

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

Т.к. скорость обычно мгновенно не меняется, особенно у массивных объектов.

Share this post


Link to post
Share on other sites

Определение ориентации (в кватернионном представлении) на основе показаний акселерометра и магнетометра:

http://code.google.com/p/9dof-orientation-estimation/

Хороший теоретический материал на англ.

http://campar.in.tum.de/Chair/KalmanFilter

Share this post


Link to post
Share on other sites

При задании матрицы перехода используются

школьные формулы (раздел механики, движение материальной точки) :)

                          X  =   1*X + 0*Y + Vx*deltatime + Vy*0, 
Y = 0*X + 1*Y + 0*Vx + Vy*deltatime,
Vx = 0*X + 0*Y + 1*Vx + 0*Vy,
Vy = 0*X + 0*Y + 0*Vx + 1*Vy[/code]

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

В общем если полностью, то так:

Для оси X:

ax=M/Fx; vx=vx+ax*dt; x=x+vx*dt

где M - масса тела, ax - ускорение вдоль x, vx - скорость вдоль x, x - координата, dt - малый интервал времени, Fx - приложенное к точке усилие вдоль оси x.

Share this post


Link to post
Share on other sites

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

Именно то что описанно в примере

cvSetIdentity( this->kalman->measurement_matrix, cvRealScalar(1) );

        cvSetIdentity( this->kalman->process_noise_cov, cvRealScalar(1e-5) );

        cvSetIdentity( this->kalman->measurement_noise_cov, cvRealScalar(1e-1) );

        cvSetIdentity( this->kalman->error_cov_post, cvRealScalar(1));

Читал то что описаннов opencv-книге помогло отчасти, но повторюсь нет общей картины

Share this post


Link to post
Share on other sites

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

Именно то что описанно в примере

cvSetIdentity( this->kalman->measurement_matrix, cvRealScalar(1) );
cvSetIdentity( this->kalman->process_noise_cov, cvRealScalar(1e-5) );
cvSetIdentity( this->kalman->measurement_noise_cov, cvRealScalar(1e-1) );
cvSetIdentity( this->kalman->error_cov_post, cvRealScalar(1));
[/code]

Читал то что описаннов opencv-книге помогло отчасти, но повторюсь нет общей картины

Вот кусок моей незаконченной статьи:

KalmanFilter.pdf

Share this post


Link to post
Share on other sites

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

Именно то что описанно в примере

cvSetIdentity( this->kalman->measurement_matrix, cvRealScalar(1) );

        cvSetIdentity( this->kalman->process_noise_cov, cvRealScalar(1e-5) );

        cvSetIdentity( this->kalman->measurement_noise_cov, cvRealScalar(1e-1) );

        cvSetIdentity( this->kalman->error_cov_post, cvRealScalar(1));

Это матрицы измерения, ковариации шума процесса, ковариации шума измерения, начальная матрица ковариации ошибки соответственно.

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

Share this post


Link to post
Share on other sites

Ну почему обязательно 1 секунда?

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

И не проводить операции над величинами, обозначающими одну и ту же физическую величину, представленными в разных единицах измерения ([м]+[пикселы]) или ([с]+[мс]).

Аналогичная ситуация с координатами (1 м, 1 пиксел,...).

Share this post


Link to post
Share on other sites

Ну почему обязательно 1 секунда?

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

И не проводить операции над величинами, обозначающими одну и ту же физическую величину, представленными в разных единицах измерения ([м]+[пикселы]) или ([с]+[мс]).

Аналогичная ситуация с координатами (1 м, 1 пиксел,...).

Ну тогда и скорость у вас должна измеряться в соответствующих единицах: 1 метр/цикл, 1 пиксел/такт :)

А если для примера взять систему уравнений, в которой вектор состояния это расстояние и скорость, то в дискретном представлении имеем следующие матрицы (если их расчитывать по теории):

вектор состояния:

x=[r v]

матрица перехода:

Fk=[1 dt; 0 1]

матрица ковариации шума процесса:

Qk=[(dt^3)/3 (dt^2)/2; (dt^2)/2 dt]Q

где dt-шаг по времени.

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

А тут уж решайте сами, что это - мкс , цикл или такт :D

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


  • Recently Browsing   0 members

    No registered users viewing this page.

×