/// <summary> /// Handle mouse click actions according to eye state /// </summary> /// <returns></returns> private bool HandleMouseClickActions() { float meanRightClosed = 0; float meanLeftClosed = 0; for (int i = leftEyeClosedHistory.Count - 1; i >= leftEyeClosedHistory.Count - 1 - nudConvolutionFilterLength.Value; i--) { if (leftEyeClosedHistory[i]) { meanLeftClosed++; } if (rightEyeClosedHistory[i]) { meanRightClosed++; } } int divisor = (leftEyeClosedHistory.Count) - (leftEyeClosedHistory.Count - 1 - (int)nudConvolutionFilterLength.Value); meanRightClosed = meanRightClosed / divisor; meanLeftClosed = meanLeftClosed / divisor; if (mousePositionHistory.Count - 1 - nudConvolutionFilterLength.Value <= 0) { return(false); } if ((meanLeftClosed > (float)nudEyeClosedFilterThreshold.Value && meanRightClosed > (float)nudDoubleClickSecondEyeThreshold.Value) || (meanLeftClosed > (float)nudDoubleClickSecondEyeThreshold.Value && meanRightClosed > (float)nudEyeClosedFilterThreshold.Value)) { MouseControl.Move(mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].X, mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].Y); MouseControl.Click(); MouseControl.Click(); this.lbAction.Invoke((MethodInvoker)(() => this.lbAction.Items.Add("Double Click on X: " + mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].X + " Y: " + mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].Y))); return(true); } else if (meanLeftClosed > (float)nudEyeClosedFilterThreshold.Value) { MouseControl.Move(mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].X, mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].Y); MouseControl.Click(); this.lbAction.Invoke((MethodInvoker)(() => this.lbAction.Items.Add("Left Click on X: " + mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].X + " Y: " + mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].Y))); return(true); } else if (meanRightClosed > (float)nudEyeClosedFilterThreshold.Value) { MouseControl.Move(mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].X, mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].Y); MouseControl.RightClick(); this.lbAction.Invoke((MethodInvoker)(() => this.lbAction.Items.Add("Right Click on X: " + mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].X + " Y: " + mousePositionHistory[mousePositionHistory.Count - 1 - (int)nudConvolutionFilterLength.Value].Y))); return(true); } return(false); }
private void MoveMouseAccordingToFaceRotation(FaceTrackFrame currentFaceFrame) { if (headRotationHistory.Count > gaussFilter.Count - 1 && leftEyeClosedHistory.Count > nudConvolutionFilterLength.Value && currentFaceFrame.TrackSuccessful) { lastFramesReady = DateTime.Now; if (status == StatusEnum.Initializing) { SetReadyStatus(); } else { if (status == StatusEnum.UnreadyDeactivated) { SwitchStatus(StatusEnum.ReadyActivated); } else if (status == StatusEnum.ReadyActivated) { float browRaiserValue = currentFaceFrame.GetAnimationUnitCoefficients()[AnimationUnit.BrowRaiser]; float browLowererValue = currentFaceFrame.GetAnimationUnitCoefficients()[AnimationUnit.BrowLower]; float mouthOpenValue = currentFaceFrame.GetAnimationUnitCoefficients()[AnimationUnit.JawLower]; if (browRaiserHistory.Count >= 100) { browRaiserHistory.RemoveAt(0); browLowererHistory.RemoveAt(0); mouthOpenHistory.RemoveAt(0); } browLowererHistory.Add(browLowererValue); browRaiserHistory.Add(browRaiserValue); mouthOpenHistory.Add(mouthOpenValue); //Method 1: Without Smoothing //System.Drawing.Point smoothedXY = ScaleXY(currentFaceFrame.Rotation); //Method 2: Gaussian Smoothing System.Drawing.Point smoothedXY = CalculateGaussianSmoothedXYPosition(currentFaceFrame); //Check for right, left or Double Click //1. Check if there was already a click 20 Frames ago, or if Drag & Drop is active if (clickDelay > nudClickDelay.Value && !DragnDropActive) { //2. If not, calculate mean values of dy's last 16 Frames if (HandleMouseClickActions()) { clickDelay = 0; } else { //check for open Mouth if (mouthOpenValue > (float)nudMouthOpenStartThreshold.Value && mouthOpenHistory[mouthOpenHistory.Count - 2] > (float)nudMouthOpenConfirmation.Value && mouthOpenHistory[mouthOpenHistory.Count - 3] > (float)nudMouthOpenConfirmation.Value && mouthOpenHistory[mouthOpenHistory.Count - 4] > (float)nudMouthOpenConfirmation.Value) { MouseControl.Move(mousePositionHistory[mousePositionHistory.Count - 4].X, mousePositionHistory[mousePositionHistory.Count - 4].Y); this.lbAction.Invoke((MethodInvoker)(() => this.lbAction.Items.Add("Left Mouse Down on X: " + mousePositionHistory[mousePositionHistory.Count - 4].X + " Y: " + mousePositionHistory[mousePositionHistory.Count - 4].Y))); //lbAction.Items.Add("Left Mouse Down on X: " + mousePositionHistory[mousePositionHistory.Count - 4].X + " Y: " + mousePositionHistory[mousePositionHistory.Count - 4].Y); MouseControl.MouseDownLeft(); DragnDropActive = true; clickDelay = 0; } } } else if (DragnDropActive) { if (mouthOpenValue < (float)nudMouthOpenEndThreshold.Value) { this.lbAction.Invoke((MethodInvoker)(() => this.lbAction.Items.Add("Left Mouse Up on X: " + smoothedXY.X + " Y: " + smoothedXY.Y))); MouseControl.MouseUpLeft(); DragnDropActive = false; clickDelay = 0; } } MouseControl.Move(smoothedXY.X, smoothedXY.Y); HandleScrolling(browRaiserValue, browLowererValue); if (mousePositionHistory.Count > 100) { mousePositionHistory.RemoveAt(0); } mousePositionHistory.Add(new Microsoft.Kinect.Toolkit.FaceTracking.Point(smoothedXY.X, smoothedXY.Y)); File.AppendAllText("mouseLog.txt", DateTime.Now + " - Face and eyes successfully tracked.\n"); } } } }
private void OnAllFramesReady(object sender, AllFramesReadyEventArgs allFramesReadyEventArgs) { ColorImageFrame colorImageFrame = null; DepthImageFrame depthImageFrame = null; SkeletonFrame skeletonFrame = null; File.AppendAllText("mouseLog.txt", DateTime.Now + " - All Kinect frames ready.\n"); try { colorImageFrame = allFramesReadyEventArgs.OpenColorImageFrame(); depthImageFrame = allFramesReadyEventArgs.OpenDepthImageFrame(); skeletonFrame = allFramesReadyEventArgs.OpenSkeletonFrame(); if (colorImageFrame == null || depthImageFrame == null || skeletonFrame == null) { File.AppendAllText("mouseLog.txt", DateTime.Now + " - Color- depth or Skeletonframe is null. Aborting Frame.\n"); return; } // Check for image format changes. The FaceTracker doesn't // deal with that so we need to reset. if (this.depthImageFormat != depthImageFrame.Format) { this.depthImage = null; this.depthImageFormat = depthImageFrame.Format; } if (this.colorImageFormat != colorImageFrame.Format) { this.colorImage = null; this.colorImageFormat = colorImageFrame.Format; } // Create any buffers to store copies of the data we work with if (this.depthImage == null) { this.depthImage = new short[depthImageFrame.PixelDataLength]; } if (this.colorImage == null) { this.colorImage = new byte[colorImageFrame.PixelDataLength]; } // Get the skeleton information if (this.SkeletonData == null || this.SkeletonData.Length != skeletonFrame.SkeletonArrayLength) { this.SkeletonData = new Skeleton[skeletonFrame.SkeletonArrayLength]; } colorImageFrame.CopyPixelDataTo(this.colorImage); depthImageFrame.CopyPixelDataTo(this.depthImage); skeletonFrame.CopySkeletonDataTo(this.SkeletonData); Skeleton activeSkeleton = null; activeSkeleton = (from skel in this.SkeletonData where skel.TrackingState == SkeletonTrackingState.Tracked select skel).FirstOrDefault(); //Idea: Separate Eye-Parts of Color Image //Use learning Algorithm for right and left eye //Detect blink on separated parts of color Image //colorImage is one dimensional array with 640 x 480 x 4 (RGBA) values if (activeSkeleton != null) { File.AppendAllText("mouseLog.txt", DateTime.Now + " - Skeleton is there. Trying to find face.\n"); FaceTrackFrame currentFaceFrame = faceTracker.Track(ColorImageFormat.RgbResolution640x480Fps30, colorImage, depthImageFormat, depthImage, activeSkeleton); if (currentFaceFrame.TrackSuccessful) { File.AppendAllText("mouseLog.txt", DateTime.Now + " - Recognized face successfully.\n"); } else { File.AppendAllText("mouseLog.txt", DateTime.Now + " - Couldn't find face in frame.\n"); } //Get relevant Points for blink detection //Left eye int minX = (int)Math.Round(currentFaceFrame.GetProjected3DShape()[FeaturePoint.AboveOneFourthLeftEyelid].X); int minY = (int)Math.Round(currentFaceFrame.GetProjected3DShape()[FeaturePoint.AboveOneFourthLeftEyelid].Y); int maxX = (int)Math.Round(currentFaceFrame.GetProjected3DShape()[FeaturePoint.BelowThreeFourthLeftEyelid].X); int maxY = (int)Math.Round(currentFaceFrame.GetProjected3DShape()[FeaturePoint.BelowThreeFourthLeftEyelid].Y); Bitmap leftEye = EyeExtract(colorImageFrame, currentFaceFrame, minX, minY, maxX, maxY, false); //this.pbRight.BeginInvoke((MethodInvoker)(() => this.pbRight.Image = leftEye)); // //Right eye minX = (int)Math.Round(currentFaceFrame.GetProjected3DShape()[FeaturePoint.AboveThreeFourthRightEyelid].X); minY = (int)Math.Round(currentFaceFrame.GetProjected3DShape()[FeaturePoint.AboveThreeFourthRightEyelid].Y); maxX = (int)Math.Round(currentFaceFrame.GetProjected3DShape()[FeaturePoint.OneFourthBottomRightEyelid].X); maxY = (int)Math.Round(currentFaceFrame.GetProjected3DShape()[FeaturePoint.OneFourthBottomRightEyelid].Y); Bitmap rightEye = EyeExtract(colorImageFrame, currentFaceFrame, minX, minY, maxX, maxY, true); Bitmap leftEye2 = null; Bitmap rightEye2 = null; if (leftEye != null) { leftEye2 = new Bitmap(leftEye); } if (rightEye != null) { rightEye2 = new Bitmap(rightEye); } // System.Delegate d = new MethodInvoker(SetPictures)); // this.Invoke(SetPictures, leftEye); //pbRight.Image = rightEye; this.pbLeft.BeginInvoke((MethodInvoker)(() => this.pbLeft.Image = rightEye2)); this.pbLeft.BeginInvoke((MethodInvoker)(() => this.pbRight.Image = leftEye2)); // this.Invoke(new MethodInvoker(SetPictures)); //Wende Kantenfilter auf die beiden Augen an. if (rightEye != null && leftEye != null) { Dictionary <string, int> angleCount; Bitmap edgePicRight = Convolution(ConvertGrey(rightEye), true, out angleCount); bool rightEyeClosed = IsEyeClosed(angleCount); Bitmap edgePicLeft = Convolution(ConvertGrey(leftEye), false, out angleCount); bool leftEyeClosed = IsEyeClosed(angleCount); // pbLeftFaltung.Image = edgePicLeft; // pbRightFaltung.Image = edgePicRight; if (rightEyeClosedHistory.Count > 100) { rightEyeClosedHistory.RemoveAt(0); } if (leftEyeClosedHistory.Count > 100) { leftEyeClosedHistory.RemoveAt(0); } leftEyeClosedHistory.Add(leftEyeClosed); rightEyeClosedHistory.Add(rightEyeClosed); //If Face is rotated, move Mouse if (headRotationHistory.Count > gaussFilter.Count - 1 && leftEyeClosedHistory.Count > nudConvolutionFilterLength.Value && currentFaceFrame.TrackSuccessful) { int x = 0; int y = 0; float browRaiserValue = currentFaceFrame.GetAnimationUnitCoefficients()[AnimationUnit.BrowRaiser]; float browLowererValue = currentFaceFrame.GetAnimationUnitCoefficients()[AnimationUnit.BrowLower]; float mouthOpenValue = currentFaceFrame.GetAnimationUnitCoefficients()[AnimationUnit.JawLower]; if (browRaiserHistory.Count >= 100) { browRaiserHistory.RemoveAt(0); browLowererHistory.RemoveAt(0); mouthOpenHistory.RemoveAt(0); } browLowererHistory.Add(browLowererValue); browRaiserHistory.Add(browRaiserValue); mouthOpenHistory.Add(mouthOpenValue); //Method 1: Ohne Glättung //ScaleXY(currentFaceFrame.Rotation, out x, out y); //MouseControl.Move(x, y); ////Method 2: Glättung über die letzten x Bilder: //int i = 0; //Vector3DF rotationMedium = new Vector3DF(); //while (i < 10 && headRotationHistory.Count - 1 > i) //{ // i++; // rotationMedium.X += headRotationHistory[headRotationHistory.Count - 1 - i].X; // rotationMedium.Y += headRotationHistory[headRotationHistory.Count - 1 - i].Y; //} //rotationMedium.X = rotationMedium.X / i; //rotationMedium.Y = rotationMedium.Y / i; //ScaleXY(rotationMedium, out x, out y); //MouseControl.Move(x, y); //Method 3: Gauß-Filter: Gewichte die letzten Bilder stärker. Vector3DF rotationMedium = new Vector3DF(); rotationMedium.X = currentFaceFrame.Rotation.X * gaussFilter[0]; rotationMedium.Y = currentFaceFrame.Rotation.Y * gaussFilter[0]; int i = 0; while (i < gaussFilter.Count - 1) { rotationMedium.X += (headRotationHistory[headRotationHistory.Count - 1 - i].X * gaussFilter[i]); rotationMedium.Y += (headRotationHistory[headRotationHistory.Count - 1 - i].Y * gaussFilter[i]); i++; } rotationMedium.X = (float)(rotationMedium.X / gaussFactor); rotationMedium.Y = (float)(rotationMedium.Y / gaussFactor); ScaleXY(rotationMedium, out x, out y); //Method 4: Quadratische Glättung //double deltaX = ((-currentFaceFrame.Rotation.Y) - (-headRotationHistory.Last().Y)); //double deltaY = ((-currentFaceFrame.Rotation.X) - (-headRotationHistory.Last().X)); //if (deltaX < 0) // deltaX = -Math.Pow(deltaX, 2) * 4; //else // deltaX = Math.Pow(deltaX, 2) * 4; //if (deltaY < 0) // deltaY = -Math.Pow(deltaY, 2) * 5; //else // deltaY = Math.Pow(deltaY, 2) * 5; //MouseControl.DeltaMove((int)Math.Round(deltaX, 0), (int)Math.Round(deltaY)); //Check for right, left or Double Click //1. Check if there was already a click 20 Frames ago, or if Drag & Drop is active if (clickDelay > nudClickDelay.Value && !pointNClickActive) { //2. If not, calculate mean values of dy's last 16 Frames if (CalculateMeanConvolutionValues()) { clickDelay = 0; } else { //Else check for open Mouth if (mouthOpenValue > (float)nudMouthOpenStartThreshold.Value && mouthOpenHistory[mouthOpenHistory.Count - 2] > (float)nudMouthOpenConfirmation.Value && mouthOpenHistory[mouthOpenHistory.Count - 3] > (float)nudMouthOpenConfirmation.Value && mouthOpenHistory[mouthOpenHistory.Count - 4] > (float)nudMouthOpenConfirmation.Value) { MouseControl.Move(mousePositionHistory[mousePositionHistory.Count - 4].X, mousePositionHistory[mousePositionHistory.Count - 4].Y); this.lbAction.Invoke((MethodInvoker)(() => this.lbAction.Items.Add("Left Mouse Down on X: " + mousePositionHistory[mousePositionHistory.Count - 4].X + " Y: " + mousePositionHistory[mousePositionHistory.Count - 4].Y))); //lbAction.Items.Add("Left Mouse Down on X: " + mousePositionHistory[mousePositionHistory.Count - 4].X + " Y: " + mousePositionHistory[mousePositionHistory.Count - 4].Y); MouseControl.MouseDownLeft(); pointNClickActive = true; clickDelay = 0; } } } else if (pointNClickActive) { if (mouthOpenValue < (float)nudMouthOpenEndThreshold.Value) { this.lbAction.Invoke((MethodInvoker)(() => this.lbAction.Items.Add("Left Mouse Up on X: " + x + " Y: " + y))); MouseControl.MouseUpLeft(); pointNClickActive = false; clickDelay = 0; } } MouseControl.Move(x, y); if (browLowererValue > (float)nudBrowLowererStartThreshold.Value) { MouseControl.ScrollDown((int)(-browLowererValue * (int)nudScrollMultiplierDown.Value)); } if (browRaiserValue > (float)nudBrowRaiserStartThreshold.Value) { MouseControl.ScrollDown((int)(browRaiserValue * (int)nudScrollMultiplierUp.Value)); } if (mousePositionHistory.Count > 100) { mousePositionHistory.RemoveAt(0); } mousePositionHistory.Add(new Microsoft.Kinect.Toolkit.FaceTracking.Point(x, y)); File.AppendAllText("mouseLog.txt", DateTime.Now + " - Face and eyes successfully tracked.\n"); } } else { File.AppendAllText("mouseLog.txt", DateTime.Now + " - Face recognized but couldn't find eye in face.\n"); } clickDelay++; headRotationHistory.Add(currentFaceFrame.Rotation); if (headRotationHistory.Count >= 100) { headRotationHistory.RemoveAt(0); } } else { File.AppendAllText("mouseLog.txt", DateTime.Now + " - Active Skeleton is null. Couldn't analyze frame.\n"); } } catch (Exception e) { File.AppendAllText("mouseLog.txt", DateTime.Now + " - Error during frame analyzation.\n" + e.ToString()); } finally { if (colorImageFrame != null) { colorImageFrame.Dispose(); } if (depthImageFrame != null) { depthImageFrame.Dispose(); } if (skeletonFrame != null) { skeletonFrame.Dispose(); } } }