FingerDetector.cs 8.4 KB

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