using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using bbiwarg.Images; using bbiwarg.Recognition.FingerRecognition; using bbiwarg.Graphics; using bbiwarg.Utility; using Emgu.CV; using Emgu.CV.Structure; namespace bbiwarg.Recognition.HandRecognition { class HandDetector { private DepthImage depthImage; private EdgeImage edgeImage; private List fingers; public List Hands { get; private set; } public Image HandMask { get; private set; } public OutputImage outputImage; public HandDetector(DepthImage depthImage, EdgeImage edgeImage, List fingers, OutputImage outputImage) { this.depthImage = depthImage; this.edgeImage = edgeImage; this.fingers = fingers; this.outputImage = outputImage; detectHands(); drawHands(); } private void detectHands() { int width = depthImage.Width; int height = depthImage.Height; int maxArea = width * height; Image image = edgeImage.Image.Copy().Dilate(2).Erode(2).Mul(255); HandMask = image.CopyBlank(); //draw top finger slice foreach (Finger finger in fingers) { // TODO: connect contour with other edges Contour contour = finger.Contour; image.FillConvexPoly(contour.ToArray(), new Gray(0)); image.DrawPolyline(finger.Contour.ToArray(), true, new Gray(255), 1); FingerSlice slice = finger.SliceTrail.EndSlice; Vector2D direction = slice.LineSegment.Line.Direction; Vector2D start = slice.Start+(Constants.FingerContourMargin+Constants.FingerSliceOverlapFactor)*direction; Vector2D end = slice.End-(Constants.FingerContourMargin+Constants.FingerSliceOverlapFactor)*direction; image.Draw(new Emgu.CV.Structure.LineSegment2D(start, end), new Gray(0), 2); //FingerSlice slice = finger.SliceTrail.Slices[1]; //image.Draw(new Emgu.CV.Structure.LineSegment2D(slice.Start, slice.End), new Gray(255), 2); } Hands = new List(); foreach (Finger finger in fingers) { bool newHand = true; foreach (Hand hand in Hands) { if (hand.isInside(finger.HandPoint)) { hand.addFinger(finger); finger.setHand(hand); newHand = false; break; } } if (newHand) { Image mask = new Image(width + 2, height + 2); MCvConnectedComp comp = new MCvConnectedComp(); CvInvoke.cvFloodFill(image, finger.HandPoint, new MCvScalar(255), new MCvScalar(1), new MCvScalar(1), out comp, Emgu.CV.CvEnum.CONNECTIVITY.FOUR_CONNECTED, Emgu.CV.CvEnum.FLOODFILL_FLAG.DEFAULT, mask); if (comp.area < maxArea * Constants.HandMaxSize) { Image cropedMask = mask.Copy(new Rectangle(1, 1, width, height)).Mul(255).Dilate(1); Hand hand = new Hand(cropedMask); Hands.Add(hand); hand.addFinger(finger); finger.setHand(hand); HandMask = HandMask.Or(cropedMask); } } } float minX = float.MaxValue; foreach (Hand hand in Hands) { if (hand.Centroid.X < minX) minX = hand.Centroid.X; } foreach (Hand hand in Hands) { if (hand.Centroid.X == minX) hand.Side = Hand.HandSide.Left; else hand.Side = Hand.HandSide.Right; } if (Hands.Count == 1 && Hands[0].Fingers.Count == 1) { if (Hands[0].Centroid.X < Hands[0].Fingers[0].HandPoint.X) Hands[0].Side = Hand.HandSide.Right; else Hands[0].Side = Hand.HandSide.Left; } } private void drawHands() { if (Hands.Count == 1) { outputImage.Image[0] = outputImage.Image[1] = outputImage.Image[2] = Hands[0].Mask; } else if (Hands.Count > 1) { for (int i = 0; i < 2; ++i) { if (Hands[i].Side == Hand.HandSide.Left) outputImage.Image[0] = outputImage.Image[0] | (Hands[i].Mask); else outputImage.Image[1] = outputImage.Image[1] | (Hands[i].Mask); } } } } }