public PointSkeleton3D(PointSkeleton3D point,int timeStamp) { this.X = point.X; this.Y = point.Y; this.Z = point.Z; this.TimeStamp = timeStamp; }
/// <summary> /// Finger identification with angle between palm-wrist line and every fingertip /// </summary> /// <param name="fingertips"></param> /// <param name="palm"></param> /// <param name="wrist"></param> public void Identify2(List <PointSkeleton3D> fingertips, PointSkeleton3D palm, PointSkeleton3D wrist) { if (null == fingertips) { return; } if (fingertips.Count == 5) { PointSkeleton3D v1 = palm - wrist; float min = float.MaxValue; PointSkeleton3D res = new PointSkeleton3D(); foreach (var i in fingertips) { PointSkeleton3D v2 = i - palm; float angle = PointSkeleton3D.Angle(v1, v2); if (angle < min) { min = angle; res = i; } } Fingers[FingerType.MiddleRight].Position = res; Fingers[FingerType.MiddleRight].TrackingState = FingerTrackingState.Tracked; } else { Fingers[FingerType.MiddleRight].TrackingState = FingerTrackingState.NotTracked; } }
public PointSkeleton3D(PointSkeleton3D point, int timeStamp) { this.X = point.X; this.Y = point.Y; this.Z = point.Z; this.TimeStamp = timeStamp; }
//timeStamp没啥用?? private void FingerTrack(List <PointSkeleton3D> fingertips, int timeStamp) { foreach (var i in Fingers) { if (i.Value.TrackingState == FingerTrackingState.Tracked) { PointSkeleton3D res = new PointSkeleton3D(); float min = float.MaxValue; foreach (var j in fingertips) { float temp = PointSkeleton3D.EuclideanDistance(i.Value.Position, j); if (temp < DIS_THRESHOLD && min > temp) { min = temp; res = j; } } if (min != float.MaxValue) { i.Value.Position.X = res.X; i.Value.Position.Y = res.Y; i.Value.Position.Z = res.Z; i.Value.Position.TimeStamp = res.TimeStamp; } else if ((timeStamp > i.Value.Position.TimeStamp && timeStamp - i.Value.Position.TimeStamp >= FRAME_INTERVAL) || (timeStamp < i.Value.Position.TimeStamp && (timeStamp + KinectUtil.LOOP_TIMES) - i.Value.Position.TimeStamp >= FRAME_INTERVAL)) { i.Value.TrackingState = FingerTrackingState.NotTracked; } } } }
/// <summary> /// Implement the IComparer interface for List<T>.Sort() /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <returns></returns> private int CompareByCoord_X(PointSkeleton3D p1, PointSkeleton3D p2) { if (p1.X == p2.X) { return(0); } return((p1.X < p2.X) ? 1 : -1); }
/// <summary> /// Sort Fingertips list with depth increasing /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <returns></returns> private int CompareByDepth(PointSkeleton3D p1, PointSkeleton3D p2) { if (p1.Z == p2.Z) { return(0); } return((p1.Z > p2.Z) ? 1 : -1); }
public static PointSkeleton3D operator -(PointSkeleton3D point1, PointSkeleton3D point2) { PointSkeleton3D ret = new PointSkeleton3D(); ret.X = point1.X - point2.X; ret.Y = point1.Y - point2.Y; ret.Z = point1.Z - point2.Z; return ret; }
public static PointSkeleton3D operator -(PointSkeleton3D point1, PointSkeleton3D point2) { PointSkeleton3D ret = new PointSkeleton3D(); ret.X = point1.X - point2.X; ret.Y = point1.Y - point2.Y; ret.Z = point1.Z - point2.Z; return(ret); }
/// <summary> /// Map PointSkeleton3D to PointDepth3D /// </summary> /// <param name="pointSkleton3D"></param> /// <param name="depthImageFormat"></param> /// <returns></returns> public PointDepth3D MapSkeletonPointToDepthPoint(PointSkeleton3D pointSkleton3D, DepthImageFormat depthImageFormat) { SkeletonPoint point = new SkeletonPoint(); point.X = pointSkleton3D.X; point.Y = pointSkleton3D.Y; point.Z = pointSkleton3D.Z; return(new PointDepth3D(mapper.MapSkeletonPointToDepthPoint(point, depthImageFormat))); }
/// <summary> /// Map PointSkeleton3D to Point2D /// </summary> /// <param name="pointSkleton3D"></param> /// <param name="colorImageFormat"></param> /// <returns></returns> public Point2D MapSkeletonPointToColorPoint(PointSkeleton3D pointSkleton3D, ColorImageFormat colorImageFormat) { SkeletonPoint point = new SkeletonPoint(); point.X = pointSkleton3D.X; point.Y = pointSkleton3D.Y; point.Z = pointSkleton3D.Z; ColorImagePoint ImgPoint = mapper.MapSkeletonPointToColorPoint(point, colorImageFormat); return(new Point2D(ImgPoint.X, ImgPoint.Y)); }
/// <summary> /// Need to override if you override operator == and != /// </summary> /// <param name="obj"></param> /// <returns></returns> public override bool Equals(object obj) { PointSkeleton3D other = (PointSkeleton3D)obj; if (this.X == other.X && this.Y == other.Y && this.Z == other.Z && this.TimeStamp == other.TimeStamp) { return(true); } return(false); }
/// <summary> /// Finger Identify, sort by x_coordniate first,so many assumptions /// </summary> /// <param name="fingertips"></param> public void Identify(List <PointSkeleton3D> fingertips, int timeStamp) { if (null == fingertips) { return; } if (fingertips.Count == 5) //目前只能处理掌心比较标准的情况 { TrackingState = FingerTrackingState.Tracked; fingertips.Sort(CompareByCoord_X); Fingers[FingerType.MiddleRight].Position = fingertips[2]; Fingers[FingerType.MiddleRight].TrackingState = FingerTrackingState.Tracked; float dis1 = PointSkeleton3D.EuclideanDistance(fingertips[2], fingertips[0]); float dis2 = PointSkeleton3D.EuclideanDistance(fingertips[2], fingertips[4]); Fingers[FingerType.ThumbRight].Position = (dis1 > dis2 ? fingertips[0] : fingertips[4]); Fingers[FingerType.LittleRight].Position = (dis1 > dis2 ? fingertips[4] : fingertips[0]); Fingers[FingerType.ThumbRight].TrackingState = FingerTrackingState.Tracked; Fingers[FingerType.LittleRight].TrackingState = FingerTrackingState.Tracked; } FingerTrack(fingertips, timeStamp); }
/// <summary> /// Depth Frame Ready /// Kinect tracks skeletons, localize the Skeleton Hand Joint Position /// Map Skeleton point given by Kinect to PointDepth3D , Add result to HandTracker's List buffer for computing every frame /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void sensor_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) { using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame()) { if (skeletonFrame != null) { if (skeletonData.Length != skeletonFrame.SkeletonArrayLength) { skeletonData = new Skeleton[skeletonFrame.SkeletonArrayLength]; } skeletonFrame.CopySkeletonDataTo(skeletonData); int personCount = 0; foreach (Skeleton sk in skeletonData) { if (sk.TrackingState == SkeletonTrackingState.Tracked) { //Skeleton point map to depth point given by Kinect CoordinateMapper mapper = new CoordinateMapper(this.sensor); DepthImagePoint left = mapper.MapSkeletonPointToDepthPoint( sk.Joints[JointType.HandLeft].Position, this.sensor.DepthStream.Format); DepthImagePoint right = mapper.MapSkeletonPointToDepthPoint( sk.Joints[JointType.HandRight].Position, this.sensor.DepthStream.Format); rightWrist = new PointSkeleton3D(sk.Joints[JointType.WristRight].Position); rightHand = new PointSkeleton3D(sk.Joints[JointType.HandRight].Position); rightElbow = new PointSkeleton3D(sk.Joints[JointType.ElbowRight].Position); personCount++; } } skeletonReadyFlag = (personCount == 0 ? false : true); } } }
public static float Angle(PointSkeleton3D point1, PointSkeleton3D point2) { return((float)Math.Acos((point1.X * point2.X + point1.Y * point2.Y + point1.Z * point2.Z) / (Length(point1) * Length(point2)))); }
/// <summary> /// Implement the IComparer interface for List<T>.Sort() /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <returns></returns> private int CompareByCoord_X(PointSkeleton3D p1, PointSkeleton3D p2) { if (p1.X == p2.X) return 0; return (p1.X < p2.X) ? 1 : -1; }
/// <summary> /// Finger Identification with two fingertips' max Distance /// </summary> /// <param name="fingertips"></param> public void Identify3(List <PointSkeleton3D> fingertips, int timeStamp) { if (null == fingertips) { return; } if (fingertips.Count == 5) { //1.Find two indexs for ThumbFinger and LittleFinger int thumbIndex = 0, littleIndex = 0; float max = float.MinValue; for (int i = 0; i < fingertips.Count; i++) { for (int j = i + 1; j < fingertips.Count; j++) { float dis = PointSkeleton3D.EuclideanDistance(fingertips[i], fingertips[j]); if (dis > max) { max = dis; thumbIndex = i; littleIndex = j; } } } //2.S and T Set construction, compute min distance between two Sets PointSkeleton3D[] S = new PointSkeleton3D[2]; S[0] = new PointSkeleton3D(fingertips[littleIndex]); S[1] = new PointSkeleton3D(fingertips[thumbIndex]); PointSkeleton3D[] T = new PointSkeleton3D[3]; int k = 0; for (int i = 0; i < fingertips.Count; i++) { if (fingertips[i] != S[0] && fingertips[i] != S[1]) { T[k++] = new PointSkeleton3D(fingertips[i]); } } int[] neighbour = new int[S.Length]; float[] minDis = new float[S.Length]; for (int i = 0; i < S.Length; i++) { float min = float.MaxValue; int temp = 0; for (int j = 0; j < T.Length; j++) { float dis = PointSkeleton3D.EuclideanDistance(S[i], T[j]); if (dis < min) { min = dis; temp = j; } } if (min != float.MaxValue) { neighbour[i] = temp; minDis[i] = min; } } if (minDis[0] == Math.Max(minDis[0], minDis[1])) { //Fingers[FingerType.ThumbRight].Position = S[0]; //Fingers[FingerType.ThumbRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.IndexRight].Position = T[neighbour[0]]; //Fingers[FingerType.IndexRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.LittleRight].Position = S[1]; //Fingers[FingerType.LittleRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.RingRight].Position = T[neighbour[1]]; //Fingers[FingerType.RingRight].TrackingState = FingerTrackingState.Tracked; Tracked(FingerType.ThumbRight, S[0]); Tracked(FingerType.IndexRight, T[neighbour[0]]); Tracked(FingerType.LittleRight, S[1]); Tracked(FingerType.RingRight, T[neighbour[1]]); } else { //Fingers[FingerType.ThumbRight].Position = S[1]; //Fingers[FingerType.ThumbRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.IndexRight].Position = T[neighbour[1]]; //Fingers[FingerType.IndexRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.LittleRight].Position = S[0]; //Fingers[FingerType.LittleRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.RingRight].Position = T[neighbour[0]]; //Fingers[FingerType.RingRight].TrackingState = FingerTrackingState.Tracked; Tracked(FingerType.LittleRight, S[0]); Tracked(FingerType.RingRight, T[neighbour[0]]); Tracked(FingerType.ThumbRight, S[1]); Tracked(FingerType.IndexRight, T[neighbour[1]]); } //3.Middle Finger Remaineds int remain = 0; for (int i = 0; i < T.Length; i++) { if (i != neighbour[0] && i != neighbour[1]) { remain = i; } } //Fingers[FingerType.MiddleRight].Position = T[remain]; //Fingers[FingerType.MiddleRight].TrackingState = FingerTrackingState.Tracked; Tracked(FingerType.MiddleRight, T[remain]); } FingerTrack(fingertips, timeStamp); }
private void Tracked(FingerType id, PointSkeleton3D position) { //if (null != position) Fingers[id].Position = new PointSkeleton3D(position); Fingers[id].TrackingState = FingerTrackingState.Tracked; }
/// <summary> /// Get the Euclidean Distance between two point in Skeleton Space /// </summary> /// <param name="point1"></param> /// <param name="point2"></param> /// <returns></returns> public static float EuclideanDistance(PointSkeleton3D point1, PointSkeleton3D point2) { return((float)Math.Sqrt((point1.X - point2.X) * (point1.X - point2.X) + (point1.Y - point2.Y) * (point1.Y - point2.Y) + (point1.Z - point2.Z) * (point1.Z - point2.Z))); }
/// <summary> /// Get the Euclidean Distance between two point in Skeleton Space /// </summary> /// <param name="point1"></param> /// <param name="point2"></param> /// <returns></returns> public static float EuclideanDistance(PointSkeleton3D point1, PointSkeleton3D point2) { return (float)Math.Sqrt((point1.X - point2.X) * (point1.X - point2.X) + (point1.Y - point2.Y) * (point1.Y - point2.Y) + (point1.Z - point2.Z) * (point1.Z - point2.Z)); }
/// <summary> /// Finger Identification with two fingertips' max Distance /// </summary> /// <param name="fingertips"></param> public void Identify3(List<PointSkeleton3D> fingertips, int timeStamp) { if (null == fingertips) return; if(fingertips.Count == 5) { //1.Find two indexs for ThumbFinger and LittleFinger int thumbIndex = 0, littleIndex = 0 ; float max = float.MinValue; for (int i = 0; i < fingertips.Count; i++) { for (int j = i + 1; j < fingertips.Count; j++) { float dis = PointSkeleton3D.EuclideanDistance(fingertips[i], fingertips[j]); if (dis > max) { max = dis; thumbIndex = i; littleIndex = j; } } } //2.S and T Set construction, compute min distance between two Sets PointSkeleton3D[] S = new PointSkeleton3D[2]; S[0] = new PointSkeleton3D(fingertips[littleIndex]); S[1] = new PointSkeleton3D(fingertips[thumbIndex]); PointSkeleton3D[] T = new PointSkeleton3D[3]; int k = 0; for (int i = 0; i < fingertips.Count; i++) { if (fingertips[i] != S[0] && fingertips[i] != S[1]) T[k++] = new PointSkeleton3D(fingertips[i]); } int[] neighbour = new int[S.Length]; float[] minDis = new float[S.Length]; for (int i = 0; i < S.Length; i++) { float min = float.MaxValue; int temp = 0; for (int j = 0; j < T.Length; j++) { float dis = PointSkeleton3D.EuclideanDistance(S[i], T[j]); if (dis < min) { min = dis; temp = j; } } if (min != float.MaxValue) { neighbour[i] = temp; minDis[i] = min; } } if (minDis[0] == Math.Max(minDis[0], minDis[1])) { //Fingers[FingerType.ThumbRight].Position = S[0]; //Fingers[FingerType.ThumbRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.IndexRight].Position = T[neighbour[0]]; //Fingers[FingerType.IndexRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.LittleRight].Position = S[1]; //Fingers[FingerType.LittleRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.RingRight].Position = T[neighbour[1]]; //Fingers[FingerType.RingRight].TrackingState = FingerTrackingState.Tracked; Tracked(FingerType.ThumbRight, S[0]); Tracked(FingerType.IndexRight, T[neighbour[0]]); Tracked(FingerType.LittleRight, S[1]); Tracked(FingerType.RingRight, T[neighbour[1]]); } else { //Fingers[FingerType.ThumbRight].Position = S[1]; //Fingers[FingerType.ThumbRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.IndexRight].Position = T[neighbour[1]]; //Fingers[FingerType.IndexRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.LittleRight].Position = S[0]; //Fingers[FingerType.LittleRight].TrackingState = FingerTrackingState.Tracked; //Fingers[FingerType.RingRight].Position = T[neighbour[0]]; //Fingers[FingerType.RingRight].TrackingState = FingerTrackingState.Tracked; Tracked(FingerType.LittleRight, S[0]); Tracked(FingerType.RingRight, T[neighbour[0]]); Tracked(FingerType.ThumbRight, S[1]); Tracked(FingerType.IndexRight, T[neighbour[1]]); } //3.Middle Finger Remaineds int remain = 0; for (int i = 0; i < T.Length; i++) { if (i != neighbour[0] && i != neighbour[1]) remain = i; } //Fingers[FingerType.MiddleRight].Position = T[remain]; //Fingers[FingerType.MiddleRight].TrackingState = FingerTrackingState.Tracked; Tracked(FingerType.MiddleRight, T[remain]); } FingerTrack(fingertips, timeStamp); }
public static float Length(PointSkeleton3D point1) { return((float)(Math.Sqrt(point1.X * point1.X + point1.Y * point1.Y + point1.Z * point1.Z))); }
/// <summary> /// Map PointSkeleton3D to Point2D /// </summary> /// <param name="pointSkleton3D"></param> /// <param name="colorImageFormat"></param> /// <returns></returns> public Point2D MapSkeletonPointToColorPoint(PointSkeleton3D pointSkleton3D, ColorImageFormat colorImageFormat) { SkeletonPoint point = new SkeletonPoint(); point.X = pointSkleton3D.X; point.Y = pointSkleton3D.Y; point.Z = pointSkleton3D.Z; ColorImagePoint ImgPoint = mapper.MapSkeletonPointToColorPoint(point, colorImageFormat); return new Point2D(ImgPoint.X, ImgPoint.Y); }
public Finger() { Position = new PointSkeleton3D(); TrackingState = FingerTrackingState.NotTracked; }
/// <summary> /// Sort Fingertips list with depth increasing /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <returns></returns> private int CompareByDepth(PointSkeleton3D p1, PointSkeleton3D p2) { if (p1.Z == p2.Z) return 0; return (p1.Z > p2.Z) ? 1 : -1; }
/// <summary> /// Map PointSkeleton3D to PointDepth3D /// </summary> /// <param name="pointSkleton3D"></param> /// <param name="depthImageFormat"></param> /// <returns></returns> public PointDepth3D MapSkeletonPointToDepthPoint(PointSkeleton3D pointSkleton3D,DepthImageFormat depthImageFormat) { SkeletonPoint point = new SkeletonPoint(); point.X = pointSkleton3D.X; point.Y = pointSkleton3D.Y; point.Z = pointSkleton3D.Z; return new PointDepth3D(mapper.MapSkeletonPointToDepthPoint(point,depthImageFormat)); }
public static float Length(PointSkeleton3D point1) { return (float)(Math.Sqrt(point1.X * point1.X + point1.Y * point1.Y + point1.Z * point1.Z)); }
//timeStamp没啥用?? private void FingerTrack(List<PointSkeleton3D> fingertips,int timeStamp) { foreach (var i in Fingers) { if (i.Value.TrackingState == FingerTrackingState.Tracked) { PointSkeleton3D res = new PointSkeleton3D(); float min = float.MaxValue; foreach (var j in fingertips) { float temp = PointSkeleton3D.EuclideanDistance(i.Value.Position, j); if (temp < DIS_THRESHOLD && min > temp) { min = temp; res = j; } } if (min != float.MaxValue) { i.Value.Position.X = res.X; i.Value.Position.Y = res.Y; i.Value.Position.Z = res.Z; i.Value.Position.TimeStamp = res.TimeStamp; } else if ((timeStamp > i.Value.Position.TimeStamp && timeStamp - i.Value.Position.TimeStamp >= FRAME_INTERVAL) || (timeStamp < i.Value.Position.TimeStamp && (timeStamp + KinectUtil.LOOP_TIMES) - i.Value.Position.TimeStamp >= FRAME_INTERVAL)) { i.Value.TrackingState = FingerTrackingState.NotTracked; } } } }
/// <summary> /// Smooth FingerTips with current computed result and time stamp /// </summary> /// <param name="curr"></param> /// <param name="timeStamp"></param> public void Smooth(List <PointSkeleton3D> curr, int timeStamp) { if (curr == null || curr.Count > 6) { return; } NoiseFilter(curr); if (fingerTips.Count >= curr.Count) { List <PointSkeleton3D> candinateDelete = new List <PointSkeleton3D>(); foreach (var i in fingerTips) { PointSkeleton3D res = new PointSkeleton3D(); float min = float.MaxValue; //Find nearest cooresponding point in two Lists foreach (var j in curr) { float temp = PointSkeleton3D.EuclideanDistance(i, j); if (temp < DIS_THRESHOLD && min > temp) { min = temp; res = new PointSkeleton3D(j); } } //Update result with weighted method if (min != float.MaxValue) { if (min < 0.008f) { i.TimeStamp = timeStamp; } else { i.X = i.X * ALPHA + (1 - ALPHA) * res.X; i.Y = i.Y * ALPHA + (1 - ALPHA) * res.Y; i.Z = i.Z * ALPHA + (1 - ALPHA) * res.Z; i.TimeStamp = timeStamp; } } //the point lost, Check the timestamp difference else if ((timeStamp > i.TimeStamp && timeStamp - i.TimeStamp >= FRAME_INTERVAL) || (timeStamp < i.TimeStamp && (timeStamp + KinectUtil.LOOP_TIMES) - i.TimeStamp >= FRAME_INTERVAL)) { candinateDelete.Add(i); } } foreach (var k in candinateDelete) { fingerTips.Remove(k); } } else { fingerTips.Clear(); foreach (var i in curr) { PointSkeleton3D point = new PointSkeleton3D(i, timeStamp); fingerTips.Add(point); } } }
/// <summary> /// Smooth FingerTips with current computed result and time stamp /// </summary> /// <param name="curr"></param> /// <param name="timeStamp"></param> public void Smooth(List<PointSkeleton3D> curr,int timeStamp) { if (curr == null || curr.Count > 6) { return; } NoiseFilter(curr); if (fingerTips.Count >= curr.Count) { List<PointSkeleton3D> candinateDelete = new List<PointSkeleton3D>(); foreach (var i in fingerTips) { PointSkeleton3D res = new PointSkeleton3D(); float min = float.MaxValue; //Find nearest cooresponding point in two Lists foreach (var j in curr) { float temp = PointSkeleton3D.EuclideanDistance(i, j); if (temp < DIS_THRESHOLD && min > temp) { min = temp; res = new PointSkeleton3D(j); } } //Update result with weighted method if (min != float.MaxValue) { if (min < 0.008f) { i.TimeStamp = timeStamp; } else { i.X = i.X * ALPHA + (1 - ALPHA) * res.X; i.Y = i.Y * ALPHA + (1 - ALPHA) * res.Y; i.Z = i.Z * ALPHA + (1 - ALPHA) * res.Z; i.TimeStamp = timeStamp; } } //the point lost, Check the timestamp difference else if ((timeStamp > i.TimeStamp && timeStamp - i.TimeStamp >= FRAME_INTERVAL) || (timeStamp < i.TimeStamp && (timeStamp + KinectUtil.LOOP_TIMES) - i.TimeStamp >= FRAME_INTERVAL)) { candinateDelete.Add(i); } } foreach (var k in candinateDelete) { fingerTips.Remove(k); } } else { fingerTips.Clear(); foreach (var i in curr) { PointSkeleton3D point = new PointSkeleton3D(i,timeStamp); fingerTips.Add(point); } } }
public static float Angle(PointSkeleton3D point1, PointSkeleton3D point2) { return (float)Math.Acos((point1.X * point2.X + point1.Y * point2.Y + point1.Z * point2.Z) / (Length(point1) * Length(point2))); }
/// <summary> /// Finger identification with angle between palm-wrist line and every fingertip /// </summary> /// <param name="fingertips"></param> /// <param name="palm"></param> /// <param name="wrist"></param> public void Identify2(List<PointSkeleton3D> fingertips, PointSkeleton3D palm, PointSkeleton3D wrist) { if (null == fingertips) return; if (fingertips.Count == 5) { PointSkeleton3D v1 = palm - wrist; float min = float.MaxValue; PointSkeleton3D res = new PointSkeleton3D(); foreach (var i in fingertips) { PointSkeleton3D v2 = i - palm; float angle = PointSkeleton3D.Angle(v1, v2); if (angle < min) { min = angle; res = i; } } Fingers[FingerType.MiddleRight].Position = res; Fingers[FingerType.MiddleRight].TrackingState = FingerTrackingState.Tracked; } else { Fingers[FingerType.MiddleRight].TrackingState = FingerTrackingState.NotTracked; } }