CalibrationDuringGazeRecording
This example is more comprehensive than most, as it aims to illustrate how you can put together a complete, ready-to-run script, by combining information from different examples. Note that running this script will produce a small CSV data file in the working directory.
clear; Tobii = EyeTrackingOperations(); % Enter the address to the desired eye tracker if you have % more than one (otherwise leave this as an empty string). % example address: 'tet-tcp://10.46.32.51'; eyetracker_address = ''; % Check if a specific eye tracker address has been provided, and if so, % try to locate it and return the corresponding eye tracker object. if (~strcmp(eyetracker_address, '')) try eyetracker = Tobii.get_eyetracker(eyetracker_address); catch ME if (strcmp(ME.identifier,'EyeTrackerGet:error204')) fprintf('Unable to connect to specified eye tracker.\n'); return end end else try eyetrackers = Tobii.find_all_eyetrackers(); eyetracker = eyetrackers(1); catch fprintf("Unable to find any connected eye trackers.\n"); return end end eyetracker.get_gaze_data(); % check if gaze data collection seems to be working % TODO before commit: pause pause(1); result = eyetracker.get_gaze_data(); if isa(result,'StreamError') fprintf('Gaze data stream Error: %s\n',string(result.Error.value)); fprintf('Source: %s\n',string(result.Source.value)); fprintf('SystemTimeStamp: %d\n',result.SystemTimeStamp); fprintf('Message: %s\n',result.Message); return end % Start calibration procedure (while gaze recording is running % in the background) calib = ScreenBasedCalibration(eyetracker); try calib.enter_calibration_mode(); catch ME if (strcmp(ME.identifier,'EnterCalibrationMode:error210')) fprintf('The previous calibration was not completed!\n'); calib.leave_calibration_mode() fprintf('Calibration is restarted\n'); calib.enter_calibration_mode() else fprintf('%s\n', ME.identifier); return end end % Define the points on screen we should calibrate at. % The coordinates are normalized, i.e. [0.0, 0.0] is the upper left corner and % [1.0, 1.0] is the lower right corner. points_to_collect = [[0.1,0.1];[0.1,0.9];[0.5,0.5];[0.9,0.1];[0.9,0.9]]; % When collecting data a point should be presented on the screen in the % appropriate position. We do not provide this here, but you may wish to % use Matlab's own 'imshow' function for this, or a 3rd party package % like Psychtoolbox for this purpose. for i=1:size(points_to_collect,1) collect_result = calib.collect_data(points_to_collect(i,:)); fprintf('Point [%.2f,%.2f] Collect Result: %d\n',points_to_collect(i,:),collect_result.value); end calibration_result = calib.compute_and_apply(); fprintf('Calibration Status: %d\n',calibration_result.Status.value.value); % After analysing the calibration result one might want to re-calibrate % some of the points (this would need to be done in an interactive fashion % however - you would most likely want to write your own logic for handling % this, or find a 3rd party package that 'wraps' this Tobii package and handles % things for you). points_to_recalibrate = [[0.1,0.1];[0.1,0.9]]; for i=1:size(points_to_recalibrate,1) calib.discard_data(points_to_recalibrate(i,:)); collect_result = calib.collect_data(points_to_recalibrate(i,:)); fprintf('Point [%.2f,%.2f] Collect Result: %d\n',points_to_recalibrate(i,:),collect_result.value); end calibration_result = calib.compute_and_apply(); fprintf('Calibration Status: %d\n',calibration_result.Status.value.value); % Check if the calibration result was successful, meaning a calibration could % be performed. Note that depending on your requirements, the calibration % might still not be of high enough quality. You would need to also run a % validation of the calibration to evaluate this. if calibration_result.Status == CalibrationStatus.Success points = calibration_result.CalibrationPoints; number_points = size(points,2); % plot the calibration points and associated data for i=1:number_points plot(points(i).PositionOnDisplayArea(1),points(i).PositionOnDisplayArea(2),'ok','LineWidth',10); mapping_size = size(points(i).RightEye,2); set(gca, 'YDir', 'reverse'); axis([-0.2 1.2 -0.2 1.2]) hold on; for j=1:mapping_size if points(i).LeftEye(j).Validity == CalibrationEyeValidity.ValidAndUsed plot(points(i).LeftEye(j).PositionOnDisplayArea(1), points(i).LeftEye(j).PositionOnDisplayArea(2),'-xr','LineWidth',3); end if points(i).RightEye(j).Validity == CalibrationEyeValidity.ValidAndUsed plot(points(i).RightEye(j).PositionOnDisplayArea(1),points(i).RightEye(j).PositionOnDisplayArea(2),'xb','LineWidth',3); end end end end calib.leave_calibration_mode(); % Now that calibration is finished, get the gaze data recorded in the meantime. gaze_data = eyetracker.get_gaze_data(); eyetracker.stop_gaze_data(); n_collected = size(gaze_data, 1); fprintf('Collected %d data points\n', n_collected); % Store the relevant data to N-by-1 arrays to simplify saving below % (please see the reference guide documentation on GazeData for % information on what other properties/data are available) left_eye_xs = zeros(n_collected, 1); right_eye_ys = zeros(n_collected, 1); left_eye_xs = zeros(n_collected, 1); right_eye_ys = zeros(n_collected, 1); sample_times_from_start = zeros(n_collected, 1); first_t = gaze_data(1).SystemTimeStamp; for i=1:length(gaze_data) single_data = gaze_data(i); left_gp = single_data.LeftEye.GazePoint; right_gp = single_data.RightEye.GazePoint; left_eye_xs(i) = left_gp.OnDisplayArea(1); left_eye_ys(i) = left_gp.OnDisplayArea(2); right_eye_xs(i) = right_gp.OnDisplayArea(1); right_eye_ys(i) = right_gp.OnDisplayArea(2); sample_time_from_start_us = single_data.SystemTimeStamp - first_t; % convert from microseconds to seconds sample_time_from_start_s = double(sample_time_from_start_us) / 1000000; sample_times_from_start(i) = sample_time_from_start_s; end output_matrix = [ sample_times_from_start(:), ... left_eye_xs(:), ... left_eye_ys(:), ... right_eye_xs(:), ... right_eye_ys(:) ]; % Save the data to a CSV format file % (first writing column headers to file) header_lines = ["time_seconds", "left_x", "left_y", "right_x", "right_y"]; writematrix(header_lines, 'gaze_data.csv'); writematrix(output_matrix, 'gaze_data.csv', 'WriteMode', 'append');