/// <summary> /// Enter the calibration validation mode and starts subscribing to gaze data from the eye tracker. /// </summary> public void EnterValidationMode() { if (State != ValidationState.NotInValidationMode) { throw new InvalidOperationException("Validation mode already entered"); } _dataMap = new List <KeyValuePair <NormalizedPoint2D, Queue <GazeDataEventArgs> > >(); _result.UpdateResult(new List <CalibrationValidationPoint>(), float.NaN, float.NaN, float.NaN, float.NaN, float.NaN, float.NaN); State = ValidationState.NotCollectingData; _eyeTracker.GazeDataReceived += OnGazeDataReceived; }
public CalibrationValidationResult Compute() { if (IsCollectingData) { throw new InvalidOperationException("Compute called while collecting data"); } var points = new List <CalibrationValidationPoint>(); foreach (var kv in _dataMap) { var targetPoint2D = kv.Key; var samples = kv.Value; var targetPoint3D = targetPoint2D.NormalizedPoint2DToPoint3D(_eyeTracker.GetDisplayArea()); if (samples.Count < _sampleCount) { // We timed out before collecting enough valid samples. // Set the timeout flag and continue. points.Add(new CalibrationValidationPoint(targetPoint2D, -1, -1, -1, -1, -1, -1, true, samples.ToArray())); continue; } var gazePointAverageLeft = samples.Average(s => s.LeftEye.GazePoint.PositionInUserCoordinates); var gazePointAverageRight = samples.Average(s => s.RightEye.GazePoint.PositionInUserCoordinates); var gazeOriginAverageLeft = samples.Average(s => s.LeftEye.GazeOrigin.PositionInUserCoordinates); var gazeOriginAverageRight = samples.Average(s => s.RightEye.GazeOrigin.PositionInUserCoordinates); var directionGazePointLeft = gazeOriginAverageLeft.NormalizedDirection(gazePointAverageLeft); var directionTargetLeft = gazeOriginAverageLeft.NormalizedDirection(targetPoint3D); var accuracyLeftEye = directionTargetLeft.Angle(directionGazePointLeft); var directionGazePointRight = gazeOriginAverageRight.NormalizedDirection(gazePointAverageRight); var directionTargetRight = gazeOriginAverageRight.NormalizedDirection(targetPoint3D); var accuracyRightEye = directionTargetRight.Angle(directionGazePointRight); var varianceLeft = samples.Select(s => Math.Pow(s .LeftEye.GazeOrigin.PositionInUserCoordinates.NormalizedDirection(s.LeftEye.GazePoint.PositionInUserCoordinates) .Angle(s.LeftEye.GazeOrigin.PositionInUserCoordinates.NormalizedDirection(gazePointAverageLeft)), 2)).Average(); var varianceRight = samples.Select(s => Math.Pow(s .RightEye.GazeOrigin.PositionInUserCoordinates.NormalizedDirection(s.RightEye.GazePoint.PositionInUserCoordinates) .Angle(s.RightEye.GazeOrigin.PositionInUserCoordinates.NormalizedDirection(gazePointAverageRight)), 2)).Average(); var precisionLeftEye = varianceLeft > 0 ? Math.Sqrt(varianceLeft) : 0; var precisionRightEye = varianceRight > 0 ? Math.Sqrt(varianceRight) : 0; var precisionLeftEyeRMS = samples.RootMeanSquare(s => s.LeftEye); var precisionRightEyeRMS = samples.RootMeanSquare(s => s.RightEye); points.Add(new CalibrationValidationPoint( targetPoint2D, (float)accuracyLeftEye, (float)precisionLeftEye, (float)accuracyRightEye, (float)precisionRightEye, (float)precisionLeftEyeRMS, (float)precisionRightEyeRMS, false, samples.ToArray())); } if (points.Count == 0) { _latestResult.UpdateResult(points, 0, 0, 0); } else { var validPoints = points.Where(p => !p.TimedOut); if (validPoints.Count() == 0) { _latestResult.UpdateResult(points, 0, 0, 0); } else { var avaragePrecisionLeftEye = validPoints.Select(p => p.PrecisionLeftEye).Average(); var avaragePrecisionRightEye = validPoints.Select(p => p.PrecisionRightEye).Average(); var avarageAccuracyLeftEye = validPoints.Select(p => p.AccuracyLeftEye).Average(); var avarageAccuracyRightEye = validPoints.Select(p => p.AccuracyRightEye).Average(); var averagePrecisionLeftEyeRMS = validPoints.Select(p => p.PrecisionLeftEyeRMS).Average(); var averagePrecisionRightEyeRMS = validPoints.Select(p => p.PrecisionRightEyeRMS).Average(); _latestResult.UpdateResult( points, (avarageAccuracyLeftEye + avarageAccuracyRightEye) / 2.0f, (avaragePrecisionLeftEye + avaragePrecisionRightEye) / 2.0f, (averagePrecisionLeftEyeRMS + averagePrecisionRightEyeRMS) / 2.0f); } } return(_latestResult); }