using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using bbiwarg.Recognition.Tracking; using bbiwarg.Utility; namespace bbiwarg.Recognition.FingerRecognition { /// /// Represents a finger that is tracked for several frames. /// class TrackedFinger : TrackedObject { /// /// the kalman filter for the tip point prediction /// private Kalman2DPositionFilter tipPointKalman; /// /// 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; /// /// predicted position of the tip point /// public Vector2D TipPointPrediction { get { return tipPointKalman.getPrediction(); } } /// /// 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); } } /// /// 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(); } /// /// 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); } } /// /// Indicates wether a newly detected finger should be reverse (direction differs from average direction of previous fingers). /// /// the detected finger /// wether 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); } /// /// logs the state change /// private void logStateChange() { String stateAsString = CurrentState.ToString().ToLower(); Logger.log(String.Format("Finger #{0} {1}", this.ID, stateAsString), LogSubject.FingerTracker); } } }