TouchDetector.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using Emgu.CV;
  8. using Emgu.CV.Structure;
  9. using bbiwarg.Images;
  10. using bbiwarg.Recognition.FingerRecognition;
  11. using bbiwarg.Recognition.PalmRecognition;
  12. using bbiwarg.Utility;
  13. using bbiwarg.Output;
  14. using bbiwarg.Input.InputHandling;
  15. namespace bbiwarg.Recognition.TouchRecognition
  16. {
  17. /// <summary>
  18. /// Detects touches by flood filling around a small area around each finger tip and counting the number of affected pixels. If the finger is touching or slightly hovering above something, the flood fill spreads into the touched object and the number of affected pixels is higher.
  19. /// </summary>
  20. class TouchDetector
  21. {
  22. /// <summary>
  23. /// the depth image of the current frame
  24. /// </summary>
  25. private DepthImage depthImage;
  26. /// <summary>
  27. /// the fingers of the current frame
  28. /// </summary>
  29. private List<Finger> fingers;
  30. /// <summary>
  31. /// the palms of the current frame
  32. /// </summary>
  33. private List<Palm> palms;
  34. /// <summary>
  35. /// the detected touches in the current frame
  36. /// </summary>
  37. private List<Touch> touches;
  38. /// <summary>
  39. /// Detects touches in the current frame and stores them in frameData.detectedTouchEvents
  40. /// </summary>
  41. /// <param name="frameData">the current frame</param>
  42. public void detectTouches(FrameData frameData)
  43. {
  44. depthImage = frameData.DepthImage;
  45. fingers = frameData.TrackedFingers;
  46. palms = frameData.TrackedPalms;
  47. touches = new List<Touch>();
  48. if (palms.Count > 0)
  49. {
  50. foreach (Finger finger in fingers)
  51. {
  52. Touch touch = detectTouch(finger);
  53. if (touch != null)
  54. touches.Add(touch);
  55. }
  56. }
  57. frameData.DetectedTouches = touches;
  58. }
  59. /// <summary>
  60. /// Detects if a finger is touching a palm and either returns a new Touch or null
  61. /// </summary>
  62. /// <param name="finger">the fingers</param>
  63. /// <returns>a new Touch or null</returns>
  64. private Touch detectTouch(Finger finger)
  65. {
  66. Vector2D tipPoint = finger.TipPoint;
  67. Vector2D direction = finger.Direction;
  68. Vector2D tipPointInside = tipPoint.moveWithinBound(depthImage.Size, direction.getInverse(), Parameters.TouchTipInsideFactor);
  69. Vector2D tipPointOutside = tipPoint.moveWithinBound(depthImage.Size, direction, Parameters.TouchTipOutsideFactor);
  70. foreach (Palm palm in palms)
  71. {
  72. if (palm.isInside(tipPointOutside))
  73. {
  74. Image<Gray, byte> touchMask = getTouchMask(tipPointInside);
  75. int touchPixels = touchMask.CountNonzero()[0];
  76. int numPixels = touchMask.Width * touchMask.Height;
  77. float touchValue = touchPixels / (float)numPixels;
  78. if (touchValue > Parameters.TouchMinTouchValue)
  79. {
  80. Touch touch = new Touch(tipPointOutside, finger, palm);
  81. return touch;
  82. }
  83. }
  84. }
  85. return null;
  86. }
  87. /// <summary>
  88. /// Gets an image of a small area around the desired touch point (copied from the depth image)
  89. /// </summary>
  90. /// <param name="touchPoint">the touch position</param>
  91. /// <returns>image of the touch area around the touch position</returns>
  92. private Image<Gray, byte> getTouchMask(Vector2D touchPoint)
  93. {
  94. int minX = Math.Max(touchPoint.IntX - 2 * Parameters.TouchAreaSize / 3, 0);
  95. int maxX = Math.Min(touchPoint.IntX + Parameters.TouchAreaSize / 3, depthImage.Size.Width - 1);
  96. int minY = Math.Max(touchPoint.IntY - 2 * Parameters.TouchAreaSize / 3, 0);
  97. int maxY = Math.Min(touchPoint.IntY + Parameters.TouchAreaSize / 3, depthImage.Size.Height - 1);
  98. Vector2D relTouchPoint = new Vector2D(touchPoint.IntX - minX, touchPoint.IntY - minY);
  99. Rectangle rect = new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1);
  100. Image<Gray, byte> touchArea = depthImage.Image.Copy(rect);
  101. Image<Gray, byte> touchMask = new Image<Gray, byte>(rect.Width + 2, rect.Height + 2);
  102. MCvConnectedComp comp = new MCvConnectedComp();
  103. CvInvoke.cvFloodFill(touchArea, relTouchPoint, new MCvScalar(255), new MCvScalar(Parameters.TouchFloodfillDownDiff), new MCvScalar(Parameters.TouchFloodfillUpDiff), out comp, Emgu.CV.CvEnum.CONNECTIVITY.EIGHT_CONNECTED, Emgu.CV.CvEnum.FLOODFILL_FLAG.DEFAULT, touchMask);
  104. Rectangle cropRect = new Rectangle(1, 1, rect.Width, rect.Height);
  105. return touchMask.Copy(cropRect);
  106. }
  107. }
  108. }