FingerDetector.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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 System.Drawing;
  8. using Emgu.CV;
  9. using Emgu.CV.Structure;
  10. using bbiwarg.Images;
  11. using bbiwarg.Utility;
  12. namespace bbiwarg.Detectors.Fingers
  13. {
  14. class FingerDetector
  15. {
  16. private DepthImage depthImage;
  17. private EdgeImage edgeImage;
  18. private FingerImage fingerImage;
  19. private List<Finger> fingers;
  20. Image<Gray, byte> fingerPoints;
  21. public FingerDetector(DepthImage depthImage, EdgeImage edgeImage, FingerImage fingerImage) {
  22. this.depthImage = depthImage;
  23. this.edgeImage = edgeImage;
  24. this.fingerImage = fingerImage;
  25. findFingerPoints();
  26. findFingers();
  27. }
  28. public List<Finger> getFingers() {
  29. return fingers;
  30. }
  31. private void findFingerPoints() {
  32. int width = depthImage.getWidth();
  33. int height = depthImage.getHeight();
  34. fingerPoints = new Image<Gray, byte>(width, height);
  35. for (int y = 0; y < height; y++) {
  36. for (int x = 0; x < width; x++) {
  37. if (edgeImage.isEdgeAt(x, y))
  38. {
  39. Vector2D startPoint = new Vector2D(x, y);
  40. searchFingerPoint(startPoint, new Vector2D(1, 0), fingerPoints);
  41. searchFingerPoint(startPoint, new Vector2D(0, 1), fingerPoints);
  42. //searchFingerPoint(startPoint, new Vector2D(1, -1), fingerPoints);
  43. //searchFingerPoint(startPoint, new Vector2D(1, 1), fingerPoints);
  44. }
  45. }
  46. }
  47. }
  48. private void searchFingerPoint(Vector2D start, Vector2D direction, Image<Gray, byte> fingerPointsImage) {
  49. int width = fingerPointsImage.Width;
  50. int height = fingerPointsImage.Height;
  51. float minFingerSize = 10;
  52. float maxFingerSize = 30;
  53. float stepSize = direction.getLength();
  54. bool edgeFound = false;
  55. Vector2D edge = start + minFingerSize * direction;
  56. float index = minFingerSize;
  57. float maxXIndex = (direction.x == 0) ? float.MaxValue : ((direction.x > 0) ? ((width - start.x) / direction.x) : (-start.x / direction.x));
  58. float maxYIndex = (direction.y == 0) ? float.MaxValue : ((direction.y > 0) ? ((height - start.y) / direction.y) : (-start.y / direction.y));
  59. float maxIndex = Math.Min(maxFingerSize, Math.Min(maxXIndex, maxYIndex));
  60. while (!edgeFound && index < maxIndex) {
  61. if (edgeImage.isEdgeAt((int)edge.x, (int)edge.y))
  62. edgeFound = true;
  63. else {
  64. index += stepSize;
  65. edge += direction;
  66. }
  67. }
  68. if (edgeFound && fingerDepthTest(start, edge))
  69. {
  70. Vector2D mid = 0.5f * (start + edge);
  71. fingerPointsImage.Data[(int)mid.y, (int)mid.x, 0] = byte.MaxValue;
  72. fingerImage.setFingerAt((int)mid.x, (int)mid.y, FingerImageState.possibleFinger);
  73. }
  74. }
  75. private bool fingerDepthTest(Vector2D p1, Vector2D p2) {
  76. Vector2D mid = 0.5f * (p1 + p2);
  77. Int16 depthP1 = depthImage.getDepthAt((int)p1.x, (int)p1.y);
  78. Int16 depthMid = depthImage.getDepthAt((int)mid.x, (int)mid.y);
  79. Int16 depthP2 = depthImage.getDepthAt((int)p2.x, (int)p2.y);
  80. return (depthP1 > depthMid && depthMid < depthP2);
  81. }
  82. private void findFingers()
  83. {
  84. int width = depthImage.getWidth();
  85. int height = depthImage.getHeight();
  86. fingerPoints = fingerPoints.Dilate(1);
  87. double rhoResolution = 1;
  88. double thetaResolution = Math.PI / 90.0;
  89. int threshold = 10;
  90. double minLineWidth = 20;
  91. double gapBetweenLines = 2;
  92. LineSegment2D[] lines = fingerPoints.HoughLinesBinary(rhoResolution, thetaResolution, threshold, minLineWidth, gapBetweenLines)[0];
  93. fingers = new List<Finger>();
  94. foreach (LineSegment2D line in lines) {
  95. Vector2D p1 = new Vector2D(line.P1.X, line.P1.Y);
  96. Vector2D p2 = new Vector2D(line.P2.X, line.P2.Y);
  97. Finger finger = new Finger(p1, p2);
  98. List<Finger> mergeableFingers = new List<Finger>();
  99. foreach (Finger f in fingers) {
  100. if (finger.isMergeable(f))
  101. mergeableFingers.Add(f);
  102. }
  103. if (mergeableFingers.Count == 0)
  104. fingers.Add(finger);
  105. else if (mergeableFingers.Count == 1)
  106. mergeableFingers[0].mergeFingers(finger);
  107. else {
  108. foreach (Finger mf in mergeableFingers) {
  109. finger.mergeFingers(mf);
  110. fingers.Remove(mf);
  111. }
  112. fingers.Add(finger);
  113. }
  114. }
  115. //draw fingers in fingerImage
  116. foreach(Finger finger in fingers) {
  117. fingerImage.drawLine(finger.getTipPoint(), finger.getHandPoint(), FingerImageState.fingerDetected);
  118. }
  119. }
  120. }
  121. }