protected override void GazeDataReceivedSynchronized(object sender, GazeDataItem gazePoint) { lock (this) { if (collectingData) { gazePoints.AddLast(gazePoint); } } }
/// <summary> /// The on gaze data. /// </summary> /// <param name="gd"> /// The gd. /// </param> public void OnGazeData(GazeDataItem gd) { // Add data to history this.dataHistory.Enqueue(gd); // Remove history item if necessary while (this.dataHistory.Count > HistorySize) { this.dataHistory.Dequeue(); } this.leftValidity = gd.LeftValidity; this.rightValidity = gd.RightValidity; this.leftEye = gd.LeftEyePosition3DRelative; this.rightEye = gd.RightEyePosition3DRelative; this.Invalidate(); }
/// <summary> /// Forwards 2D gaze points to fixation detector. Gaze points are only forwarded /// if CPU and Eyetracker clocks are synchronized and validity is < 2. If both eyes are valid gaze point coordinates are averaged, /// if only one eye is valid, only that eye's gaze point is used. /// </summary> /// <param name="sender"></param> /// <param name="e">GazeDataItem to process</param> protected override void GazeDataReceivedSynchronized(object sender, GazeDataItem gazePoint) { // ignore gaze data with low validity if (gazePoint.LeftValidity < 2 || gazePoint.RightValidity < 2) { // convert timestamp long microseconds = syncManager.RemoteToLocal(gazePoint.TimeStamp); int milliseconds = (int)(microseconds / 1000); int time = milliseconds; if (((microseconds / 100) % 10) >= 5) { time++; // round } // convert normalized screen coordinates (float between [0 - 1]) to pixel coordinates // coordinates (0, 0) designate the top left corner double leftX = gazePoint.LeftGazePoint2D.X * SCREEN_WIDTH; double leftY = gazePoint.LeftGazePoint2D.Y * SCREEN_HEIGHT; double rightX = gazePoint.RightGazePoint2D.X * SCREEN_WIDTH; double rightY = gazePoint.RightGazePoint2D.Y * SCREEN_HEIGHT; if (gazePoint.LeftValidity < 2 && gazePoint.RightValidity < 2) { // average left and right eyes int x = (int)((leftX + rightX) / 2); int y = (int)((leftY + rightY) / 2); fixationDetector.addPoint(time, x, y); } else if (gazePoint.LeftValidity < 2) { // use only left eye fixationDetector.addPoint(time, (int)leftX, (int)leftY); } else if (gazePoint.RightValidity < 2) { // use only right eye fixationDetector.addPoint(time, (int)rightX, (int)rightY); } } }
// filter gaze data by EyeValidity private Vector2D?GetAverageGazePoint(GazeDataItem data) { if (data.LeftValidity == 0 && data.RightValidity == 0) { return(new Vector2D((data.LeftGazePoint2D.X + data.RightGazePoint2D.X) * 0.5, (data.LeftGazePoint2D.Y + data.RightGazePoint2D.Y) * 0.5)); } else if (data.LeftValidity < 2 && data.LeftValidity <= data.RightValidity) { return(new Vector2D(data.LeftGazePoint2D.X, data.LeftGazePoint2D.Y)); } else if (data.RightValidity < 2 && data.RightValidity <= data.LeftValidity) { return(new Vector2D(data.RightGazePoint2D.X, data.RightGazePoint2D.Y)); } else if (data.LeftValidity == 2 && data.RightValidity == 2) { return(new Vector2D(data.LeftGazePoint2D.X, data.LeftGazePoint2D.Y)); } else { return(null); } }
// constructor public CustomGazeData(GazeDataItem gdi) { lePos3D = new Vector3D(gdi.LeftEyePosition3D.X * invertXAxis, gdi.LeftEyePosition3D.Y, gdi.LeftEyePosition3D.Z); rePos3D = new Vector3D(gdi.RightEyePosition3D.X * invertXAxis, gdi.RightEyePosition3D.Y, gdi.RightEyePosition3D.Z); lePos3DRel = new Vector3D(gdi.LeftEyePosition3DRelative.X * invertXAxis, gdi.LeftEyePosition3DRelative.Y, gdi.LeftEyePosition3DRelative.Z); rePos3DRel = new Vector3D(gdi.RightEyePosition3DRelative.X * invertXAxis, gdi.RightEyePosition3DRelative.Y, gdi.RightEyePosition3DRelative.Z); leGazePoint = new Vector3D(gdi.LeftGazePoint3D.X * invertXAxis, gdi.LeftGazePoint3D.Y, gdi.LeftGazePoint3D.Z); reGazePoint = new Vector3D(gdi.RightGazePoint3D.X * invertXAxis, gdi.RightGazePoint3D.Y, gdi.RightGazePoint3D.Z); leGazePointRel = new Vector2D(gdi.LeftGazePoint2D.X, gdi.LeftGazePoint2D.Y); reGazePointRel = new Vector2D(gdi.RightGazePoint2D.X, gdi.RightGazePoint2D.Y); leValidity = gdi.LeftValidity; reValidity = gdi.RightValidity; lePupilDiameter = gdi.LeftPupilDiameter; rePupilDiameter = gdi.RightPupilDiameter; }
public EyetrackerEvent(GazeDataItem gdi) { this.gdi = gdi; }
/// <summary> /// Writes (X, Y) coordinate of gaze point to console if CPU and eyetracker clocks are synchronized. /// /// Detailed explanation of synchronization available in Tobii SDK 3.0 Developer Guide. /// http://www.tobii.com/Global/Analysis/Downloads/User_Manuals_and_Guides/Tobii%20SDK%203.0%20Release%20Candidate%201%20Developers%20Guide.pdf /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected override void GazeDataReceivedSynchronized(object sender, GazeDataItem gazePoint) { Print(gazePoint); }
/// <summary> /// Forwards 2D gaze points to fixation detector. Gaze points are only forwarded /// if CPU and Eyetracker clocks are synchronized and validity is < 2. If both eyes are valid gaze point coordinates are averaged, /// if only one eye is valid, only that eye's gaze point is used. /// </summary> /// <param name="sender"></param> /// <param name="e">GazeDataItem to process</param> protected override void GazeDataReceivedSynchronized(object sender, GazeDataItem gazePoint) { // ignore gaze data with low validity if (gazePoint.LeftValidity < 2 || gazePoint.RightValidity < 2) { // convert timestamp long microseconds = syncManager.RemoteToLocal(gazePoint.TimeStamp); int milliseconds = (int)(microseconds / 1000); int time = milliseconds; if (((microseconds / 100) % 10) >= 5) time++; // round // convert normalized screen coordinates (float between [0 - 1]) to pixel coordinates // coordinates (0, 0) designate the top left corner double leftX = gazePoint.LeftGazePoint2D.X * SCREEN_WIDTH; double leftY = gazePoint.LeftGazePoint2D.Y * SCREEN_HEIGHT; double rightX = gazePoint.RightGazePoint2D.X * SCREEN_WIDTH; double rightY = gazePoint.RightGazePoint2D.Y * SCREEN_HEIGHT; if (gazePoint.LeftValidity < 2 && gazePoint.RightValidity < 2) { // average left and right eyes int x = (int)((leftX + rightX) / 2); int y = (int)((leftY + rightY) / 2); fixationDetector.addPoint(time, x, y); } else if (gazePoint.LeftValidity < 2) { // use only left eye fixationDetector.addPoint(time, (int)leftX, (int)leftY); } else if (gazePoint.RightValidity < 2) { // use only right eye fixationDetector.addPoint(time, (int)rightX, (int)rightY); } } }
/// <summary> /// Writes gaze data information to console. /// </summary> /// <param name="gazePoint">GazeDataItem to write to console</param> protected void Print(GazeDataItem gazePoint) { int ms = (int)syncManager.RemoteToLocal(gazePoint.TimeStamp); Console.WriteLine("GazePoint [" + ms + "] - (" + gazePoint.LeftGazePoint2D.X * FixationDetector.SCREEN_WIDTH + ", " + gazePoint.LeftGazePoint2D.Y * FixationDetector.SCREEN_HEIGHT + ")"); }
/////////////////////////////////////////////////////////////////////////////// // Defining Properties // /////////////////////////////////////////////////////////////////////////////// #region PROPERTIES #endregion //PROPERTIES /////////////////////////////////////////////////////////////////////////////// // Eventhandler // /////////////////////////////////////////////////////////////////////////////// #region EVENTS /// <summary> /// Updates the status control with the incoming gaze data. /// </summary> /// <param name="gd">The <see cref="GazeDataItem"/> with the current /// gaze data.</param> public void Update(GazeDataItem gd) { this.tobiiTrackStatusControl.OnGazeData(gd); }
/// <summary> /// Writes gaze data information to console. /// </summary> /// <param name="gazePoint">GazeDataItem to write to console</param> protected void Print(GazeDataItem gazePoint) { int ms = (int)syncManager.RemoteToLocal(gazePoint.TimeStamp); Console.WriteLine("GazePoint [" + ms + "] - (" + gazePoint.LeftGazePoint2D.X*FixationDetector.SCREEN_WIDTH + ", " + gazePoint.LeftGazePoint2D.Y*FixationDetector.SCREEN_HEIGHT + ")"); }
/// <summary> /// Method to implement that handles the received eyetracker gaze data. /// </summary> /// <param name="sender"></param> /// <param name="gazePoint"></param> protected abstract void GazeDataReceivedSynchronized(object sender, GazeDataItem gazePoint);
/// <summary> /// Writes gaze data information to console. /// </summary> /// <param name="gazePoint">GazeDataItem to write to console</param> protected void Print(GazeDataItem gazePoint) { int ms = (int)syncManager.RemoteToLocal(gazePoint.TimeStamp); Console.WriteLine("GazePoint [" + ms + "] - (" + gazePoint.LeftEyePosition3D.X + ", " + gazePoint.LeftEyePosition3D.Y + ")"); }
/// <summary> /// OnGazeData event handler for connected tracker. /// This event fires whenever there are new gaze data /// to receive. /// It converts the interface internal gaze structure into /// a OGAMA readable format and fires the <see cref="Tracker.OnGazeDataChanged"/> /// event to the recorder. /// </summary> /// <param name="sender"> /// Source of the event /// </param> /// <param name="e"> /// The <see cref="GazeDataEventArgs"/> with the new gaze data /// from the device. /// </param> private void ConnectedTrackerGazeDataReceived(object sender, GazeDataEventArgs e) { // Send the gaze data to the track status control. GazeDataItem gd = e.GazeDataItem; this.tobiiTrackStatus.OnGazeData(gd); if (this.dlgTrackStatus != null && this.dlgTrackStatus.Visible) { this.dlgTrackStatus.Update(gd); } // Convert Tobii gazestamp in milliseconds. var newGazeData = new GazeData { Time = gd.TimeStamp / 1000 }; // The validity code takes one of five values for each eye ranging from 0 to 4, with the // following interpretation: // 0 - The eye tracker is certain that the data for this eye is right. There is no risk of // confusing data from the other eye. // 1 - The eye tracker has only recorded one eye, and has made some assumptions and // estimations regarding which is the left and which is the right eye. However, it is still // very likely that the assumption made is correct. The validity code for the other eye is // in this case always set to 3. // 2 - The eye tracker has only recorded one eye, and has no way of determining which // one is left eye and which one is right eye. The validity code for both eyes is set to 2. // 3 - The eye tracker is fairly confident that the actual gaze data belongs to the other // eye. The other eye will always have validity code 1. // 4 - The actual gaze data is missing or definitely belonging to the other eye. // Hence, there are a limited number of possible combinations of validity codes for the // two eyes: // Code Description // 0 - 0 Both eyes found. Data is valid for both eyes. // 0 - 4 or 4 - 0 One eye found. Gaze data is the same for both eyes. // 1 – 3 or 3 - 1 One eye found. Gaze data is the same for both eyes. // 2 – 2 One eye found. Gaze data is the same for both eyes. // 4 – 4 No eye found. Gaze data for both eyes are invalid. // Use data only if both left and right eye was found by the eye tracker // It is recommended that the validity codes are always used for data filtering, // to remove data points which are obviously incorrect. // Normally, we recommend removing all data points with a validity code of 2 or higher. if (gd.LeftValidity == 0 && gd.RightValidity == 0) { // Let the x, y and distance be the right and left eye average newGazeData.GazePosX = (float)((gd.LeftGazePoint2D.X + gd.RightGazePoint2D.X) / 2); newGazeData.GazePosY = (float)((gd.LeftGazePoint2D.Y + gd.RightGazePoint2D.Y) / 2); newGazeData.PupilDiaX = gd.LeftPupilDiameter; newGazeData.PupilDiaY = gd.RightPupilDiameter; } else if (gd.LeftValidity == 4 && gd.RightValidity == 4) { newGazeData.GazePosX = 0; newGazeData.GazePosY = 0; newGazeData.PupilDiaX = 0; newGazeData.PupilDiaY = 0; } else if (gd.LeftValidity == 2 && gd.RightValidity == 2) { newGazeData.GazePosX = 0; newGazeData.GazePosY = 0; newGazeData.PupilDiaX = 0; newGazeData.PupilDiaY = 0; } else if (gd.LeftValidity == 1 && gd.RightValidity == 3) { newGazeData.GazePosX = (float)gd.LeftGazePoint2D.X; newGazeData.GazePosY = (float)gd.LeftGazePoint2D.Y; newGazeData.PupilDiaX = gd.LeftPupilDiameter; newGazeData.PupilDiaY = null; } else if (gd.LeftValidity == 3 && gd.RightValidity == 1) { newGazeData.GazePosX = (float)gd.RightGazePoint2D.X; newGazeData.GazePosY = (float)gd.RightGazePoint2D.Y; newGazeData.PupilDiaX = null; newGazeData.PupilDiaY = gd.RightPupilDiameter; } else if (gd.LeftValidity == 0 && gd.RightValidity == 4) { newGazeData.GazePosX = (float)gd.LeftGazePoint2D.X; newGazeData.GazePosY = (float)gd.LeftGazePoint2D.Y; newGazeData.PupilDiaX = gd.LeftPupilDiameter; newGazeData.PupilDiaY = null; } else if (gd.LeftValidity == 4 && gd.RightValidity == 0) { newGazeData.GazePosX = (float)gd.RightGazePoint2D.X; newGazeData.GazePosY = (float)gd.RightGazePoint2D.Y; newGazeData.PupilDiaX = null; newGazeData.PupilDiaY = gd.RightPupilDiameter; } else { newGazeData.GazePosX = null; newGazeData.GazePosY = null; newGazeData.PupilDiaX = null; newGazeData.PupilDiaY = null; } this.OnGazeDataChanged(new GazeDataChangedEventArgs(newGazeData)); }
public void OnGazeData(GazeDataItem gd) { // Add data to history _dataHistory.Enqueue(gd); // Remove history item if necessary while (_dataHistory.Count > HistorySize) { _dataHistory.Dequeue(); } _leftValidity = gd.LeftValidity; _rightValidity = gd.RightValidity; _leftEye = gd.LeftEyePosition3DRelative; _rightEye = gd.RightEyePosition3DRelative; Invalidate(); }