using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.Structure;
namespace bbiwarg.Utility
{
///
/// Filter used to smooth a series of 2d positions.
///
class Kalman2DPositionFilter
{
///
/// the emgu kalman filter
///
private Kalman kalman;
///
/// xx entry for the measurement noise covariance matrix
///
private float mXX;
///
/// xy and yx entry for the measurement noise covariance matrix
///
private float mXY;
///
/// yy entry for the measurement noise covariance matrix
///
private float mYY;
///
/// value used for all entries in the process noise covariance matrix
///
private float processNoiseFactor;
///
/// number of measurements per second
///
private float fps;
///
/// true iff the kalman filter is initialized
///
public bool Initialized { get; private set; }
// state: x, y, v_x, v_y
// x: current x position
// y: current y position
// v_x: velocity in x direction
// v_y: velocity in y direction
// a_x: acceleration in x direction
// a_y: acceleration in y direction
///
/// Creates a Kalman2DPositionFilter.
///
/// xx entry for the measurement noise covariance matrix
/// xy and yx entry for the measurement noise covariance matrix
/// yy entry for the measurement noise covariance matrix
/// value used for all entries in the process noise covariance matrix
/// number of measurements per second
public Kalman2DPositionFilter(float mXX, float mXY, float mYY, float processNoiseFactor = 1.0e-4f, int fps = 30)
{
this.mXX = mXX;
this.mXY = mXY;
this.mYY = mYY;
this.processNoiseFactor = processNoiseFactor;
this.fps = fps;
reset();
}
///
/// Resets the kalman filter.
///
public void reset()
{
// 6 state variables and 2 measurements (0 controls)
kalman = new Kalman(2, 2, 0);
// time step (s)
float t = 1 / fps;
// transition matrix
Matrix transitionMatrix = new Matrix(new float[,]
{ {1.0f, 0.0f},
{0.0f, 1.0f}});
kalman.TransitionMatrix = transitionMatrix;
// measurement matrix
Matrix measurementMatrix = new Matrix(new float[,]
{ {1.0f, 0.0f}, // first measurement = x
{0.0f, 1.0f} // second measurement = y
});
kalman.MeasurementMatrix = measurementMatrix;
// measurement noise covariance matrix
Matrix measurementNoiseCovarianceMatrix = new Matrix(2, 2);
measurementNoiseCovarianceMatrix[0, 0] = mXX;
measurementNoiseCovarianceMatrix[0, 1] = measurementNoiseCovarianceMatrix[1, 0] = mXY;
measurementNoiseCovarianceMatrix[1, 1] = mYY;
kalman.MeasurementNoiseCovariance = measurementNoiseCovarianceMatrix;
// process noise covariance matrix
Matrix processNoiseCovarianceMatrix = new Matrix(2, 2);
processNoiseCovarianceMatrix.SetIdentity(new MCvScalar(processNoiseFactor));
kalman.ProcessNoiseCovariance = processNoiseCovarianceMatrix;
// error covariance post matrix (initial value)
Matrix errorCovariancePostMatrix = new Matrix(2, 2);
errorCovariancePostMatrix.SetIdentity(new MCvScalar(processNoiseFactor));
kalman.ErrorCovariancePost = errorCovariancePostMatrix;
Initialized = false;
}
///
/// Sets the initial position.
///
/// initial position
public void setInitialPosition(Vector2D initialPosition)
{
// initial state (x, y, v_x, v_y)
Matrix initialState = new Matrix(new float[] { initialPosition.X, initialPosition.Y});
kalman.CorrectedState = initialState;
Initialized = true;
}
///
/// Computes a prediction for the next position based on the previous positions.
///
/// prediction for the next position
public Vector2D getPrediction()
{
Matrix predicton = kalman.Predict();
return new Vector2D(predicton[0, 0], predicton[1, 0]);
}
///
/// Computes a smoothed position for a measurement and updates the filter.
///
/// the measurement
/// the smoothed position
public Vector2D getCorrectedPosition(Vector2D rawPosition)
{
Matrix rawPositionMatrix = new Matrix(new float[,]
{ {rawPosition.X},
{rawPosition.Y}});
// prediction according to model
kalman.Predict();
// corrected point
Matrix estimate = kalman.Correct(rawPositionMatrix);
return new Vector2D(estimate[0, 0], estimate[1, 0]);
}
}
}