4

Im implementing a kalman filter that receives real measurements from a camshift head tracking after previously detecting the face with an Haar Cascade. I initialise the state pre and state post variables from the kalman filter with the head position from the Haar Cascade, and call kalman predict and correct while doing the camshift to get some smoothing. The problem is that the predicted and corrected values are always the start values from the haar cascade. Should i update the state pre or state post variables while doing camshift?

private CvKalman Kf ;
public CvMat measurement = new CvMat(2,1, MatrixType.F32C1);
public int frameCounter = 0;
public float[] A = {1,0,1,0, 0,1,0,1, 0,0,1,0, 0,0,0,1};
public float[] H = {1,0,0,0, 0,1,0,0};
public float[] Q = {0.0001f,0,0,0, 0,0.0001f,0,0, 0,0,0.0001f,0, 0,0,0,0.0001f};
public float[] R = {0.2845f,0.0045f,0.0045f,0.0455f};
public float[] P = {100,0,0,0, 0,100,0,0, 0,0,100,0, 0,0,0,100};

initkalman is called once while doing the haar cascade, and tracking window is the initial head position.

void initKalman(CvRect trackinWindow){
    Kf = new CvKalman (4, 2, 0);
    Marshal.Copy (A, 0, Kf.TransitionMatrix.Data, A.Length);
    Marshal.Copy (H, 0, Kf.MeasurementMatrix.Data, H.Length);
    Marshal.Copy (Q, 0, Kf.ProcessNoiseCov.Data, Q.Length);
    Marshal.Copy (R, 0, Kf.MeasurementNoiseCov.Data, R.Length);
    Marshal.Copy (P, 0, Kf.ErrorCovPost.Data, P.Length);
    measurement.mSet (0, 0, trackingWindow.X);
    measurement.mSet (1, 0, trackingWindow.Y);

    Kf.StatePost.mSet(0,0,trackingWindow.X);
    Kf.StatePost.mSet(1,0,trackingWindow.Y);
    Kf.StatePost.mSet(2, 0, 0);
    Kf.StatePost.mSet(3, 0, 0);
}

I call the processKalman function in each camshift iteration, being now tracking window the actual head position

    CvPoint processKalman(CvRect trackingwindow)
{

    CvMat prediction = Cv.KalmanPredict(Kf);

    CvPoint predictionPoint;
    predictionPoint.X = (int)prediction.DataArraySingle [0];
    predictionPoint.Y = (int)prediction.DataArraySingle [1];

    Debug.Log (predictionPoint.X);

    measurement.mSet (0, 0, trackingWindow.X);
    measurement.mSet (1, 0, trackingWindow.Y);

    CvMat estimated = Cv.KalmanCorrect(Kf,measurement);

    CvPoint auxCP;

    auxCP.X = (int)estimated.DataArraySingle [0];
    auxCP.Y = (int)estimated.DataArraySingle [1];
    return auxCP;

}

This is not working and always returning only the initial head position.The guy from this excellent blog is changing the state post with the actual measurement before calling the predict function, but the only thing that changes for me by doing so is that the predicted and corrected values now are identical with the camshift head position for each frame.

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
  • Show us your Kalman Prediction and Correction code. It is likely here where you are going wrong... – MoonKnight Feb 26 '14 at 16:06
  • I use the standard methods from the opencvsharp library. But like I said, I think that something is not right with the state pre and post variables and their initialisation. Could be also an internal problem with the standard methods, since i haven't seen anybody except the guy from the blog i mentioned that uses the opencvsharp wrapper. If it is so I guess I will need to make my own method as you proposed. – Jack Eisenherz Feb 26 '14 at 19:03
  • 1
    Yeah maybe, but in the above I don't see an array of data, just a single point. If you run the filter for one point of course you will get the starting state vector back. The whole idea of the Kalman filter is that it is recursive and in a way 'trains' itself to find the state vector associated with the observation vector in discreet time. If this is from a well known library it is likely to be doing the right thing, you need to have a time-series of observation vectors (could be 1D) y_{n}[nPoints] and run the filter on that. I would go back and read more about the implementation... – MoonKnight Feb 26 '14 at 20:24
  • ok got my mistake!! I'm missing the correction and estimation arrays in which i store the prediction and correction! Thank you very much. I was going crazy with that!!! – Jack Eisenherz Feb 26 '14 at 21:12

1 Answers1

3

I would not write your filter like this. I would use the following contract for all Kalman-type filters.

public interface IKalmanFilter
{
    /// <summary>
    /// The current observation vector being used.
    /// </summary>
    Vector<double> Observation { get; }

    /// <summary>
    /// The best estimate of the current state of the system.
    /// </summary>
    Vector<double> State { get; }

    /// <summary>
    /// The covariance of the current state of the filter. Higher covariances
    /// indicate a lower confidence in the state estimate.
    /// </summary>
    Matrix<double> StateVariance { get; }

    /// <summary>
    /// The one-step-ahead forecast error of y given the previous measurement.
    /// </summary>
    Vector<double> ForecastError { get; }

    /// <summary>
    /// The one-step ahead forecast error variance.
    /// </summary>
    Matrix<double> ForecastErrorVariance { get; }

    /// <summary>
    /// The Kalman Gain matrix.
    /// </summary>
    Matrix<double> KalmanGain { get; }

    /// <summary>
    /// Performs a prediction of the next state of the system.
    /// </summary>
    /// <param name="T">The state transition matrix.</param>
    void Predict(Matrix<double> T);

    /// <summary>
    /// Perform a prediction of the next state of the system.
    /// </summary>
    /// <param name="T">The state transition matrix.</param>
    /// <param name="R">The linear equations to describe the effect of the noise
    /// on the system.</param>
    /// <param name="Q">The covariance of the noise acting on the system.</param>
    void Predict(Matrix<double> T, Matrix<double> R, Matrix<double> Q);

    /// <summary>
    /// Updates the state estimate and covariance of the system based on the
    /// given measurement.
    /// </summary>
    /// <param name="y">The measurements of the system.</param>
    /// <param name="T">The state transition matrix.</param>
    /// <param name="Z">Linear equations to describe relationship between
    /// measurements and state variables.</param>
    /// <param name="H">The covariance matrix of the measurements.</param>
    void Update(Vector<double> y, Matrix<double> T, 
        Matrix<double> Z, Matrix<double> H, Matrix<double> Q);
}

Where Vector<T> and Matrix<T> for my own implementation are those from MathNet.Numerics. The reason I have shown this is that this structure will enable you to run smoothing recursions on the filtered data sets and perform maximum likelihood parameter estimation (should you require it).

Once you have you implementation for the Linear Gaussian Kalman Filter with the template above, you can call it for some data set in a loop for each data point in the time-series (note that the loop is not done within the filter code). For a one-dimensional state/observation vector we could write:

// Set default initial state and variance.
a = Vector<double>.Build.Dense(1, 0.0d);
P = Matrix<double>.Build.Dense(1, 1, Math.Pow(10, 7));

// Run the filter.
List<double> filteredData = new List<double>();
IKalmanFilter filter = new KalmanFilter(a, P);
for (int i = 0; i < Data.Length; i++)
{
    filter.Predict(T, R, Q);
    Vector<double> v = DenseVector.Create(1, k => Convert.ToDouble(Data[i]));
    filter.Update(v, T, Z, H, Q);

    // Now to get the filtered state values, you use. (0 as it is one-dimensional data)
    filteredData.Add(filter.State[0]);
}

I know this is not using your code but I hope it is of some help. If you decide you would like to go down this route, I will help you with the actual Kalman filter code...

MoonKnight
  • 23,214
  • 40
  • 145
  • 277