attachment:calibrateEyeTracker.m of EyeTrackingWithMatlab - Meg Wiki
location: attachment:calibrateEyeTracker.m of EyeTrackingWithMatlab

Attachment 'calibrateEyeTracker.m'

Download

   1 % Calibration routine for SMI IViewX eyetracker and Psychtoolbox,
   2 % using the serial port for communication.
   3 % This function is fairly robust - if calibration fails for some
   4 % reason it will quietly print out some warnings and return. If
   5 % calibration failures are catastrophic for your experiment, you will
   6 % need to check the output flag for success==1 in your own script.
   7 % Syntax:
   8 % success = calibrateEyeTracker(window,[ET_serial],[ET_params])
   9 % Inputs (all optional except the Psychtoolbox window):
  10 % window - Psychtoolbox screen handle
  11 % ET_serial - Opened serial port object for scanner. Initialise with e.g.
  12 % 		ET_serial = serial('COM1','BaudRate',9600,'Databits',8);
  13 %   	fopen(ET_serial);
  14 % 		If left undefined, we open a serial port with the above settings.
  15 % ET_params - struct with eye tracking parameters. All are optional.
  16 % 	npoints - (13) number of calibration points
  17 % 	calibarea - ([screenx screeny]) calibration area on screen
  18 % 	bgcolour - ([128 128 128]) background colour (RGB)
  19 % 	targcolour - ([255 255 255]) target colour (RGB)
  20 % 	targsize - (20) target height/width in pixels
  21 % 	acceptkey - ([spacebar]) key for forcing point acceptance
  22 % 	quitkey - ([escapekey]) key for aborting calibration
  23 % 		Use KbName('UnifyKeyNames') to get names for other keys
  24 %   waitforvalid - (1) wait for valid data during calibration
  25 %   randompointorder - (0) randomise point order during calibration
  26 %   autoaccept - (1) Auto-accept points after some fixation dur.
  27 %   checklevel - (2) Fussiness when accepting points (0-3). SMI recommends
  28 %       2 for every-day use. Drop if subject is problematic.
  29 % 13/4/2010 J Carlin, heavily indebted to Maarten van Caasteren's
  30 % VB script for E-Prime
  31 
  32 % TODO
  33 % Drift correction
  34 % ET_SAV - no problem!
  35 
  36 function [ready,points] = calibrateEyeTracker(window,ET_serial,ET_params)
  37 
  38 % If no serial object entered, try to set one up
  39 if ~exist('ET_serial','var') || isempty(ET_serial)
  40     ET_serial = serial('COM1','BaudRate',9600,'Databits',8);
  41     fopen(ET_serial);
  42 end
  43 
  44 % By default, calls time out in 10 SECONDS.
  45 % This is clearly unacceptably slow for our
  46 % purposes. Now 50 ms.
  47 set(ET_serial,'timeout',.1);
  48 % The downside is that Matlab spits out a lot of
  49 % warnings. Let's disable these...
  50 wstate=warning('off','MATLAB:serial:fgetl:unsuccessfulRead');
  51 
  52 
  53 
  54 
  55 % If you don't know what you want, we will fill this in with
  56 % defaults.
  57 if ~exist('ET_params','var')
  58 	ET_params = struct;
  59 end
  60 
  61 % Screen settings
  62 sc = Screen('Resolution',window);
  63 schw = [sc.width sc.height];
  64 
  65 KbName('UnifyKeyNames');
  66 
  67 % These are the default settings
  68 default_params = struct(...
  69 	'npoints',13,...
  70 	'calibarea',schw,... % Full screen size
  71 	'bgcolour',[128 128 128],...
  72 	'targcolour',[255 255 255],...
  73 	'targsize',20, ...
  74 	'acceptkey',KbName('space'), ...
  75 	'quitkey',KbName('escape'), ...
  76     'waitforvalid',1,...
  77     'randompointorder',0,...
  78     'autoaccept',1,...
  79     'checklevel',2 ...
  80 	);
  81 
  82 % Now put in defaults for whatever was left undefined
  83 fns = fieldnames(default_params);
  84 for fn = fns'
  85 	if ~isfield(ET_params,fn{1})
  86 		ET_params.(fn{1}) = default_params.(fn{1});
  87 	end
  88 end
  89 
  90 % Quick sanity check
  91 if ~sum(ET_params.npoints == [2,5,9,13])
  92     error('SMI eye trackers only support 2,5,9 or 13 point calibration')
  93 end
  94 
  95 % Start and stop calibration once. This somehow
  96 % solves a lot of problems
  97 fprintf(ET_serial,sprintf('ET_CAL %d',ET_params.npoints));
  98 fprintf(ET_serial,'ET_BRK');
  99 % Wait for various crap to go through
 100 w = 0;
 101 while w == 0
 102     if isempty(fgetl(ET_serial))
 103         w = 1;
 104     end
 105 end
 106 
 107 % Draw background
 108 Screen(window,'FillRect',ET_params.bgcolour);
 109 
 110 % Display settings for targets
 111 % Make a cross - studiously avoiding alpha blending here to
 112 % maximise compatibility (but you will need to im processing toolbox)
 113 % Settings
 114 cross_orgsize = 100;
 115 cross_linewidth = .05;
 116 % Build cross
 117 cs = round((cross_orgsize / 2) - (cross_orgsize * cross_linewidth));
 118 ce = round((cross_orgsize / 2) + (cross_orgsize * cross_linewidth));
 119 cr = zeros(cross_orgsize);
 120 cr(:,cs:ce) = 1;
 121 cr(cs:ce,:) = 1;
 122 % Resize - Since square, no point to bicubic interpolation
 123 cr_rs = imresize(cr,[ET_params.targsize ET_params.targsize],'nearest');
 124 % Make target uint8, colour
 125 rgb_t = ET_params.targcolour;
 126 cros = uint8(cat(3,cr_rs*rgb_t(1),cr_rs*rgb_t(2),cr_rs*rgb_t(3)));
 127 % Make an appropriately-coloured background
 128 rgb = ET_params.bgcolour;
 129 bg = uint8(ones(ET_params.targsize));
 130 bg_rgb =cat(3,bg*rgb(1),bg*rgb(2),bg*rgb(3));
 131 % Put background and target together
 132 target = bg_rgb;
 133 target(find(cros)) = cros(find(cros));
 134 % Draw texture
 135 targetbuf = Screen('MakeTexture',window,target);
 136 % Set up basic rect
 137 targetrect = [0 0 size(target,1) size(target,2)];
 138 
 139 % Various calibration settings
 140 fprintf(ET_serial,sprintf('ET_CPA %d %d',0,ET_params.waitforvalid));
 141 fprintf(ET_serial,sprintf('ET_CPA %d %d',1,ET_params.randompointorder));
 142 fprintf(ET_serial,sprintf('ET_CPA %d %d',2,ET_params.autoaccept));
 143 fprintf(ET_serial,sprintf('ET_LEV %d',ET_params.checklevel));
 144 
 145 % Set calibration area (ie screen res)
 146 fprintf(ET_serial,sprintf('ET_CSZ %d %d',schw(1),schw(2)));
 147 
 148 % These are the default ET points for a 13 point calibration on
 149 % a 1280x1024 screen. We can tweak this according to our needs...
 150 standardpoints = [640 512;
 151     64 51;
 152     1216 51;
 153     64 973;
 154     1216 973;
 155     64 512;
 156     640 51;
 157     1216 512;
 158     640 973;
 159     352 282;
 160     928 282;
 161     352 743;
 162     928 743];
 163 
 164 % Scale up/down to match calibration area
 165 scaledpoints = standardpoints .* repmat(ET_params.calibarea ...
 166     ./ [1280 1024],13,1);
 167 
 168 % If the calibration area doesn't match the screen res,
 169 % need to shift everything to centre
 170 shift = @(xy) round(xy + ([sc.width sc.height]/2) - (ET_params.calibarea/2));
 171 
 172 % Shift the calibration points to centre on the screen
 173 shiftedpoints = round(scaledpoints + repmat(schw/2,13,1) ...
 174     - repmat(ET_params.calibarea/2,13,1));
 175 
 176 % Set to appropriate npoints
 177 shiftedpoints = shiftedpoints(1:ET_params.npoints,:);
 178 
 179 % Send custom points to eye tracker
 180 for p = 1:length(shiftedpoints)
 181     fprintf(ET_serial,sprintf('ET_PNT %d %d %d',p, ...
 182         shiftedpoints(p,1),shiftedpoints(p,2)));
 183 end
 184 % Start calibration
 185 fprintf(ET_serial,sprintf('ET_CAL %d',ET_params.npoints));
 186 
 187 ready = 0;
 188 ntries = 0;
 189 
 190 % Point coordinates go here - just to validate
 191 points = zeros(ET_params.npoints,2);
 192 
 193 rc = 0;
 194 while ~ready
 195 	ntries = ntries+1;
 196 
 197 	% If no connection with serial, return anyway
 198 	if ntries > 5000
 199 		fprintf('Serial port communication failure!\n')
 200 		break
 201 	end
 202 
 203 	% Check for manual attempts to move things along
 204 	[keyisdown, secs, keyCode] = KbCheck;
 205 	if keyisdown
 206 		k = find(keyCode);
 207 		k = k(1);
 208 		% Force acceptance of current point
 209 		if k == ET_params.acceptkey
 210 			fprintf('Accepting point...\n')
 211             %WaitSecs(.2); % Time to let go of key...
 212             % Now stop execution until the key is released
 213             while KbCheck
 214                 WaitSecs(.01);
 215             end
 216             fprintf(ET_serial,'ET_ACC');
 217 		% Give up on calibration
 218 		elseif k == ET_params.quitkey
 219 			fprintf('Calibration attempt aborted!\n')
 220 			fprintf(ET_serial,'ET_BRK');
 221 			break
 222 		end
 223 	end
 224 
 225 	% Check if the eye tracker has something to say
 226     response = fgetl(ET_serial);
 227     
 228 	% What might the eye tracker have to say?
 229 	if ~isempty(response)
 230 		% Save each response - mainly for debugging
 231 		rc = rc+1;
 232         resplog{rc} = response;
 233 		% Split by spaces
 234 		command_etc = strread(regexprep(response,' ',' '),'%s');
 235 		command = command_etc{1};
 236 
 237 		%%% What we do next depends on the command we got:
 238 		% Calibration point change
 239         if strcmp(command,'ET_CHG')
 240             % Coordinates for point
 241             xy = points(str2num(command_etc{2}),:);
 242 			% Rect for point
 243 			pointrect = CenterRectOnPoint(targetrect,xy(1),xy(2));
 244 			% Draw into rect
 245 			Screen('DrawTexture',window,targetbuf,[],pointrect);
 246             Screen(window,'Flip');
 247             % Reset timeout counter
 248             ntries = 0;
 249 
 250             % Calibation point definition
 251         elseif strcmp(command,'ET_PNT')
 252             points(str2num(command_etc{2}),:) = ...
 253 				[str2num(command_etc{3}) str2num(command_etc{4})];
 254 
 255 		% Screen size verification
 256 		%elseif strcmp(command,'ET_CSZ')
 257 		% Actually, we don't want calibration area
 258 			% to match screen size.
 259 			% So arguments are X and Y size
 260 			%sc = Screen('Resolution',window);
 261 			%if str2num(command_etc{2}) ~= sc.width
 262 				%fprintf('Calibration failed - Screen width mismatch\n')
 263 				%break
 264 			%elseif str2num(command_etc{3}) ~= sc.height
 265 				%fprintf('Calibration failed - Screen height mismatch\n')
 266 				%break
 267 			%end
 268 
 269 		% Calibration finished
 270 		elseif strcmp(command,'ET_FIN')
 271 			ready = 1;
 272         
 273         % Various commands we don't care about
 274         elseif strcmp(command,'ET_REC') || ...
 275                 strcmp(command,'ET_CLR') || ...
 276                 strcmp(command,'ET_CAL') || ...
 277                 strcmp(command,'ET_CSZ') || ...
 278                 strcmp(command,'ET_ACC') || ...
 279                 strcmp(command,'ET_CPA') || ...
 280                 strcmp(command,'ET_LEV')
 281             continue
 282 
 283 		% Catch all
 284 		else
 285 			fprintf(sprintf(['Calibration failed - received unrecognised '...
 286 				'input: %s\n'],response));
 287             fprintf(ET_serial,'ET_BRK');
 288 			break % DEBUG
 289 		end % Resp interpretation
 290 	end % Resp check
 291 end % While
 292 
 293 % Clear the target texture from memory
 294 Screen('Close',targetbuf);
 295 % Return warning state to whatever it started as
 296 warning(wstate.state,wstate.identifier);

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2010-06-10 15:38:10, 14.5 KB) [[attachment:ET_tools_10.zip]]
  • [get | view] (2010-06-10 15:40:21, 9.5 KB) [[attachment:calibrateEyeTracker.m]]
  • [get | view] (2010-06-10 15:40:08, 6.2 KB) [[attachment:doDriftCorrection.m]]
  • [get | view] (2010-06-10 15:40:31, 8.3 KB) [[attachment:validateCalibration.m]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.