HandDetector.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. finger.setHand(hand);
  58. newHand = false;
  59. break;
  60. }
  61. }
  62. if (newHand)
  63. {
  64. Image<Gray, byte> handMask = getHandMask(finger.HandPoint);
  65. int numPixels = handMask.CountNonzero()[0];
  66. if (numPixels < Parameters.HandMaxSize * Parameters.ImageNumPixels && numPixels > Parameters.HandMinSize * Parameters.ImageNumPixels)
  67. {
  68. Hand hand = new Hand(handMask, finger);
  69. Hands.Add(hand);
  70. finger.setHand(hand);
  71. }
  72. }
  73. }
  74. }
  75. private void findOtherHandsFingers()
  76. {
  77. otherHandsFingers = new Dictionary<Hand, List<Finger>>();
  78. foreach (Hand hand in Hands)
  79. {
  80. List<Finger> otherFingers = new List<Finger>();
  81. foreach (Finger finger in fingers)
  82. {
  83. if (!hand.Fingers.Contains(finger))
  84. otherFingers.Add(finger);
  85. }
  86. otherHandsFingers.Add(hand, otherFingers);
  87. }
  88. }
  89. private Image<Gray, byte> getHandMask(Vector2D p)
  90. {
  91. Image<Gray, byte> mask = new Image<Gray, byte>(Parameters.ImageWidth + 2, Parameters.ImageHeight + 2);
  92. MCvConnectedComp comp = new MCvConnectedComp();
  93. 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);
  94. return mask.Copy(new Rectangle(1, 1, Parameters.ImageWidth, Parameters.ImageHeight));
  95. }
  96. private void fixOverlappingFingers()
  97. {
  98. extendOrMergeThroughOverlappingFingers();
  99. fillOverlappingFingers();
  100. }
  101. private void findThumbDefects()
  102. {
  103. foreach (Hand hand in Hands)
  104. hand.findThumbDefect();
  105. }
  106. private void createHandMask()
  107. {
  108. HandMask = new Image<Gray, byte>(Parameters.ImageWidth, Parameters.ImageHeight);
  109. foreach (Hand hand in Hands)
  110. HandMask = HandMask.Or(hand.Mask);
  111. }
  112. private void extendOrMergeThroughOverlappingFingers()
  113. {
  114. List<Hand> mergedHands = new List<Hand>();
  115. foreach (Hand hand in Hands)
  116. {
  117. if (!mergedHands.Contains(hand))
  118. {
  119. List<Hand> mergeHands = new List<Hand>();
  120. foreach (Finger overlappingFinger in otherHandsFingers[hand])
  121. {
  122. FingerSlice midSlice = overlappingFinger.SliceTrail.MidSlice;
  123. Vector2D midOut1 = midSlice.Start.moveWithinBound(midSlice.Direction.getInverse(), Parameters.FingerOutMargin);
  124. Vector2D midOut2 = midSlice.End.moveWithinBound(midSlice.Direction, Parameters.FingerOutMargin);
  125. Int16 depthAtMidOut1 = depthImage.getDepthAt(midOut1);
  126. Int16 depthAtMidOut2 = depthImage.getDepthAt(midOut2);
  127. bool midOut1InHand = hand.isInside(midOut1);
  128. bool midOut2InHand = hand.isInside(midOut2);
  129. Int16 maxDepth = depthImage.MaxDepth;
  130. if (midOut1InHand != midOut2InHand && depthAtMidOut1 != maxDepth && depthAtMidOut2 != maxDepth && Math.Abs(depthAtMidOut1 - depthAtMidOut2) < Parameters.HandExtendMaxDifference)
  131. {
  132. Vector2D pHand, pHandExtension;
  133. if (midOut1InHand)
  134. {
  135. pHand = midOut1;
  136. pHandExtension = midOut2;
  137. }
  138. else
  139. {
  140. pHand = midOut2;
  141. pHandExtension = midOut1;
  142. }
  143. //check if pHandExtension is in other hand (if so -> merge with hand)
  144. bool merge = false;
  145. foreach (Hand mergeHand in Hands)
  146. {
  147. if (mergeHand.isInside(pHandExtension) && !mergedHands.Contains(mergeHand))
  148. {
  149. mergeHands.Add(mergeHand);
  150. merge = true;
  151. break;
  152. }
  153. }
  154. //if no merge, extend hand
  155. if (!merge)
  156. extendToHand(hand, pHandExtension);
  157. }
  158. }
  159. foreach (Hand mergeHand in mergeHands)
  160. {
  161. mergeToHand(hand, mergeHand);
  162. mergedHands.Add(mergeHand);
  163. }
  164. }
  165. }
  166. foreach (Hand mergedHand in mergedHands)
  167. Hands.Remove(mergedHand);
  168. }
  169. private void mergeToHand(Hand hand, Hand mergeHand)
  170. {
  171. hand.mergeWith(mergeHand);
  172. foreach (Finger finger in mergeHand.Fingers)
  173. otherHandsFingers[hand].Remove(finger);
  174. }
  175. private void extendToHand(Hand hand, Vector2D p)
  176. {
  177. Image<Gray, byte> extendMask = getHandMask(p);
  178. int numPixels = extendMask.CountNonzero()[0];
  179. if (numPixels <= Parameters.HandExtensionMaxSize * Parameters.ImageNumPixels)
  180. hand.extendMask(extendMask);
  181. }
  182. private void fillOverlappingFingers()
  183. {
  184. foreach (Hand hand in Hands)
  185. {
  186. hand.fillOverlappingFingers(otherHandsFingers[hand]);
  187. }
  188. }
  189. }
  190. }