Attachment 'validateCalibration.m'
Download 1 % Calibration routine for SMI IViewX eyetracker and Psychtoolbox,
2 % using the serial port for communication. This function validates
3 % a previous calibration. It's generally a good idea to pass the
4 % exact same params struct here as you provided to calibrateEyeTracker.
5 % NB, MeanDevXY is in deg visual angle, so is completely dependent on
6 % you appropriately configuring IViewX settings to match your setup. The
7 % other values are in pixels.
8 % Currently only reports validation parameters for the left eye if tracking
9 % binocular. As near as I can tell, this information is never transmitted,
10 % so little can be done at this end.
11 % Syntax:
12 % [success,RMSdev,RMSdevdist,MeanDevXY] = validateCalibration(window,ET_serial,ET_params)
13 % Inputs (all params are optional):
14 % window - Psychtoolbox screen handle
15 % ET_serial - Opened serial port object for scanner.
16 % ET_params - struct with eye tracking parameters. All are optional.
17 % npoints - (13) calibration points. DO NOT change between calib and
18 % validation.
19 % bgcolour - ([128 128 128]) background colour (RGB)
20 % targcolour - ([255 255 255]) target colour (RGB)
21 % targsize - (20) target height/width in pixels
22 % acceptkey - ([spacebar]) key for forcing point acceptance
23 % quitkey - ([escapekey]) key for aborting calibration
24 % Use KbName('UnifyKeyNames') to get names for other keys
25 % 13/4/2010 J Carlin
26 function [ready,RMSdev, RMSdevdist, MeanDevXY] = validateCalibration(window,ET_serial,ET_params)
27
28 % If no serial object entered, crash out
29 if ~exist('ET_serial','var') || isempty(ET_serial)
30 error('ET_serial must be defined! See calibrateEyeTracker')
31 end
32
33 % By default, calls time out in 10 SECONDS.
34 % This is clearly unacceptably slow for our
35 % purposes. Now 100 ms.
36 set(ET_serial,'timeout',.1);
37 % The downside is that Matlab spits out a lot of
38 % warnings. Let's disable these...
39 wstate=warning('off','MATLAB:serial:fgetl:unsuccessfulRead');
40
41 % If you don't know what you want, we will fill this in with
42 % defaults.
43 if ~exist('ET_params','var')
44 ET_params = struct;
45 end
46
47 % Screen settings
48 sc = Screen('Resolution',window);
49 schw = [sc.width sc.height];
50
51 KbName('UnifyKeyNames');
52
53 % These are the default settings
54 default_params = struct(...
55 'bgcolour',[128 128 128],...
56 'targcolour',[255 255 255],...
57 'targsize',20, ...
58 'npoints',13, ...
59 'acceptkey',KbName('space'), ...
60 'quitkey',KbName('escape') ...
61 );
62
63 % Now put in defaults for whatever was left undefined
64 fns = fieldnames(default_params);
65 for fn = fns'
66 if ~isfield(ET_params,fn{1})
67 ET_params.(fn{1}) = default_params.(fn{1});
68 end
69 end
70
71 % Draw background
72 Screen(window,'FillRect',ET_params.bgcolour);
73
74 % Display settings for targets
75 % Make a cross - studiously avoiding alpha blending here to
76 % maximise compatibility (but you will need to im processing toolbox)
77 % Settings
78 cross_orgsize = 100;
79 cross_linewidth = .05;
80 % Build cross
81 cs = round((cross_orgsize / 2) - (cross_orgsize * cross_linewidth));
82 ce = round((cross_orgsize / 2) + (cross_orgsize * cross_linewidth));
83 cr = zeros(cross_orgsize);
84 cr(:,cs:ce) = 1;
85 cr(cs:ce,:) = 1;
86 % Resize - Since square, no point to bicubic interpolation
87 cr_rs = imresize(cr,[ET_params.targsize ET_params.targsize],'nearest');
88 % Make target uint8, colour
89 rgb_t = ET_params.targcolour;
90 cros = uint8(cat(3,cr_rs*rgb_t(1),cr_rs*rgb_t(2),cr_rs*rgb_t(3)));
91 % Make an appropriately-coloured background
92 rgb = ET_params.bgcolour;
93 bg = uint8(ones(ET_params.targsize));
94 bg_rgb =cat(3,bg*rgb(1),bg*rgb(2),bg*rgb(3));
95 % Put background and target together
96 target = bg_rgb;
97 target(find(cros)) = cros(find(cros));
98 % Draw texture
99 targetbuf = Screen('MakeTexture',window,target);
100 % Set up basic rect
101 targetrect = [0 0 size(target,1) size(target,2)];
102
103 % Start validation
104 fprintf(ET_serial,sprintf('ET_VLS'));
105 ready = 0;
106 readyonce = 0; % Extra check to catch second eye in bino mode
107 ntries = 0;
108 points = zeros(ET_params.npoints,2);
109
110 % Initialise output vars for graceful errors
111 RMSdev = [];
112 RMSdevdist = [];
113 MeanDevXY = [];
114
115 rc = 0;
116 while ~ready
117 ntries = ntries+1;
118
119 % If no connection with serial, return anyway
120 if ntries > 500
121 fprintf('Serial port communication failure!\n')
122 break
123 end
124
125 % Check for manual attempts to move things along
126 [keyisdown, secs, keyCode] = KbCheck;
127 if keyisdown
128 k = find(keyCode);
129 k = k(1);
130 % Force acceptance of current point
131 if k == ET_params.acceptkey
132 fprintf('Accepting point...\n')
133 %WaitSecs(.2); % Time to let go of key...
134 % Now stop execution until the key is released
135 while KbCheck
136 WaitSecs(.01);
137 end
138 fprintf(ET_serial,'ET_ACC');
139 % Give up on calibration
140 elseif k == ET_params.quitkey
141 fprintf('Calibration attempt aborted!\n')
142 fprintf(ET_serial,'ET_BRK');
143 break
144 end
145 end
146
147 % Ensure a second run through after receiving the first
148 % ET_VLS return, so that we catch the second eye too.
149 if readyonce
150 ready = 1;
151 end
152
153 % Check if the eye tracker has something to say
154 response = fgetl(ET_serial);
155
156 % What might the eye tracker have to say?
157 if ~isempty(response)
158 % Save each response - mainly for debugging
159 rc = rc+1;
160 resplog{rc} = response;
161 % Split by spaces
162 command_etc = strread(regexprep(response,' ',' '),'%s');
163 command = command_etc{1};
164
165 %%% What we do next depends on the command we got:
166 % Calibration point change
167 if strcmp(command,'ET_CHG')
168 % Coordinates for point
169 xy = points(str2num(command_etc{2}),:);
170 % Rect for point
171 pointrect = CenterRectOnPoint(targetrect,xy(1),xy(2));
172 % Draw into rect
173 Screen('DrawTexture',window,targetbuf,[],pointrect);
174 Screen(window,'Flip');
175 % Reset timeout counter
176 ntries = 0;
177
178 % Calibation point definition
179 elseif strcmp(command,'ET_PNT')
180 points(str2num(command_etc{2}),:) = ...
181 [str2num(command_etc{3}) str2num(command_etc{4})];
182
183 % Screen size verification
184 %elseif strcmp(command,'ET_CSZ')
185 % Actually, we don't want calibration area
186 % to match screen size.
187 % So arguments are X and Y size
188 %sc = Screen('Resolution',window);
189 %if str2num(command_etc{2}) ~= sc.width
190 %fprintf('Calibration failed - Screen width mismatch\n')
191 %break
192 %elseif str2num(command_etc{3}) ~= sc.height
193 %fprintf('Calibration failed - Screen height mismatch\n')
194 %break
195 %end
196
197 % Validation finished
198 % The twist here is that ET_VLS returns twice if
199 % in binocular mode... So need to go through a last
200 % check after finishing this.
201 elseif strcmp(command,'ET_VLS')
202 % Command_etc should now contain various numbers
203 values = str2num(char(command_etc(3:5)))';
204 % SMI for some reason insists on including a degree
205 % symbol for the last 2, which complicates things...
206 values(end+1) = str2num(command_etc{6}(1:end-1));
207 values(end+1) = str2num(command_etc{7}(1:end-1));
208
209 if ~readyonce
210 RMSdev = values(1:2);
211 RMSdevdist = values(3);
212 MeanDevXY = values(4:5);
213 else % Right eye
214 RMSdev(2,:) = values(1:2);
215 RMSdevdist(2,:) = values(3);
216 MeanDevXY(2,:) = values(4:5);
217 end
218 readyonce = 1;
219
220
221 % Various commands we don't care about
222 elseif strcmp(command,'ET_REC') || ...
223 strcmp(command,'ET_CLR') || ...
224 strcmp(command,'ET_CAL') || ...
225 strcmp(command,'ET_CSZ') || ...
226 strcmp(command,'ET_ACC') || ...
227 strcmp(command,'ET_CPA') || ...
228 strcmp(command,'ET_FIN') || ...
229 strcmp(command,'ET_LEV')
230 continue
231
232 % Catch all
233 else
234 fprintf(sprintf(['Validation failed - received unrecognised '...
235 'input: %s\n'],response));
236 fprintf(ET_serial,'ET_BRK');
237 break % DEBUG
238 end % Resp interpretation
239 end % Resp check
240 end % While
241
242 % Clear the target texture from memory
243 Screen('Close',targetbuf);
244 % Return warning state to whatever it started as
245 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.You are not allowed to attach a file to this page.