Finger.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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 Emgu.CV;
  8. using Emgu.CV.Structure;
  9. using bbiwarg.Images;
  10. using bbiwarg.Utility;
  11. namespace bbiwarg.Detectors.Fingers
  12. {
  13. class Finger
  14. {
  15. private List<Vector<int>> fingerPoints;
  16. private bool lineUpToDate = false;
  17. private Vector<float> direction;
  18. private Vector<float> pointOnLine;
  19. private Vector<float> lineEndPoint1;
  20. private Vector<float> lineEndPoint2;
  21. private Vector<int> tipPoint;
  22. private Vector<int> handPoint;
  23. private float length;
  24. public Finger(Vector<int> fingerPoint)
  25. {
  26. fingerPoints = new List<Vector<int>>();
  27. addFingerPoint(fingerPoint);
  28. }
  29. public Vector<float> getLineEndPoint1()
  30. {
  31. if (!lineUpToDate) updateLine();
  32. return lineEndPoint1;
  33. }
  34. public Vector<float> getLineEndPoint2()
  35. {
  36. if (!lineUpToDate) updateLine();
  37. return lineEndPoint2;
  38. }
  39. public Vector<float> getDirection()
  40. {
  41. if (!lineUpToDate) updateLine();
  42. return direction;
  43. }
  44. public Vector<int> getTipPoint()
  45. {
  46. if (!lineUpToDate) updateLine();
  47. return tipPoint;
  48. }
  49. public float getLength()
  50. {
  51. if (!lineUpToDate) updateLine();
  52. return length;
  53. }
  54. public void addFingerPoint(Vector<int> fingerPoint)
  55. {
  56. fingerPoints.Add(fingerPoint);
  57. lineUpToDate = false;
  58. }
  59. public float getMinDistance(Vector<int> fingerPoint)
  60. {
  61. float minDinstance = float.MaxValue;
  62. foreach (Vector<int> fp in fingerPoints)
  63. {
  64. float distance = fingerPoint.subDistance(fp, 2);
  65. if (distance < minDinstance)
  66. {
  67. minDinstance = distance;
  68. }
  69. }
  70. return minDinstance;
  71. }
  72. public float getSimilarity(Finger compareFinger) {
  73. //startDistance
  74. float maxStartDistance = 100;
  75. float xDiffStart = lineEndPoint1.x - compareFinger.getLineEndPoint1().x;
  76. float yDiffStart = lineEndPoint1.y - compareFinger.getLineEndPoint1().y;
  77. float startDistance = (float)Math.Sqrt(xDiffStart * xDiffStart + yDiffStart * yDiffStart);
  78. float startSimilarity = Math.Max(1 - (startDistance / maxStartDistance), 0);
  79. //endDistance
  80. float maxEndDistance = 100;
  81. float xDiffEnd = lineEndPoint2.x - compareFinger.getLineEndPoint2().x;
  82. float yDiffEnd = lineEndPoint2.y - compareFinger.getLineEndPoint2().y;
  83. float endDistance = (float)Math.Sqrt(xDiffEnd * xDiffEnd + yDiffEnd * yDiffEnd);
  84. float endSimilarity = Math.Max(1 - (endDistance / maxEndDistance), 0);
  85. //direction
  86. float scalaProduct = direction * compareFinger.getDirection();
  87. float lengthDirection = direction.norm();
  88. float lengthCompareDirection = compareFinger.getDirection().norm();
  89. float directionSimilarity = Math.Abs(scalaProduct / (lengthDirection * lengthCompareDirection));
  90. //Console.WriteLine(Math.Round(directionSimilarity, 2) + "###" + Math.Round(startSimilarity, 2) + "###" + Math.Round(endSimilarity, 2));
  91. return (startSimilarity + endSimilarity + directionSimilarity) / 3;
  92. }
  93. private void updateLine() {
  94. //update direction+pointonline
  95. PointF[] pointArray = new PointF[fingerPoints.Count];
  96. int i = 0;
  97. foreach (Vector<int> fp in fingerPoints)
  98. {
  99. pointArray[i] = new PointF(fp.x, fp.y);
  100. ++i;
  101. }
  102. PointF tempDirection;
  103. PointF tempPointOnLine;
  104. PointCollection.Line2DFitting(pointArray, Emgu.CV.CvEnum.DIST_TYPE.CV_DIST_L2, out tempDirection, out tempPointOnLine);
  105. direction = new Vector<float>(new float[2]{tempDirection.X, tempDirection.Y});
  106. pointOnLine = new Vector<float>(new float[2] { tempPointOnLine.X, tempPointOnLine.Y });
  107. Vector<int> fp1 = fingerPoints[0];
  108. Vector<int> fp2 = fingerPoints[0];
  109. length = 0.0f;
  110. foreach (Vector<int> fp in fingerPoints) {
  111. float distanceToFP1 = fp.subDistance(fp1,2);
  112. float distanceToFP2 = fp.subDistance(fp2,2);
  113. if (length < distanceToFP1 && distanceToFP1 >= distanceToFP2)
  114. {
  115. fp2 = fp;
  116. length = distanceToFP1;
  117. }
  118. else if (length < distanceToFP2 && distanceToFP2 > distanceToFP1)
  119. {
  120. fp1 = fp;
  121. length = distanceToFP2;
  122. }
  123. }
  124. if (fp1.y < fp2.y)
  125. {
  126. tipPoint = fp1;
  127. handPoint = fp2;
  128. }
  129. else
  130. {
  131. tipPoint = fp2;
  132. handPoint = fp1;
  133. }
  134. //update start+end
  135. lineEndPoint1 = projectToLine(tipPoint);
  136. lineEndPoint2 = projectToLine(handPoint);
  137. lineUpToDate = true;
  138. }
  139. private Vector<float> projectToLine(Vector<int> p)
  140. {
  141. float px = p.x, py = p.y, dx = direction.x, dy = direction.y, ox = pointOnLine.x, oy = pointOnLine.y;
  142. float diffx = px - ox;
  143. float diffy = py - oy;
  144. float diff_d = (diffx * dx + diffy * dy);
  145. float d_d = (dx * dx + dy * dy);
  146. float q = diff_d / d_d;
  147. float newX = ox + q * dx;
  148. float newY = oy + q * dy;
  149. return new Vector<float>(new float[2]{newX, newY});
  150. }
  151. }
  152. }