using BBIWARG.Recognition.Tracking;
using BBIWARG.Utility;
using System;
using System.Collections.Generic;
namespace BBIWARG.Recognition.FingerRecognition
{
///
/// Represents a finger that is tracked for several frames.
///
internal class TrackedFinger : TrackedObject
{
///
/// the kalman filter for the hand point prediction
///
private Kalman2DPositionFilter handPointKalman;
///
/// list of last directions (used to correct finger directions if they differ from average)
///
private List lastRawDirections;
///
/// the kalman filter for the tip point prediction
///
private Kalman2DPositionFilter tipPointKalman;
///
/// predicted position of the hand point
///
public Vector2D HandPointPrediction { get { return handPointKalman.getPrediction(); } }
///
/// the average direction of the last fingers
///
public Vector2D MeanDirection { get { return Vector2D.mean(lastRawDirections); } }
///
/// predicted position of the tip point
///
public Vector2D TipPointPrediction { get { return tipPointKalman.getPrediction(); } }
///
/// Initializes a new instance of the TrackedFinger class.
///
/// The track ID.
/// The initial detected finger.
/// The number of consecutive frames detected until the finger is considered to be tracked.
/// The number of consecutive frames lost until the finger is considered to be deleted.
public TrackedFinger(int id, Finger detectedFinger, int numFramesDetectedUntilTracked, int numFramesLostUntilDeleted)
: base(id, detectedFinger, numFramesDetectedUntilTracked, numFramesLostUntilDeleted)
{
tipPointKalman = new Kalman2DPositionFilter(Parameters.FingermXX, Parameters.FingermXY, Parameters.FingermYY);
tipPointKalman.setInitialPosition(detectedFinger.TipPoint);
handPointKalman = new Kalman2DPositionFilter(Parameters.FingermXX, Parameters.FingermXY, Parameters.FingermYY);
handPointKalman.setInitialPosition(detectedFinger.HandPoint);
lastRawDirections = new List();
logStateChange();
}
///
/// Indicates whether a newly detected finger should be reverse (direction differs from average direction of previous fingers).
///
/// the detected finger
/// whether the fingers direction matches to the direction of the previous fingers
public bool shouldFingerBeReversed(Finger detectedFinger)
{
Vector2D meanDirection = Vector2D.mean(lastRawDirections);
return meanDirection.isInOppositeDirection(detectedFinger.Direction);
}
///
/// Updates the tracked finger with the given finger, logs the state change, corrects the finger's direction if needed and updates the position predictions (kalman filters).
///
/// The detected finger.
public override void updateFrame(Finger detectedFinger)
{
base.updateFrame(detectedFinger);
if (NumFramesInCurrentState == 1)
logStateChange();
if (detectedFinger != null)
{
Vector2D rawDirection = detectedFinger.Direction;
if (shouldFingerBeReversed(detectedFinger))
detectedFinger.reverse();
tipPointKalman.getCorrectedPosition(detectedFinger.TipPoint);
handPointKalman.getCorrectedPosition(detectedFinger.HandPoint);
lastRawDirections.Add(rawDirection);
if (lastRawDirections.Count == Parameters.FingerTrackerNumDirectionsForMeanDirection)
lastRawDirections.RemoveAt(0);
}
}
///
/// logs the state change
///
private void logStateChange()
{
String stateAsString = CurrentState.ToString().ToLower();
Logger.log(String.Format("Finger #{0} {1}", this.ID, stateAsString), LogSubject.FingerTracker);
}
}
}