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