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;
}
}
}