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.Images; using bbiwarg.Recognition.FingerRecognition; using bbiwarg.Recognition.PalmRecognition; using bbiwarg.Utility; using bbiwarg.Graphics; namespace bbiwarg.Recognition.TouchRecognition { class TouchDetector { private DepthImage depthImage; private OutputImage outputImage; private List fingers; public List TouchEvents { get; private set; } public TouchDetector(List fingers, Quadrangle palmQuad, DepthImage depthImage, OutputImage outputImage) { this.depthImage = depthImage; this.outputImage = outputImage; this.fingers = fingers; this.TouchEvents = new List(); foreach (Finger finger in fingers) { Vector2D tipPoint = finger.TipPoint; Vector2D direction = finger.TipDirection; Vector2D directionInv = direction.getInverse(); Vector2D tipPointInside = (tipPoint + Constants.TouchEventTipInsideFactor * directionInv).moveInBound(Vector2D.Zero, depthImage.BottomRight, direction); Vector2D tipPointOutside = (tipPoint + Constants.TouchEventTipOutsideFactor * direction).moveInBound(Vector2D.Zero, depthImage.BottomRight, directionInv); Image touchMask = getTouchMask(tipPointInside); int touchPixels = touchMask.CountNonzero()[0]; int numPixels = touchMask.Width * touchMask.Height; float touchValue = touchPixels / (float)numPixels; if (touchValue > Constants.TouchEventMinTouchValue) { if (palmQuad != null && palmQuad.isInside(tipPointOutside)) { outputImage.fillCircle(tipPointOutside.IntX, tipPointOutside.IntY, 5, Constants.TouchEventDetectedColor); TouchEvent touchEvent = new PalmTouchEvent(tipPointOutside, touchMask, finger, palmQuad); TouchEvents.Add(touchEvent); finger.setTouchEvent(touchEvent); } } outputImage.fillCircle(tipPoint.IntX, tipPoint.IntY, 3, Constants.TouchEventTipColor); outputImage.drawText(tipPoint.IntX, tipPoint.IntY,String.Format("{0:0.00}", touchValue), Color.Red); } } private Image getTouchMask(Vector2D touchPoint) { int minX = Math.Max(touchPoint.IntX - 2 * Constants.TouchEventAreaSize / 3, 0); int maxX = Math.Min(touchPoint.IntX + Constants.TouchEventAreaSize / 3, depthImage.Width - 1); int minY = Math.Max(touchPoint.IntY - 2 * Constants.TouchEventAreaSize / 3, 0); int maxY = Math.Min(touchPoint.IntY + Constants.TouchEventAreaSize / 3, depthImage.Height - 1); Vector2D relTouchPoint = new Vector2D(touchPoint.IntX - minX, touchPoint.IntY - minY); Rectangle rect = new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1); Image touchArea = depthImage.Image.Copy(rect); Image touchMask = new Image(rect.Width + 2, rect.Height + 2); MCvConnectedComp comp = new MCvConnectedComp(); CvInvoke.cvFloodFill(touchArea, relTouchPoint, new MCvScalar(255), new MCvScalar(Constants.TouchEventFloodfillLowDiff), new MCvScalar(Constants.TouchEventFloodfillHighDiff), out comp, Emgu.CV.CvEnum.CONNECTIVITY.EIGHT_CONNECTED, Emgu.CV.CvEnum.FLOODFILL_FLAG.DEFAULT, touchMask); Rectangle cropRect = new Rectangle(1, 1, rect.Width, rect.Height); return touchMask.Copy(cropRect); } /* private float getTouchValue(Point touchPoint) { int floodValue = 255; int minX = Math.Max(touchPoint.X - 2*Constants.TouchEventAreaSize / 3, 0); int maxX = Math.Min(touchPoint.X + Constants.TouchEventAreaSize / 3, depthImage.Width-1); int minY = Math.Max(touchPoint.Y - 2*Constants.TouchEventAreaSize / 3, 0); int maxY = Math.Min(touchPoint.Y + Constants.TouchEventAreaSize / 3, depthImage.Height-1); Vector2D relTouch = new Vector2D(touchPoint.X - minX, touchPoint.Y - minY); Rectangle rect = new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1); Image touchArea = depthImage.Image.Copy(rect); MCvConnectedComp comp = new MCvConnectedComp(); CvInvoke.cvFloodFill(touchArea, relTouch, new MCvScalar(floodValue), new MCvScalar(Constants.TouchEventFloodfillLowDiff), new MCvScalar(Constants.TouchEventFloodfillHighDiff), out comp, Emgu.CV.CvEnum.CONNECTIVITY.EIGHT_CONNECTED, Emgu.CV.CvEnum.FLOODFILL_FLAG.DEFAULT, IntPtr.Zero); int matchedPixels = 0; int countedPixels = 0; for (int x = minX; x <= maxX; x++) { for (int y = minY; y <= maxY; y++) { Color color = outputImage.getColotAt(x, y); byte depth = touchArea.Data[y - minY, x - minX, 0]; Color subtractColor; if(depth == floodValue) { matchedPixels++; subtractColor = Constants.TouchEventAreaMatchedSubtractColor; } else { subtractColor = Constants.TouchEventAreaNonMatchedSubtractColor; } Color newColor = Color.FromArgb(Math.Max(color.R - subtractColor.R, 0), Math.Max(color.G - subtractColor.G, 0), Math.Max(color.B - subtractColor.B, 0)); outputImage.drawPixel(x, y, newColor); countedPixels++; } } float rel = (float)matchedPixels / (float)countedPixels; outputImage.drawLineSegment(new Utility.LineSegment2D(new Vector2D(minX, maxY), new Vector2D(minX + rel * Constants.TouchEventAreaSize, maxY)), Constants.TouchEventStatusBarColor, 2); return rel; }*/ } }