PalmDetector.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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.Utility;
  9. using bbiwarg.Recognition.FingerRecognition;
  10. using bbiwarg.Recognition.HandRecognition;
  11. using Emgu.CV;
  12. using Emgu.CV.Structure;
  13. namespace bbiwarg.Recognition.PalmRecognition
  14. {
  15. class PalmDetector
  16. {
  17. private DepthImage depthImage;
  18. private List<Hand> hands;
  19. public List<Palm> Palms;
  20. public PalmDetector(DepthImage depthImage, List<Hand> hands)
  21. {
  22. this.depthImage = depthImage;
  23. this.hands = hands;
  24. findPalms();
  25. }
  26. private void findPalms()
  27. {
  28. Palms = new List<Palm>();
  29. foreach (Hand hand in hands)
  30. {
  31. if (hand.Fingers.Count == 1)
  32. {
  33. List<ConvexityDefect> convexityDefects = findConvexityDefects(hand);
  34. ConvexityDefect thumbDefect = findThumbDefect(hand.Fingers[0], convexityDefects);
  35. if (thumbDefect != null)
  36. {
  37. Palm palm = createPalm(hand, thumbDefect);
  38. Palms.Add(palm);
  39. }
  40. }
  41. }
  42. }
  43. private List<ConvexityDefect> findConvexityDefects(Hand hand)
  44. {
  45. List<ConvexityDefect> convexityDefects;
  46. using (MemStorage ms = new MemStorage())
  47. {
  48. Contour<Point> contour = hand.Mask.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_EXTERNAL);
  49. List<MCvConvexityDefect> mcvConvexityDefects = new List<MCvConvexityDefect>(contour.GetConvexityDefacts(ms, Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE));
  50. convexityDefects = new List<ConvexityDefect>();
  51. foreach (MCvConvexityDefect defect in mcvConvexityDefects)
  52. convexityDefects.Add(new ConvexityDefect(defect));
  53. }
  54. return convexityDefects;
  55. }
  56. private ConvexityDefect findThumbDefect(Finger thumb, List<ConvexityDefect> convexityDefects)
  57. {
  58. convexityDefects.Sort((cd1, cd2) => (cd2.Depth.CompareTo(cd1.Depth)));
  59. foreach (ConvexityDefect defect in convexityDefects)
  60. {
  61. if (defect.isPossibleThumbDefect(thumb))
  62. return defect;
  63. }
  64. return null;
  65. }
  66. private Palm createPalm(Hand hand, ConvexityDefect thumbDefect)
  67. {
  68. HandSide side = determineHandSide(thumbDefect);
  69. Vector2D wristUpper = findWristUpper(hand, thumbDefect);
  70. Vector2D fingersUpper = findFingersUpper(hand, thumbDefect, side);
  71. float palmWidth = findPalmWidth(hand, thumbDefect, side);
  72. float palmLength = wristUpper.getDistanceTo(fingersUpper);
  73. Vector2D directionWristFingers = thumbDefect.VectorLong.normalize();
  74. Vector2D directionUpperLower = thumbDefect.VectorLong.getOrthogonal(side == HandSide.Right).normalize();
  75. Vector2D wristLower = wristUpper.moveWithinBound(directionUpperLower, palmWidth);
  76. Vector2D fingersLower = (wristUpper + 0.75f * palmLength * directionWristFingers + 0.75f * palmWidth * directionUpperLower).moveInBound((directionUpperLower + directionWristFingers).normalize());
  77. return new Palm(hand, thumbDefect, side, wristUpper, fingersUpper, fingersLower, wristLower);
  78. }
  79. private HandSide determineHandSide(ConvexityDefect thumbDefect)
  80. {
  81. if (thumbDefect.VectorShort.crossProduct(thumbDefect.VectorLong) < 0)
  82. return HandSide.Right;
  83. else
  84. return HandSide.Left;
  85. }
  86. private Vector2D findWristUpper(Hand hand, ConvexityDefect thumbDefect)
  87. {
  88. Vector2D wristDirection = thumbDefect.VectorLong.getInverse().normalize();
  89. Vector2D wristUpper = thumbDefect.Inner.moveWithinBound(wristDirection, 5f);
  90. Vector2D wristUpperNext = wristUpper + wristDirection;
  91. while (wristUpperNext.isInBound() && hand.isInside(wristUpperNext))
  92. {
  93. wristUpper = wristUpperNext;
  94. wristUpperNext += wristDirection;
  95. }
  96. return wristUpper;
  97. }
  98. private Vector2D findFingersUpper(Hand hand, ConvexityDefect thumbDefect, HandSide side)
  99. {
  100. Vector2D fingersDirection = thumbDefect.VectorLong.normalize();
  101. Vector2D lowerDirection = fingersDirection.getOrthogonal(side == HandSide.Right).normalize();
  102. Vector2D fingersUpper = thumbDefect.OuterLong;
  103. Vector2D fingersUpperNext = fingersUpper + fingersDirection;
  104. bool handBelow = true;
  105. while (handBelow && fingersUpperNext.isInBound())
  106. {
  107. fingersUpper = fingersUpperNext;
  108. fingersUpperNext += fingersDirection;
  109. Vector2D below = fingersUpper.copy();
  110. handBelow = false;
  111. int distance = 0;
  112. while (!handBelow && distance < Parameters.FingerMaxWidth && below.isInBound())
  113. {
  114. handBelow = hand.isInside(below);
  115. below += lowerDirection;
  116. }
  117. }
  118. return fingersUpper;
  119. }
  120. private float findPalmWidth(Hand hand, ConvexityDefect thumbDefect, HandSide side)
  121. {
  122. Vector2D lowerDirection = thumbDefect.VectorLong.getOrthogonal(side == HandSide.Right).normalize();
  123. Vector2D current = thumbDefect.Inner;
  124. Vector2D step = thumbDefect.VectorLong / Parameters.PalmNumPositionsForPalmWidth;
  125. float maxWidth = float.MinValue;
  126. for (int i = 0; i < Parameters.PalmNumPositionsForPalmWidth; i++)
  127. {
  128. Vector2D lower = current.moveWithinBound(lowerDirection, 10f);
  129. float width = current.getDistanceTo(lower);
  130. while (lower.isInBound() && hand.isInside(lower))
  131. {
  132. lower += lowerDirection;
  133. width += 1;
  134. }
  135. maxWidth = Math.Max(maxWidth, width);
  136. current += step;
  137. }
  138. return maxWidth;
  139. }
  140. }
  141. }