FingerDetector.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Drawing;
  7. using Emgu.CV;
  8. using Emgu.CV.Structure;
  9. using bbiwarg.Images;
  10. namespace bbiwarg.Detectors.Finger
  11. {
  12. class FingerDetector
  13. {
  14. private DepthImage depthImage;
  15. private EdgeImage edgeImage;
  16. private bool[,] possibleFingerPoints;
  17. private bool[,] fingerPoints;
  18. private List<Finger> possibleFingers;
  19. private List<Finger> fingers;
  20. public FingerDetector(DepthImage depthImage, EdgeImage edgeImage) {
  21. this.depthImage = depthImage;
  22. this.edgeImage = edgeImage;
  23. findPossibleFingerPoints();
  24. findPossibleFingers();
  25. setFingers();
  26. setFingerPoints();
  27. }
  28. public bool isPossibleFingerPointAt(int x, int y) {
  29. return possibleFingerPoints[x, y];
  30. }
  31. public bool isFingerPointAt(int x, int y) {
  32. return fingerPoints[x, y];
  33. }
  34. private void findPossibleFingerPoints()
  35. {
  36. int width = depthImage.getWidth();
  37. int height = depthImage.getHeight();
  38. int maxFingerSize = 30;
  39. int minFingerSize = 10;
  40. possibleFingerPoints = new bool[width, height];
  41. for (int y = 0; y < height; y++) {
  42. for (int x = 0; x < width; x++) {
  43. if (edgeImage.isEdgeAt(x,y)) {
  44. //search horizontal
  45. bool edgeRightFound = false;
  46. int edgeRightX = x + minFingerSize;
  47. while (!edgeRightFound && edgeRightX < width) {
  48. if (edgeImage.isEdgeAt(edgeRightX,y))
  49. edgeRightFound = true;
  50. else
  51. edgeRightX++;
  52. }
  53. if (edgeRightFound){
  54. int midX = (edgeRightX + x) / 2;
  55. Int16 depthLeft = depthImage.getDepthAt(x, y);
  56. Int16 depthMid = depthImage.getDepthAt(midX, y);
  57. Int16 depthRight = depthImage.getDepthAt(edgeRightX, y);
  58. if ((edgeRightX - x) < maxFingerSize && depthLeft > depthMid && depthMid < depthRight) {
  59. possibleFingerPoints[midX, y] = true;
  60. }
  61. }
  62. //search vertical
  63. bool edgeBottomFound = false;
  64. int edgeBottomY = y + minFingerSize;
  65. while (!edgeBottomFound && edgeBottomY < height) {
  66. if (edgeImage.isEdgeAt(x, edgeBottomY))
  67. edgeBottomFound = true;
  68. else
  69. edgeBottomY++;
  70. }
  71. if (edgeBottomFound) {
  72. int midY = (edgeBottomY + y) / 2;
  73. Int16 depthTop = depthImage.getDepthAt(x, y);
  74. Int16 depthMid = depthImage.getDepthAt(x, midY);
  75. Int16 depthBottom = depthImage.getDepthAt(x, edgeBottomY);
  76. if ((edgeBottomY - y) < maxFingerSize && depthTop > depthMid && depthMid < depthBottom) {
  77. possibleFingerPoints[x, midY] = true;
  78. }
  79. }
  80. }
  81. }
  82. }
  83. }
  84. private void findPossibleFingers()
  85. {
  86. int width = depthImage.getWidth();
  87. int height = depthImage.getHeight();
  88. float maxDistanceTogether = 5.0f;
  89. possibleFingers = new List<Finger>();
  90. for (int y = 0; y < height; y++)
  91. {
  92. for (int x = 0; x < width; x++)
  93. {
  94. if (possibleFingerPoints[x, y])
  95. {
  96. Int16 depth = depthImage.getDepthAt(x, y);
  97. FingerPoint fingerPoint = new FingerPoint(x,y,depth);
  98. float minDistanceValue = float.MaxValue;
  99. int minDistanceIndex = 0;
  100. for (int i = 0; i < possibleFingers.Count; i++)
  101. {
  102. float distance = possibleFingers[i].getMinDistance(fingerPoint);
  103. if (distance < minDistanceValue)
  104. {
  105. minDistanceValue = distance;
  106. minDistanceIndex = i;
  107. }
  108. }
  109. if (minDistanceValue < maxDistanceTogether)
  110. {
  111. possibleFingers[minDistanceIndex].addFingerPoint(fingerPoint);
  112. }
  113. else
  114. {
  115. possibleFingers.Add(new Finger(fingerPoint));
  116. }
  117. }
  118. }
  119. }
  120. }
  121. private void setFingers()
  122. {
  123. int width = depthImage.getWidth();
  124. int height = depthImage.getHeight();
  125. float minFingerLength = 20.0f;
  126. fingers = new List<Finger>();
  127. foreach (Finger finger in possibleFingers)
  128. {
  129. float length = finger.getLength();
  130. if (length > minFingerLength)
  131. {
  132. fingers.Add(finger);
  133. }
  134. }
  135. }
  136. private void setFingerPoints() {
  137. int width = depthImage.getWidth();
  138. int height = depthImage.getHeight();
  139. fingerPoints = new bool[width, height];
  140. foreach (Finger finger in fingers) {
  141. PointF start = finger.getStart();
  142. PointF end = finger.getEnd();
  143. drawFingerPointLine(start, end);
  144. }
  145. }
  146. private void drawFingerPointLine(PointF start, PointF end)
  147. {
  148. int width = depthImage.getWidth();
  149. int height = depthImage.getHeight();
  150. // bresenham from wikipedia
  151. int xstart = (int)start.X, xend = (int)end.X, ystart = (int)start.Y, yend = (int)end.Y;
  152. int x, y, t, dx, dy, incx, incy, pdx, pdy, ddx, ddy, es, el, err;
  153. /* Entfernung in beiden Dimensionen berechnen */
  154. dx = xend - xstart;
  155. dy = yend - ystart;
  156. /* Vorzeichen des Inkrements bestimmen */
  157. incx = dx < 0 ? -1 : 1;
  158. incy = dy < 0 ? -1 : 1;
  159. if (dx < 0) dx = -dx;
  160. if (dy < 0) dy = -dy;
  161. /* feststellen, welche Entfernung größer ist */
  162. if (dx > dy)
  163. {
  164. /* x ist schnelle Richtung */
  165. pdx = incx; pdy = 0; /* pd. ist Parallelschritt */
  166. ddx = incx; ddy = incy; /* dd. ist Diagonalschritt */
  167. es = dy; el = dx; /* Fehlerschritte schnell, langsam */
  168. }
  169. else
  170. {
  171. /* y ist schnelle Richtung */
  172. pdx = 0; pdy = incy; /* pd. ist Parallelschritt */
  173. ddx = incx; ddy = incy; /* dd. ist Diagonalschritt */
  174. es = dx; el = dy; /* Fehlerschritte schnell, langsam */
  175. }
  176. /* Initialisierungen vor Schleifenbeginn */
  177. x = xstart;
  178. y = ystart;
  179. err = el / 2;
  180. fingerPoints[Math.Min(width - 1, Math.Max(0, x)), Math.Min(height - 1, Math.Max(0, y))] = true;
  181. /* Pixel berechnen */
  182. for (t = 0; t < el; ++t) /* t zaehlt die Pixel, el ist auch Anzahl */
  183. {
  184. /* Aktualisierung Fehlerterm */
  185. err -= es;
  186. if (err < 0)
  187. {
  188. /* Fehlerterm wieder positiv (>=0) machen */
  189. err += el;
  190. /* Schritt in langsame Richtung, Diagonalschritt */
  191. x += ddx;
  192. y += ddy;
  193. }
  194. else
  195. {
  196. /* Schritt in schnelle Richtung, Parallelschritt */
  197. x += pdx;
  198. y += pdy;
  199. }
  200. fingerPoints[Math.Min(width - 1, Math.Max(0, x)), Math.Min(height - 1, Math.Max(0, y))] = true;
  201. }
  202. }
  203. }
  204. }