using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using Emgu.CV; using Emgu.CV.Structure; using bbiwarg.Recognition.FingerRecognition; using bbiwarg.Utility; using bbiwarg.Recognition.Tracking; using bbiwarg.Recognition.PalmRecognition; namespace bbiwarg.Recognition.HandRecognition { public enum HandSide { Undefined = 0, Right = 1, Left = 2 } class Hand : TrackableObject { public List ConvexityDefects { get; private set; } public int ZIndex { get; private set; } public Vector2D Centroid { get; private set; } public Vector2D CentroidInHand { get; private set; } public Image Mask { get; private set; } public List Fingers { get; private set; } public ConvexityDefect ThumbDefect { get; private set; } public Palm Palm { get; private set; } public HandSide Side { get; private set; } public Hand(Image mask, Finger finger) { Mask = mask; Fingers = new List(); addFinger(finger); findCentroids(); } public bool isInside(Vector2D point) { return (Mask.Data[point.IntY, point.IntX, 0] != 0); } public void addFinger(Finger finger) { Fingers.Add(finger); } public void setZIndex(int zIndex) { ZIndex = zIndex; } public void mergeWith(Hand mergeHand) { extendMask(mergeHand.Mask); Fingers.AddRange(mergeHand.Fingers); foreach (Finger finger in Fingers) { finger.setHand(this); } findCentroids(); } public void extendMask(Image extendMask) { Mask = Mask.Or(extendMask); findCentroids(); } public void fillOverlappingFingers(List otherFingers) { foreach (Finger finger in otherFingers) { FingerSliceTrail trail = null; foreach (FingerSlice slice in finger.SliceTrail.Slices) { Vector2D out1 = slice.OutStart; Vector2D out2 = slice.OutEnd; if (isInside(out1) && isInside(out2)) { if (trail == null) trail = new FingerSliceTrail(slice); else trail.addSlice(slice); } } if (trail != null) Mask.FillConvexPoly(trail.OuterContour.ToArray(), new Gray(1)); Mask = Mask.Dilate(1); } } public void findThumbDefect() { if (isThumbOnly()) { findConvexityDefects(); filterThumbDefect(); } determineHandSide(); } public void setPalm(Palm palm) { Palm = palm; } private bool isThumbOnly() { return (Fingers.Count == 1); } private void findConvexityDefects() { Contour contour = Mask.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_EXTERNAL); List mcvConvexityDefects = new List(contour.GetConvexityDefacts(new MemStorage(), Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE)); ConvexityDefects = new List(); foreach (MCvConvexityDefect defect in mcvConvexityDefects) ConvexityDefects.Add(new ConvexityDefect(defect)); } private void filterThumbDefect() { if (ConvexityDefects.Count > 0) { ConvexityDefects.Sort((cd1, cd2) => (cd2.Depth.CompareTo(cd1.Depth))); Finger thumb = Fingers[0]; foreach (ConvexityDefect defect in ConvexityDefects) { if (defect.isPossibleThumbDefect(thumb)) { ThumbDefect = defect; break; } } } } private void determineHandSide() { if (ThumbDefect != null) { if (ThumbDefect.VectorShort.crossProduct(ThumbDefect.VectorLong) > 0) Side = HandSide.Left; else Side = HandSide.Right; } else Side = HandSide.Undefined; } private void findCentroids() { //find centroid MCvPoint2D64f gravityCenter = Mask.GetMoments(true).GravityCenter; Centroid = new Vector2D((float)gravityCenter.x, (float)gravityCenter.y); //find centroid in hand if (isInside(Centroid)) CentroidInHand = Centroid; else { Finger finger = Fingers[0]; Vector2D direction = (finger.HandPoint - Centroid).normalize(); CentroidInHand = Centroid; while (!isInside(CentroidInHand)) CentroidInHand += direction; } } } }