using bbiwarg.Utility; using System; using System.Collections.Generic; namespace bbiwarg.Recognition.Tracking { /// /// Tracks multiple trackableObjects /// /// The type of the TrackableObjects /// The type of the TrackedObject public abstract class Tracker where T : TrackableObject where TrackedT : TrackedObject { /// /// the trackedObjects /// public List TrackedObjects; /// /// the unique ID generator /// protected TrackIDPool idPool; /// /// the size of the input image (used to calculate position similarities) /// private ImageSize imageSize; /// /// list of similarities between trackableObjects and trackedObjects /// private List> similarities; /// /// Initializes a new instance of the Tracker class. /// /// Size of the input image. public Tracker(ImageSize imageSize) { this.imageSize = imageSize; reset(); } /// /// Calculates the similarity [0-1] between a TrackedObject and a TrackableObject. /// /// the tracked object /// the detected trackable object /// the smiliarity [0-1] public abstract float calculateSimilarity(TrackedT trackedObject, T detectedObject); /// /// Resets the idPool and the trackedObjects. /// public void reset() { idPool = new TrackIDPool(); TrackedObjects = new List(); } /// /// Creates a new TrackedObject with the given TrackableObject as initial object. /// /// the initial trackableObject /// the TrackedObject protected abstract TrackedT createTrackedObject(T detectedObject); /// /// Gets a list of TrackableObjects from all TrackedObjects with the given state. /// /// the desired tracking state /// the list of trackableObjects with the given state protected List getCurrentObjectsWithState(TrackingState state) { List objects = new List(); foreach (TrackedT trackedObject in TrackedObjects) { if (trackedObject.CurrentState == state) objects.Add(trackedObject.CurrentObject); } return objects; } /// /// Calculates a similarity [0-1] between two positions with the given maximum relative distance. /// /// the first position /// the second position /// the maximum distance [0-1] relative to the image size (maxAbsoluteDistance = maxRelativeDistance*imageSize.DiagonalLenght) /// the calculated similarity between the two positions protected float getPositionSimilarity(Vector2D p1, Vector2D p2, float maxRelativeDistance) { float distance = p1.getDistanceTo(p2); float maxDistance = maxRelativeDistance * imageSize.DiagonalLength; float similarity = Math.Max(1 - distance / maxDistance, 0); return similarity; } /// /// adds new TrackedObjects or updates and removes TrackedObjects with the new trackableObjects /// /// the trackableObjects in the current frame protected void trackObjects(List detectedObjects) { if (TrackedObjects.Count == 0) { addNewTrackedObjects(detectedObjects); } else { updateTrackedObjects(detectedObjects); removeDeletableTrackedObjects(); } } /// /// Updates the trackedObjects with the detectedObjects in the current frame. Each TrackedObject is assigned the best fitting detectedObject. Each unassigned detectedObject gets a new instance of a TrackedObject, each unassigned TrackedObject gets updated with null. /// /// the trackableObjects in the current frame protected void updateTrackedObjects(List detectedObjects) { List unassignedTrackedObjects = new List(TrackedObjects); List unassignedDetectedObjects = new List(detectedObjects); createSimilarities(detectedObjects); while (similarities.Count > 0) { Similarity maxSimilarity = similarities[0]; maxSimilarity.TrackedObject.updateFrame(maxSimilarity.DetectedObject); unassignedDetectedObjects.Remove(maxSimilarity.DetectedObject); unassignedTrackedObjects.Remove(maxSimilarity.TrackedObject); removeConcurringSimilarities(maxSimilarity); } addNewTrackedObjects(unassignedDetectedObjects); foreach (TrackedT trackedObject in unassignedTrackedObjects) { trackedObject.updateFrame(null); } } /// /// creates a new TrackedObject for each trackableObject /// /// the unassigned trackableObjects private void addNewTrackedObjects(List detectedObjects) { foreach (T detectedObject in detectedObjects) { TrackedT trackedObject = createTrackedObject(detectedObject); TrackedObjects.Add(trackedObject); } } /// /// Creates the list of similarities by creating a similarity for each TrackedObject with each detected TrackableObject. /// /// the trackableObjects in the current frame private void createSimilarities(List detectedObjects) { similarities = new List>(); foreach (TrackedT trackedObject in TrackedObjects) { foreach (T detectedObject in detectedObjects) { float similarityValue = calculateSimilarity(trackedObject, detectedObject); if (similarityValue > 0) similarities.Add(new Similarity(trackedObject, detectedObject, similarityValue)); } } // sort depending on similarity-value similarities.Sort((s1, s2) => s2.Value.CompareTo(s1.Value)); } /// /// Removes all similarities with the trackedObject or the same trackableObject as the given similarity. /// /// the similarity of two assigned objects private void removeConcurringSimilarities(Similarity similarity) { for (int i = similarities.Count - 1; i >= 0; i--) { Similarity s = similarities[i]; if (s.TrackedObject == similarity.TrackedObject || s.DetectedObject == similarity.DetectedObject) similarities.RemoveAt(i); } } /// /// Removes all TrackedObjects, which current state is "delete". /// private void removeDeletableTrackedObjects() { for (int i = TrackedObjects.Count - 1; i >= 0; i--) { TrackedT trackedObject = TrackedObjects[i]; if (trackedObject.CurrentState == TrackingState.Deleted) { idPool.setIDUnused(trackedObject.ID); TrackedObjects.RemoveAt(i); } } } } }