void newFrameHandler(object sender, FrameEventArgs eventArgs) { Frame frame = eventArgs.frame; fpsDisplay.Content = frame.CurrentFramesPerSecond.ToString(); if (frame.Hands.Count > 0) { Hand hand = frame.Hands[0]; string handType = hand.IsLeft ? "Left" : "Right"; // fingers Finger thumb = hand.Fingers[0]; Finger pointer = hand.Fingers[1]; Finger middle = hand.Fingers[2]; Finger ring = hand.Fingers[3]; Finger pinky = hand.Fingers[4]; handTypeDisplay.Content = hand.IsLeft ? "left" : "right"; Arm arm = hand.Arm; Leap.Vector armDirection = arm.Direction; Leap.Vector handDirection = hand.Direction; double angleRadians = armDirection.AngleTo(handDirection); double angleDegrees = Math.Round(angleRadians * 180 / Math.PI); currentAngle = angleDegrees; calculateAverageAngle(); this.angleDisplay.Content = currentAverageAngle.ToString(); if (recording == true) { DateTime currentTime = DateTime.Now; int elapsedTime = Convert.ToInt32(((TimeSpan)(currentTime - startRecording)).TotalMilliseconds); timeDisplay.Content = elapsedTime.ToString(); string line = "timestamp: " + elapsedTime.ToString() + " | hand: " + handType + " | angle: " + currentAverageAngle.ToString(); if (firstFrame == true) { using (StreamWriter recordFile = new StreamWriter(@"C:\Users\casch\Documents\Work\Uni\Studienarbeit\Implementierung\C#\wfe.txt")) { recordFile.WriteLine(line); }; firstFrame = false; } else { using (StreamWriter recordFile = new StreamWriter(@"C:\Users\casch\Documents\Work\Uni\Studienarbeit\Implementierung\C#\wfe.txt", true)) { recordFile.WriteLine(line); }; } } } controller.RequestImages(frame.Id, Leap.Image.ImageType.DEFAULT, imagedata); }
public override void OnFrame(Controller controller) { using (var frame = controller.Frame()) { Vector A = new Vector(2, 0, 0); Vector B = new Vector(4, 2, 0); double rads = Math.Round(A.AngleTo(B), 2); Console.WriteLine("Radians " + rads); Console.WriteLine("Degrees " + Math.Round(rads*180/Math.PI, 2)); //Console.WriteLine("Thumb: " + Math.Round(frame.Fingers[0].Length / 10, 2) + "cm"); //Console.WriteLine("Index: " + Math.Round(frame.Fingers[1].Length / 10, 2) + "cm"); //Console.WriteLine("Middle: " + Math.Round(frame.Fingers[2].Length / 10, 2) + "cm"); //Console.WriteLine("Ring: " + Math.Round(frame.Fingers[3].Length / 10, 2) + "cm"); //Console.WriteLine("Pinky: " + Math.Round(frame.Fingers[4].Length / 10, 2) + "cm\n"); } Console.ReadLine(); //Thread.Sleep(2000); //using (var frame = controller.Frame()) //{ // _now = frame.Timestamp; // _timeDifference = _now - _previous; // if (frame.Hands.IsEmpty || _timeDifference < 5000) // { // return; // } // _previous = frame.Timestamp; // if (frame.Gestures().Count > 0 && OnGesturesMade != null) // { // OnGesturesMade(frame.Gestures()); // } // if (frame.Fingers.Count > 0 && OnFingersRegistered != null) // { // OnFingersRegistered(frame.Fingers); // } //} }
bool VerDirToYAxis(Vector dir, float threshold) { bool isVer = false; float radian = dir.AngleTo(Vector.YAxis); if(radian>threshold && radian<(Mathf.PI - threshold)) { isVer = true; } return isVer; }
// Update is called once per frame void Update() { mFrame = leapController.Frame(); int fingerCount = 0; if (numbersGestureRegistered || closeFistRegistered || openFistRegistered || keytapGestureRegistered || twoFingerKeytapRegistered || threeFingerKeytapRegistered || screentapGestureRegistered || twoFingerScreentapRegistered || threeFingerScreentapRegistered || steeringWheelRegistered) { fingerCount = GetFingerCount(); } foreach (Leap.Gesture gesture in mFrame.Gestures()) { switch (gesture.Type) { case Leap.Gesture.GestureType.TYPECIRCLE: if (circleGestureRegistered) { BuiltInGestureRecognised(gesture, EasyLeapGestureType.TYPECIRCLE); onCircleGestureRecognized(); } break; case Leap.Gesture.GestureType.TYPESWIPE: if (swipeGestureRegistered) { BuiltInGestureRecognised(gesture, EasyLeapGestureType.TYPESWIPE); } break; case Leap.Gesture.GestureType.TYPEKEYTAP: if (keytapGestureRegistered && fingerCount == 1) { BuiltInGestureRecognised(gesture, EasyLeapGestureType.TYPEKEYTAP); } if (twoFingerKeytapRegistered && fingerCount == 2) { BuiltInImprovedGestureRecognised(gesture, EasyLeapGestureType.TWO_FINGERS_KEYTAP); } if (threeFingerKeytapRegistered && fingerCount == 3) { BuiltInImprovedGestureRecognised(gesture, EasyLeapGestureType.THREE_FINGERS_KEYTAP); } break; case Leap.Gesture.GestureType.TYPESCREENTAP: if (screentapGestureRegistered && fingerCount == 1) { BuiltInGestureRecognised(gesture, EasyLeapGestureType.TYPESCREENTAP); } if (twoFingerScreentapRegistered && fingerCount == 2) { BuiltInImprovedGestureRecognised(gesture, EasyLeapGestureType.TWO_FINGERS_SCREENTAP); } if (threeFingerScreentapRegistered && fingerCount == 3) { BuiltInImprovedGestureRecognised(gesture, EasyLeapGestureType.THREE_FINGERS_SCREENTAP); } break; } } if (mFrame.Gestures().Count == 0) { ClearDraggingGestures(); } if (numbersGestureRegistered || closeFistRegistered || openFistRegistered) { switch (fingerCount) { case 0: // NO FINGERS if (numbersGestureRegistered) { NumbersGestureRecognised(EasyLeapGestureType.DEFAULT); } if (closeFistRegistered) { if (mFrame.Hands.Count == 1) { if (PalmIsHorizontal(mFrame.Hands[0])) { CloseFistGestureRecognised(EasyLeapGestureState.STATESTOP); } } else { CloseFistGestureRecognised(EasyLeapGestureState.STATEINVALID); } } if (openFistRegistered) { if (mFrame.Hands.Count == 1) { if (PalmIsHorizontal(mFrame.Hands[0])) { OpenFistGestureRecognised(EasyLeapGestureState.STATESTART); } } else { OpenFistGestureRecognised(EasyLeapGestureState.STATEINVALID); } } break; case 1: if (numbersGestureRegistered) { NumbersGestureRecognised(EasyLeapGestureType.ONE); } break; case 2: if (numbersGestureRegistered) { NumbersGestureRecognised(EasyLeapGestureType.TWO); } break; case 3: if (numbersGestureRegistered) { NumbersGestureRecognised(EasyLeapGestureType.THREE); } break; case 4: if (numbersGestureRegistered) { NumbersGestureRecognised(EasyLeapGestureType.FOUR); } break; case 5: if (numbersGestureRegistered) { NumbersGestureRecognised(EasyLeapGestureType.FIVE); } if (closeFistRegistered && mFrame.Hands.Count == 1) { CloseFistGestureRecognised(EasyLeapGestureState.STATESTART); } if (openFistRegistered) { OpenFistGestureRecognised(EasyLeapGestureState.STATESTOP); } break; case 6: if (numbersGestureRegistered) { NumbersGestureRecognised(EasyLeapGestureType.SIX); } break; case 7: if (numbersGestureRegistered) { NumbersGestureRecognised(EasyLeapGestureType.SEVEN); } break; case 8: if (numbersGestureRegistered) { NumbersGestureRecognised(EasyLeapGestureType.EIGHT); } break; case 9: if (numbersGestureRegistered) { NumbersGestureRecognised(EasyLeapGestureType.NINE); } break; case 10: if (numbersGestureRegistered) { NumbersGestureRecognised(EasyLeapGestureType.TEN); } break; } } if (pushGestureRegistered || pullGestureRegistered) { if (mFrame.Hands.Count == 1) { if (pushGestureRegistered) { if (mFrame.Hands[0].PalmVelocity.y < -EasyLeapGesture.MinPushPullVelocity) { PushGestureRecognised(EasyLeapGestureState.STATESTART); } else { PushGestureRecognised(EasyLeapGestureState.STATEINVALID); } } if (pullGestureRegistered) { if (mFrame.Hands[0].PalmVelocity.y > EasyLeapGesture.MinPushPullVelocity) { PullGestureRecognised(EasyLeapGestureState.STATESTART); } else { PullGestureRecognised(EasyLeapGestureState.STATEINVALID); } } } else { PushGestureRecognised(EasyLeapGestureState.STATEINVALID); PullGestureRecognised(EasyLeapGestureState.STATEINVALID); } } if (doubleInwardsSwipeGestureRegistered || doubleOutwardsSwipeGestureRegistered) { if (mFrame.Hands.Count == 2) { bool leftHandSwipeIn = (PalmIsHorizontal(mFrame.Hands.Leftmost)) && mFrame.Hands.Leftmost.PalmVelocity.x > EasyLeapGesture.MinSwipeVelocity; bool rightHandSwipeIn = (PalmIsHorizontal(mFrame.Hands.Rightmost)) && mFrame.Hands.Rightmost.PalmVelocity.x < -EasyLeapGesture.MinSwipeVelocity; if (doubleInwardsSwipeGestureRegistered && (leftHandSwipeIn && rightHandSwipeIn)) { if (mFrame.Hands[0].StabilizedPalmPosition.DistanceTo(mFrame.Hands[1].StabilizedPalmPosition) < EasyLeapGesture.MaxPalmDistance) { DoubleInwardsSwipeRecognised(EasyLeapGestureState.STATESTART); } } else { DoubleInwardsSwipeRecognised(EasyLeapGestureState.STATEINVALID); } bool leftHandSwipeOut = (PalmIsHorizontal(mFrame.Hands.Leftmost)) && mFrame.Hands.Leftmost.PalmVelocity.x < -EasyLeapGesture.MinSwipeVelocity; bool rightHandSwipeOut = (PalmIsHorizontal(mFrame.Hands.Rightmost)) && mFrame.Hands.Rightmost.PalmVelocity.x > EasyLeapGesture.MinSwipeVelocity; if (doubleOutwardsSwipeGestureRegistered && leftHandSwipeOut && rightHandSwipeOut) { if (mFrame.Hands[0].StabilizedPalmPosition.DistanceTo(mFrame.Hands[1].StabilizedPalmPosition) > EasyLeapGesture.MaxPalmDistance) { DoubleOutwardsSwipeRecognised(EasyLeapGestureState.STATESTART); } } else { DoubleOutwardsSwipeRecognised(EasyLeapGestureState.STATEINVALID); } } } if (clapGestureRegistered) { if (mFrame.Hands.Count == 2) { bool leftHandSwipeIn = (!PalmIsHorizontal(mFrame.Hands.Leftmost)) && mFrame.Hands.Leftmost.PalmVelocity.x > EasyLeapGesture.MinClapVelocity; bool rightHandSwipeIn = (!PalmIsHorizontal(mFrame.Hands.Rightmost)) && mFrame.Hands.Rightmost.PalmVelocity.x < -EasyLeapGesture.MinClapVelocity; if (leftHandSwipeIn && rightHandSwipeIn) { if (mFrame.Hands[0].StabilizedPalmPosition.DistanceTo(mFrame.Hands[1].StabilizedPalmPosition) < EasyLeapGesture.MaxPalmClapDistance) { ClapRecognised(EasyLeapGestureState.STATESTART); } } else { ClapRecognised(EasyLeapGestureState.STATEINVALID); } } } if (steeringWheelRegistered) { float palmsAngle = (mFrame.Hands.Leftmost.PalmNormal.AngleTo(mFrame.Hands.Rightmost.PalmNormal) * Mathf.Rad2Deg); if (mFrame.Hands.Count >= 1 && fingerCount < 2 && (palmsAngle > 110 || palmsAngle < 70)) { Leap.Vector leftMost = mFrame.Hands.Leftmost.StabilizedPalmPosition; Leap.Vector rightMost = mFrame.Hands.Rightmost.StabilizedPalmPosition; Leap.Vector steerVector = (leftMost - rightMost).Normalized; //steerVector.z = 0; float angle = steerVector.AngleTo(Leap.Vector.Left) * Mathf.Rad2Deg * (leftMost.y > rightMost.y ? 1 : -1); SteeringWheelRecognised(angle, Mathf.Abs(leftMost.z) - Mathf.Abs(rightMost.z)); } } // Send gestures detected to all registered gesture listeners SendGesturesToListeners(); }
/// <summary> /// 判定一个摊开手掌的状态是否是水平向前 /// </summary> /// <returns><c>true</c>, if and forward open hand was hored, <c>false</c> otherwise.</returns> bool IsHorAndForwardOpenHand(Vector palmDir,Vector fingerDir ) { bool isHorAndForward = false; if( fingerDir.AngleTo(-Vector.ZAxis) < ForwardThreshold && palmDir.AngleTo(-Vector.YAxis) < DownThreshold ) { isHorAndForward=true; } return isHorAndForward; }
// Update is called once per frame void Update() { int clickIndex; //这里的判定本该分成预备状态、运动状态、终结状态。但是对于点击来讲,这三个状态的手势判定条件都相同(手势相同、阈值相同) //所以现在都用同一个控制器来表示 if (EnterClickState(out clickIndex)) { //初始状态 if(!m_IsEnteredClick) { //标记进入点击状态,记录初始位置 m_IsEnteredClick = true; m_EnterPos = m_HandData.FingerDatas[clickIndex][Finger.FingerType.TYPE_INDEX].m_Point.m_Position; m_PreviousPos = m_EnterPos; //延迟触发初始事件 StartCoroutine(EnterClickDelay()); } //非初始状态 else //不是反弹状态 if(!m_IsEnteredBackClick) { m_DeepClickingTime+=Time.deltaTime; //是否进入一次位置判定 if (m_DeepClickingTime > CheckTimeStep) { m_DeepClickingTime = 0f; //收集当前手指索引的食指指尖位置数据 Vector indexFingerTipPos = m_HandData.FingerDatas[clickIndex][Finger.FingerType.TYPE_INDEX].m_Point.m_Position; m_Off = indexFingerTipPos - m_PreviousPos; //是向前点击状态,偏移向量与-z轴(Leap坐标系)的夹角小于某个阈值 if(m_Off.AngleTo(-Vector.ZAxis)<DeepClickRadianThreshold) //if (indexFingerTipPos.z < m_PreviousPos.z) { float deep = m_EnterPos.z - indexFingerTipPos.z; //是反弹状态 if( deep > DeepThreshold ) { //标记进入了反弹状态,记录反弹状态的位置 m_IsEnteredBackClick = true; m_EnterBackPos = indexFingerTipPos; if(m_OnBackFunc != null) { // print("aaa"); m_OnBackFunc(); } } } //不是前进状态 else { //手势匹配失败,重置变量 ResetClickState(); } //更新m_PreviousPos的位置 m_PreviousPos = indexFingerTipPos; } } else //进入了返回状态 { m_BackClickingTime+=Time.deltaTime; //进入位置判定 if ( m_BackClickingTime > CheckTimeStep ) { m_BackClickingTime = 0f; Vector indexFingerTipPos = m_HandData.FingerDatas[clickIndex][Finger.FingerType.TYPE_INDEX].m_Point.m_Position; //是后退状态 if (m_PreviousPos.z < indexFingerTipPos.z) { float backDeep = indexFingerTipPos.z - m_EnterBackPos.z; //满足了反弹阈值 if( backDeep > BackThreshold ) { print("Clicked"); //触发事件,重置状态 if (m_OnClicked!=null) { print("Clicked()"); m_OnClicked(); } ResetClickState(); } } } } } //不是手指点击状态 else { ResetClickState(); m_IsEnteredClick = false; } }
/// <summary> /// 判定一个手指指向是否是点击前方 /// 这里阈值的判定与其说是+x轴,倒不如说是距离yz面的夹角程度更直接,但实现方式上选择了+x轴。 /// </summary> /// <param name="dir"></param> /// <param name="threshold">表示距离+x的夹角,标准是90度</param> bool IsPointAsClickForwardDir(Vector dir,float threshold) { bool IsPointAsClick = false; float radian = dir.AngleTo(Vector.Right); if (radian > threshold && radian < Mathf.PI - threshold) { IsPointAsClick = true; } return IsPointAsClick; }