FingerDetector.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using bbiwarg.Images;
  8. using bbiwarg.Utility;
  9. using Emgu.CV.Structure;
  10. using Emgu.CV;
  11. namespace bbiwarg.Detectors.Fingers
  12. {
  13. class FingerDetector
  14. {
  15. private DepthImage depthImage;
  16. private EdgeImage edgeImage;
  17. private FingerImage fingerImage;
  18. private List<FingerSliceTrail> horizontalFingerSliceTrails;
  19. private List<FingerSliceTrail> verticalFingerSliceTrails;
  20. private List<Finger> fingers;
  21. public List<Finger> Fingers { get { return fingers; } private set { fingers = value; } }
  22. public FingerDetector(DepthImage depthImage, EdgeImage edgeImage, FingerImage fingerImage)
  23. {
  24. this.depthImage = depthImage;
  25. this.edgeImage = edgeImage;
  26. this.fingerImage = fingerImage;
  27. findHorizontalFingerSliceTrails();
  28. findVerticalFingerSliceTrails();
  29. transformFingerSliceTrailsToFingers();
  30. }
  31. private void findHorizontalFingerSliceTrails()
  32. {
  33. horizontalFingerSliceTrails = new List<FingerSliceTrail>();
  34. int width = depthImage.getWidth();
  35. int height = depthImage.getHeight();
  36. int minFingerSize = 10;
  37. int maxFingerSize = 30;
  38. //search horizontal finger-slices
  39. for (int y = 0; y < height; y++)
  40. {
  41. int x = 0;
  42. while (x <= width - minFingerSize)
  43. {
  44. if (edgeImage.isEdgeAt(x, y) && depthImage.getDepthAt(x, y) > depthImage.getDepthAt(x + 1, y))
  45. {
  46. int sliceX1 = x;
  47. int maxSliceX2 = Math.Min(sliceX1 + maxFingerSize, width - 1);
  48. x++;
  49. while (x <= maxSliceX2)
  50. {
  51. if (edgeImage.isEdgeAt(x, y))
  52. {
  53. int sliceX2 = x;
  54. Vector2D sliceStart = new Vector2D(Math.Max(sliceX1 - 1, 0), y);
  55. Vector2D sliceEnd = new Vector2D(Math.Min(sliceX2 + 1, width - 1), y);
  56. FingerSlice fingerSlice = new FingerSlice(sliceStart, sliceEnd);
  57. if (fingerSlice.Size > minFingerSize && fingerSliceDepthTest(fingerSlice))
  58. {
  59. addHorizontalFingerSlice(fingerSlice);
  60. fingerImage.drawLine(fingerSlice.Line, FingerImageState.possibleFingerSlice);
  61. }
  62. break;
  63. }
  64. else x++;
  65. }
  66. }
  67. else
  68. x++;
  69. }
  70. }
  71. }
  72. private void findVerticalFingerSliceTrails()
  73. {
  74. verticalFingerSliceTrails = new List<FingerSliceTrail>();
  75. int width = depthImage.getWidth();
  76. int height = depthImage.getHeight();
  77. int minFingerSize = 10;
  78. int maxFingerSize = 30;
  79. //search vertical finger-slices
  80. for (int x = 0; x < width; x++)
  81. {
  82. int y = 0;
  83. while (y <= height - minFingerSize)
  84. {
  85. if (edgeImage.isEdgeAt(x, y) && depthImage.getDepthAt(x, y) > depthImage.getDepthAt(x, y + 1))
  86. {
  87. int sliceY1 = y;
  88. int maxSliceY2 = Math.Min(sliceY1 + maxFingerSize, height - 1);
  89. y++;
  90. while (y <= maxSliceY2)
  91. {
  92. if (edgeImage.isEdgeAt(x, y))
  93. {
  94. int sliceY2 = y;
  95. Vector2D sliceStart = new Vector2D(x, Math.Max(sliceY1 - 1, 0));
  96. Vector2D sliceEnd = new Vector2D(x, Math.Min(sliceY2 + 1, height - 1));
  97. FingerSlice fingerSlice = new FingerSlice(sliceStart, sliceEnd);
  98. if (fingerSlice.Size > minFingerSize && fingerSliceDepthTest(fingerSlice))
  99. {
  100. addVerticalFingerSlice(fingerSlice);
  101. fingerImage.drawLine(fingerSlice.Line, FingerImageState.possibleFingerSlice);
  102. }
  103. break;
  104. }
  105. else y++;
  106. }
  107. }
  108. else
  109. y++;
  110. }
  111. }
  112. }
  113. private void transformFingerSliceTrailsToFingers()
  114. {
  115. int minNumSlices = 15;
  116. Fingers = new List<Finger>();
  117. List<FingerSliceTrail> fingerSliceTrails = new List<FingerSliceTrail>();
  118. fingerSliceTrails.AddRange(horizontalFingerSliceTrails);
  119. fingerSliceTrails.AddRange(verticalFingerSliceTrails);
  120. foreach (FingerSliceTrail trail in fingerSliceTrails)
  121. {
  122. if (trail.NumSlices >= minNumSlices)
  123. {
  124. //reorder finger slice so that it goes tip->hand
  125. /*Int16 depthAtTip = depthImage.getDepthAt((int)trail.Start.Mid.X, (int)trail.Start.Mid.Y);
  126. Int16 depthAtHand = depthImage.getDepthAt((int)trail.End.Mid.X, (int)trail.End.Mid.Y);
  127. if (depthAtTip < depthAtHand)
  128. trail.reverse();*/
  129. Finger finger = new Finger(trail);
  130. //filter double hits (horizontal+vertical finger)
  131. bool addFinger = true;
  132. for (int i = fingers.Count - 1; i >= 0; i--)
  133. {
  134. Finger f = fingers[i];
  135. Utility.LineSegment2D lineA = finger.LineSegment;
  136. Utility.LineSegment2D lineB = f.LineSegment;
  137. if(lineA.getVerticalDistanceTo(lineB) < 5 && lineA.getParallelDistanceTo(lineB) < 5)
  138. {
  139. if (finger.SliceTrail.NumSlices > f.SliceTrail.NumSlices)
  140. fingers.RemoveAt(i);
  141. else
  142. addFinger = false;
  143. }
  144. }
  145. if (addFinger)
  146. {
  147. fingers.Add(finger);
  148. fingerImage.drawFinger(finger, FingerImageState.fingerDetected);
  149. }
  150. }
  151. }
  152. }
  153. private bool fingerSliceDepthTest(FingerSlice fingerSlice)
  154. {
  155. Int16 depthStart = depthImage.getDepthAt(fingerSlice.Start.IntX, fingerSlice.Start.IntY);
  156. Int16 depthMid = depthImage.getDepthAt(fingerSlice.Mid.IntX, fingerSlice.Mid.IntY);
  157. Int16 depthEnd = depthImage.getDepthAt(fingerSlice.End.IntX, fingerSlice.End.IntY);
  158. return (depthStart > depthMid && depthMid < depthEnd);
  159. }
  160. private void addHorizontalFingerSlice(FingerSlice slice)
  161. {
  162. int maxYGap = 5;
  163. int maxXDifference = 5;
  164. bool assigned = false;
  165. foreach (FingerSliceTrail trail in horizontalFingerSliceTrails)
  166. {
  167. FingerSlice trailEnd = trail.End;
  168. if (slice.Mid.Y - trailEnd.Mid.Y <= maxYGap && Math.Abs(trailEnd.Mid.X - slice.Mid.X) <= maxXDifference)
  169. {
  170. trail.addSlice(slice);
  171. assigned = true;
  172. }
  173. }
  174. if (!assigned)
  175. horizontalFingerSliceTrails.Add(new FingerSliceTrail(slice));
  176. }
  177. private void addVerticalFingerSlice(FingerSlice slice)
  178. {
  179. int maxXGap = 5;
  180. int maxYDifference = 5;
  181. bool assigned = false;
  182. foreach (FingerSliceTrail trail in verticalFingerSliceTrails)
  183. {
  184. FingerSlice trailEnd = trail.End;
  185. if (slice.Mid.X - trailEnd.Mid.X <= maxXGap && Math.Abs(trailEnd.Mid.Y - slice.Mid.Y) <= maxYDifference)
  186. {
  187. trail.addSlice(slice);
  188. assigned = true;
  189. }
  190. }
  191. if (!assigned)
  192. verticalFingerSliceTrails.Add(new FingerSliceTrail(slice));
  193. }
  194. }
  195. }