using BBIWARG.Recognition.FingerRecognition;
using BBIWARG.Recognition.PalmRecognition;
using BBIWARG.Recognition.Tracking;
using BBIWARG.Utility;
using Emgu.CV;
using Emgu.CV.Structure;
using System.Collections.Generic;
namespace BBIWARG.Recognition.HandRecognition
{
///
/// Represents a Hand.
///
public class Hand : TrackableObject
{
///
/// the center of gravity of the hand
///
public Vector2D Centroid { get; private set; }
///
/// the fingers belonging to the hand
///
public List Fingers { get; private set; }
///
/// a mask of the hand (0=outside, 1=in hand)
///
public Image Mask { get; private set; }
///
/// the palm belonging to the hand
///
public Palm Palm { get; set; }
///
/// Initializes a new instance of the Hand class.
///
/// The mask.
/// The fingers.
public Hand(Image mask, List fingers)
{
Mask = mask;
Fingers = fingers;
foreach (Finger finger in Fingers)
finger.Hand = this;
}
///
/// Extends the mask.
///
/// the mask of the extension
public void extendMask(Image extendMask)
{
Mask = Mask.Or(extendMask);
}
///
/// Fills the Hand mask defects caused by overlapping fingers.
///
/// list of fingers that don't belong to this hand
public void fillOverlappingFingers(List otherFingers)
{
ImageSize imageSize = new ImageSize(Mask.Width, Mask.Height);
foreach (Finger finger in otherFingers)
{
FingerSliceTrail trail = null;
foreach (FingerSlice slice in finger.SliceTrail.Slices)
{
Vector2D direction = slice.Direction;
Vector2D out1 = slice.Start.moveWithinBound(imageSize, direction.getInverse(), Parameters.FingerContourMargin);
Vector2D out2 = slice.End.moveWithinBound(imageSize, direction, Parameters.FingerContourMargin);
if (isInside(out1) && isInside(out2))
{
if (trail == null)
trail = new FingerSliceTrail(slice);
else
trail.addSlice(slice);
}
}
if (trail != null)
Mask.FillConvexPoly(trail.getContour(Parameters.FingerOutMargin).ToArray(), new Gray(1));
}
Mask = Mask.Dilate(1);
}
///
/// Finds the hands centroid (center of gravity).
///
public void findCentroid()
{
MCvPoint2D64f gravityCenter = Mask.GetMoments(true).GravityCenter;
Centroid = new Vector2D((float)gravityCenter.x, (float)gravityCenter.y);
}
///
/// Checks whether a given point is inside the hand.
///
/// the point
/// whether the point is inside the hand
public bool isInside(Vector2D point)
{
return Mask.Data[point.IntY, point.IntX, 0] != 0;
}
///
/// Merges another Hand to this hand by extending the mask and adding the fingers.
///
/// the other hand
public void mergeWith(Hand mergeHand)
{
extendMask(mergeHand.Mask);
Fingers.AddRange(mergeHand.Fingers);
foreach (Finger finger in mergeHand.Fingers)
finger.Hand = this;
}
}
}