using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using Emgu.CV; using Emgu.CV.Structure; using bbiwarg.Images; namespace bbiwarg.Detectors.Fingers { class Finger { private List fingerPoints; private bool lineUpToDate = false; private PointF direction; private PointF pointOnLine; private PointF lineEndPoint1; private PointF lineEndPoint2; private FingerPoint tipPoint; private FingerPoint handPoint; private float length; public Finger(FingerPoint fingerPoint) { fingerPoints = new List(); addFingerPoint(fingerPoint); } public PointF getLineEndPoint1() { if (!lineUpToDate) updateLine(); return lineEndPoint1; } public PointF getLineEndPoint2() { if (!lineUpToDate) updateLine(); return lineEndPoint2; } public FingerPoint getTipPoint() { if (!lineUpToDate) updateLine(); return tipPoint; } public PointF getDirection() { if (!lineUpToDate) updateLine(); return direction; } public float getLength() { if (!lineUpToDate) updateLine(); return length; } public void addFingerPoint(FingerPoint fingerPoint) { fingerPoints.Add(fingerPoint); lineUpToDate = false; } public float getMinDistance(FingerPoint fingerPoint) { float minDinstance = float.MaxValue; foreach (FingerPoint fp in fingerPoints) { float distance = fp.getDistanceTo(fingerPoint); if (distance < minDinstance) { minDinstance = distance; } } return minDinstance; } public float getSimilarity(Finger compareFinger) { //startDistance float maxStartDistance = 100; float xDiffStart = lineEndPoint1.X - compareFinger.getLineEndPoint1().X; float yDiffStart = lineEndPoint1.X - compareFinger.getLineEndPoint1().Y; float startDistance = (float)Math.Sqrt(xDiffStart * xDiffStart + yDiffStart * yDiffStart); float startSimilarity = Math.Max(1 - (startDistance / maxStartDistance), 0); //endDistance float maxEndDistance = 50; float xDiffEnd = lineEndPoint2.X - compareFinger.getLineEndPoint2().X; float yDiffEnd = lineEndPoint2.X - compareFinger.getLineEndPoint2().Y; float endDistance = (float)Math.Sqrt(xDiffEnd * xDiffEnd + yDiffEnd * yDiffEnd); float endSimilarity = Math.Max(1 - (endDistance / maxEndDistance), 0); //direction return (0.2f*startSimilarity + 0.8f*endSimilarity); } private void updateLine() { //update direction+pointonline PointF[] pointArray = new PointF[fingerPoints.Count]; int i = 0; foreach (FingerPoint fp in fingerPoints) { pointArray[i] = new PointF(fp.getX(), fp.getY()); ++i; } PointCollection.Line2DFitting(pointArray, Emgu.CV.CvEnum.DIST_TYPE.CV_DIST_L2, out direction, out pointOnLine); FingerPoint fp1 = fingerPoints[0]; FingerPoint fp2 = fingerPoints[0]; length = 0.0f; foreach (FingerPoint fp in fingerPoints) { float distanceToFP1 = fp.getDistanceTo(fp1); float distanceToFP2 = fp.getDistanceTo(fp2); if (length < distanceToFP1 && distanceToFP1 >= distanceToFP2) { fp2 = fp; length = distanceToFP1; } else if (length < distanceToFP2 && distanceToFP2 > distanceToFP1) { fp1 = fp; length = distanceToFP2; } } if (fp1.getY() < fp2.getY()) { tipPoint = fp1; handPoint = fp2; } else { tipPoint = fp2; handPoint = fp1; } //update start+end lineEndPoint1 = projectToLine(new PointF(tipPoint.getX(), tipPoint.getY())); lineEndPoint2 = projectToLine(new PointF(handPoint.getX(), handPoint.getY())); lineUpToDate = true; } private PointF projectToLine(PointF p) { float px = p.X, py = p.Y, dx = direction.X, dy = direction.Y, ox = pointOnLine.X, oy = pointOnLine.Y; float diffx = px - ox; float diffy = py - oy; float diff_d = (diffx * dx + diffy * dy); float d_d = (dx * dx + dy * dy); float q = diff_d / d_d; return new PointF(ox + q * dx, oy + q * dy); } } }