using BBIWARG.Utility; using Emgu.CV; using System; using System.Collections.Generic; using System.Drawing; namespace BBIWARG.Recognition.FingerRecognition { /// /// Each Finger consists of multiple FingerSlices, a FingerSliceTrail is a collection of these slices. /// public class FingerSliceTrail { /// /// the fitted direction through all slice's mid points [end to start] /// private Vector2D fittedDirection; /// /// indicates whether the variable fittedDirection is up to date (outdates if new slices are added) /// private bool fittedDirectionUpToDate; /// /// the line segment connection the first slice's mid to the last slice's mid /// private LineSegment2D lineSegment; /// /// indicates whether the variable lineSegment is up to date (outdates if new start or end slices are added) /// private bool lineSegmentUpToDate; /// /// the last slice /// public FingerSlice EndSlice { get { return Slices[Slices.Count - 1]; } } /// /// the fitted direction through all slice's mid points [end to start] /// public Vector2D FittedDirection { get { if (!fittedDirectionUpToDate) updateFittedDirection(); return fittedDirection; } } /// /// the line segment connecting the start slice's mid to the end slice's mid /// public LineSegment2D LineSegment { get { if (!lineSegmentUpToDate) updateLineSegment(); return lineSegment; } } /// /// the middle slice /// public FingerSlice MidSlice { get { return Slices[NumSlices / 2]; } } /// /// the number of slices /// public int NumSlices { get { return Slices.Count; } } /// /// the finger slices /// public List Slices { get; private set; } /// /// the first slice /// public FingerSlice StartSlice { get { return Slices[0]; } } /// /// Initializes a new instance of the FingerSliceTrail class. /// /// The initial slice. public FingerSliceTrail(FingerSlice slice) { Slices = new List(); Slices.Capacity = 200; addSlice(slice); lineSegmentUpToDate = false; fittedDirectionUpToDate = false; } /// /// The slice at the given index. /// /// the index /// the slice at the given index public FingerSlice this[int index] { get { return Slices[index]; } } /// /// Adds a slice to the end of the slice trail and outdates the lineSegment and fittedDirection. /// /// the slice that should be added public void addSlice(FingerSlice slice) { try { Slices.Add(slice); lineSegmentUpToDate = false; fittedDirectionUpToDate = false; } catch (OutOfMemoryException e) { // do nothing... } } /// /// Gets the contour of the finger with a given margin /// /// the margin around the finger (in pixels) /// the contour of the finger public Contour getContour(float margin) { List pointsA = new List(); List pointsB = new List(); foreach (FingerSlice slice in Slices) { Vector2D direction = slice.Direction; pointsA.Add(slice.Start + margin * direction.getInverse()); pointsB.Add(slice.End + margin * direction); } pointsA.Reverse(); pointsA.AddRange(pointsB); Contour contour = new Contour(new MemStorage()); contour.PushMulti(pointsA.ToArray(), Emgu.CV.CvEnum.BACK_OR_FRONT.FRONT); return contour; } /// /// Calculates the direction of the last few slices. /// /// the end direction (direction towards hand) public Vector2D getEndDirection() { int innerEndIndex = Math.Max(0, NumSlices - Parameters.FingerNumSlicesForRelativeDirection); return (EndSlice.Mid - Slices[innerEndIndex].Mid).normalize(); } /// /// Calculates the direction of the first few slices /// /// the start direction (pointing direction) public Vector2D getStartDirection() { int innerStartIndex = Math.Min(NumSlices - 1, Parameters.FingerNumSlicesForRelativeDirection); return (StartSlice.Mid - Slices[innerStartIndex].Mid).normalize(); } /// /// Removes the first few slices. /// /// the number of slices that should be removed public void removeFirstSlices(int numSlices) { Slices.RemoveRange(0, numSlices); lineSegmentUpToDate = false; fittedDirectionUpToDate = false; } /// /// Reverses the trail and updates the line segment and the fitted direction /// public void reverse() { Slices.Reverse(); if (lineSegmentUpToDate) lineSegment = new LineSegment2D(lineSegment.P2, lineSegment.P1); if (fittedDirectionUpToDate) fittedDirection = fittedDirection.getInverse(); } /// /// updates the fitted direction (line fitting through all slices mid points) /// private void updateFittedDirection() { List midPoints = new List(); foreach (FingerSlice slice in Slices) midPoints.Add(slice.Mid); PointF pointOnLine, direction; PointCollection.Line2DFitting(midPoints.ToArray(), Emgu.CV.CvEnum.DIST_TYPE.CV_DIST_FAIR, out direction, out pointOnLine); fittedDirection = new Vector2D(direction).normalize(); if (fittedDirection.isInOppositeDirection(LineSegment.Direction)) fittedDirection = fittedDirection.getInverse(); fittedDirectionUpToDate = true; } /// /// updates the line segment (new line segment from end to start) /// private void updateLineSegment() { lineSegment = new LineSegment2D(EndSlice.Mid, StartSlice.Mid); lineSegmentUpToDate = true; } } }