HandDetector.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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 bbiwarg.Images;
  8. using bbiwarg.Recognition.FingerRecognition;
  9. using bbiwarg.Graphics;
  10. using bbiwarg.Utility;
  11. using Emgu.CV;
  12. using Emgu.CV.Structure;
  13. namespace bbiwarg.Recognition.HandRecognition
  14. {
  15. class HandDetector
  16. {
  17. private DepthImage depthImage;
  18. private EdgeImage edgeImage;
  19. private Image<Gray, byte> modifiedHandDepthImage;
  20. private List<Finger> fingers;
  21. private Dictionary<Hand, List<Finger>> otherHandsFingers;
  22. public List<Hand> Hands { get; private set; }
  23. public Image<Gray, byte> HandMask { get; private set; }
  24. public HandDetector(DepthImage depthImage, EdgeImage edgeImage, List<Finger> fingers)
  25. {
  26. this.depthImage = depthImage;
  27. this.edgeImage = edgeImage;
  28. this.fingers = fingers;
  29. createModifiedHandEdgeImage();
  30. findHands();
  31. findOtherHandsFingers();
  32. fixOverlappingFingers();
  33. findThumbDefects();
  34. createHandMask();
  35. }
  36. private void createModifiedHandEdgeImage()
  37. {
  38. modifiedHandDepthImage = depthImage.Image.Copy();
  39. foreach (Finger finger in fingers)
  40. {
  41. Int16 depthAtHand = depthImage.getDepthAt(finger.HandPoint);
  42. Point[] contour = finger.getContour(0f).ToArray();
  43. modifiedHandDepthImage.DrawPolyline(contour, false, new Gray(depthAtHand), 1);
  44. }
  45. }
  46. private void findHands()
  47. {
  48. Hands = new List<Hand>();
  49. foreach (Finger finger in fingers)
  50. {
  51. bool newHand = true;
  52. foreach (Hand hand in Hands)
  53. {
  54. if (hand.isInside(finger.HandPoint))
  55. {
  56. hand.addFinger(finger);
  57. newHand = false;
  58. break;
  59. }
  60. }
  61. if (newHand)
  62. {
  63. Image<Gray, byte> handMask = getHandMask(finger.HandPoint);
  64. int numPixels = handMask.CountNonzero()[0];
  65. if (numPixels < Parameters.HandMaxSize * Parameters.ImageNumPixels && numPixels > Parameters.HandMinSize * Parameters.ImageNumPixels)
  66. {
  67. Hand hand = new Hand(handMask, finger);
  68. Hands.Add(hand);
  69. }
  70. }
  71. }
  72. }
  73. private void findOtherHandsFingers()
  74. {
  75. otherHandsFingers = new Dictionary<Hand, List<Finger>>();
  76. foreach (Hand hand in Hands)
  77. {
  78. List<Finger> otherFingers = new List<Finger>();
  79. foreach (Finger finger in fingers)
  80. {
  81. if (!hand.Fingers.Contains(finger))
  82. otherFingers.Add(finger);
  83. }
  84. otherHandsFingers.Add(hand, otherFingers);
  85. }
  86. }
  87. private Image<Gray, byte> getHandMask(Vector2D p)
  88. {
  89. Image<Gray, byte> mask = new Image<Gray, byte>(Parameters.ImageWidth + 2, Parameters.ImageHeight + 2);
  90. MCvConnectedComp comp = new MCvConnectedComp();
  91. CvInvoke.cvFloodFill(modifiedHandDepthImage, p, new MCvScalar(255), new MCvScalar(Parameters.HandFloodFillDownDiff), new MCvScalar(Parameters.HandFloodFillUpDiff), out comp, Emgu.CV.CvEnum.CONNECTIVITY.FOUR_CONNECTED, Emgu.CV.CvEnum.FLOODFILL_FLAG.DEFAULT, mask);
  92. return mask.Copy(new Rectangle(1, 1, Parameters.ImageWidth, Parameters.ImageHeight));
  93. }
  94. private void fixOverlappingFingers()
  95. {
  96. extendOrMergeThroughOverlappingFingers();
  97. fillOverlappingFingers();
  98. }
  99. private void findThumbDefects()
  100. {
  101. foreach (Hand hand in Hands)
  102. hand.findThumbDefect();
  103. }
  104. private void createHandMask()
  105. {
  106. HandMask = new Image<Gray, byte>(Parameters.ImageWidth, Parameters.ImageHeight);
  107. foreach (Hand hand in Hands)
  108. HandMask = HandMask.Or(hand.Mask);
  109. }
  110. private void extendOrMergeThroughOverlappingFingers()
  111. {
  112. List<Hand> mergedHands = new List<Hand>();
  113. foreach (Hand hand in Hands)
  114. {
  115. if (!mergedHands.Contains(hand))
  116. {
  117. List<Hand> mergeHands = new List<Hand>();
  118. foreach (Finger overlappingFinger in otherHandsFingers[hand])
  119. {
  120. FingerSlice midSlice = overlappingFinger.SliceTrail.MidSlice;
  121. Vector2D midOut1 = midSlice.Start.moveWithinBound(midSlice.Direction.getInverse(), Parameters.FingerOutMargin);
  122. Vector2D midOut2 = midSlice.End.moveWithinBound(midSlice.Direction, Parameters.FingerOutMargin);
  123. Int16 depthAtMidOut1 = depthImage.getDepthAt(midOut1);
  124. Int16 depthAtMidOut2 = depthImage.getDepthAt(midOut2);
  125. bool midOut1InHand = hand.isInside(midOut1);
  126. bool midOut2InHand = hand.isInside(midOut2);
  127. Int16 maxDepth = depthImage.MaxDepth;
  128. if (midOut1InHand != midOut2InHand && depthAtMidOut1 != maxDepth && depthAtMidOut2 != maxDepth && Math.Abs(depthAtMidOut1 - depthAtMidOut2) < Parameters.HandExtendMaxDifference)
  129. {
  130. Vector2D pHand, pHandExtension;
  131. if (midOut1InHand)
  132. {
  133. pHand = midOut1;
  134. pHandExtension = midOut2;
  135. }
  136. else
  137. {
  138. pHand = midOut2;
  139. pHandExtension = midOut1;
  140. }
  141. //check if pHandExtension is in other hand (if so -> merge with hand)
  142. bool merge = false;
  143. foreach (Hand mergeHand in Hands)
  144. {
  145. if (mergeHand.isInside(pHandExtension) && !mergedHands.Contains(mergeHand))
  146. {
  147. mergeHands.Add(mergeHand);
  148. merge = true;
  149. break;
  150. }
  151. }
  152. //if no merge, extend hand
  153. if (!merge)
  154. extendToHand(hand, pHandExtension);
  155. }
  156. }
  157. foreach (Hand mergeHand in mergeHands)
  158. {
  159. mergeToHand(hand, mergeHand);
  160. mergedHands.Add(mergeHand);
  161. }
  162. }
  163. }
  164. foreach (Hand mergedHand in mergedHands)
  165. Hands.Remove(mergedHand);
  166. }
  167. private void mergeToHand(Hand hand, Hand mergeHand)
  168. {
  169. hand.mergeWith(mergeHand);
  170. foreach (Finger finger in mergeHand.Fingers)
  171. otherHandsFingers[hand].Remove(finger);
  172. }
  173. private void extendToHand(Hand hand, Vector2D p)
  174. {
  175. Image<Gray, byte> extendMask = getHandMask(p);
  176. int numPixels = extendMask.CountNonzero()[0];
  177. if (numPixels <= Parameters.HandExtensionMaxSize * Parameters.ImageNumPixels)
  178. hand.extendMask(extendMask);
  179. }
  180. private void fillOverlappingFingers()
  181. {
  182. foreach (Hand hand in Hands)
  183. {
  184. hand.fillOverlappingFingers(otherHandsFingers[hand]);
  185. }
  186. }
  187. }
  188. }