TRACKPixx Demo 6 – Creating a dynamic gaze follower with the TRACKPixx3

Note

This demo requires TRACKPixx Revision 16 or later. You can check for recent firmware updates at vpixx.com/whatsnew

This demo is a simple interactive gaze follower. Thirteen dots are displayed on a black background, with the current x,y positions of the left and right eye overlaid. Users can toggle the follower on and off by pressing “U” (on) or “H” (off) on the keyboard. The follower can be set to display the position tracked from a single frame by pressing “D”, or the mean position of the last 10 recorded frames by pressing “F”. Clicking on fixated locations with the mouse will show the error between recorded eye position and screen location.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
function TPxGazeFollow()
% TPxGazeFollow()
%
% This shows your current gaze position.
% Press L to load a calibration.
%
% Further Comments will be added on the next release.
%
% History:
%
% Dec 22, 2017  gm     Written

clear all;
close all;
dummy = 0;
screen = 2;
KbName('UnifyKeyNames');
[windowPtr, windowRect]=PsychImaging('OpenWindow', screen, 0);
cx = 1920/2;
cy = 1080/2;
dx = 400;
dy = 250;
xy = [  cx cy;...
        cx cy+dy;...
        cx+dx cy;...
        cx cy-dy;...
        cx-dx cy;...
        cx+dx cy+dy;...
        cx-dx cy+dy;...
        cx+dx cy-dy;...
        cx-dx cy-dy;...
        cx+dx/2 cy+dy/2;...
        cx-dx/2 cy+dy/2;...
        cx-dx/2 cy-dy/2;...
        cx+dx/2 cy-dy/2;];
    
xy = xy';
Datapixx('Open');
Datapixx('HideOverlay');
Datapixx('SetTPxAwake');
Datapixx('RegWrRd');
fileID = fopen('gaze_measure.csv', 'a');
fileID2 = fopen('gaze_raw_compare.csv', 'a');
fprintf(fileID, 'mouse X,mouse Y,right eye x,right eye y,left eye x,left eye y,error rigth x,error right y,error left x,error left y\n');
visible = 1;
mfilter = 0;
xAvgRight = [];
yAvgRight = [];
xAvgLeft = [];
yAvgLeft = [];
xErrRight = [];
yErrRight = [];
xErrLeft = [];
yErrLeft = [];
while (1)
    % 1- Get Eye position
    % 2- Put that in array
    % 3- Draw it on screen
    DrawFormattedText(windowPtr, 'Following your gaze now!\n Press L to load calibrations', 'center', 700, 255);
    Screen('DrawDots', windowPtr, [xy(1,:)' xy(2,:)']', [30]', [255 255 255]', [], 1);
    if ~dummy
        Datapixx('RegWrRd');
        [xScreenRight yScreenRight xScreenLeft yScreenLeft xRawRight yRawRight xRawLeft yRawLeft] = Datapixx('GetEyePosition');     
        
        
        array = [xScreenRight yScreenRight];
        array = Datapixx('ConvertCoordSysToCustom', array);
        xScreenRight = array(1);
        yScreenRight = array(2);
        array = [xScreenLeft yScreenLeft];
        array = Datapixx('ConvertCoordSysToCustom', array);
        xScreenLeft = array(1);
        yScreenLeft = array(2);

    else 
       [X,Y] = GetMouse();
    end
    
    if (size(xAvgRight,1) < 10)
        xAvgRight = [xScreenRight;xAvgRight];
        yAvgRight = [yScreenRight;yAvgRight];
        xAvgLeft = [xScreenLeft;xAvgLeft];
        yAvgLeft = [yScreenLeft;yAvgLeft];
    else
        xAvgRight = circshift(xAvgRight,1);
        xAvgRight(1) = xScreenRight;
        yAvgRight = circshift(yAvgRight,1);
        yAvgRight(1) = yScreenRight;
        xAvgLeft = circshift(xAvgLeft,1);
        xAvgLeft(1) = xScreenLeft;
        yAvgLeft = circshift(yAvgLeft,1);
        yAvgLeft(1) = yScreenLeft;
    end
    
    if ~dummy
        if visible
            if mfilter
                Screen('DrawDots', windowPtr, [mean(xAvgRight); mean(yAvgRight)], [15]', [255 0 0]', [], 1);
                Screen('DrawDots', windowPtr, [mean(xAvgLeft); mean(yAvgLeft)], [15]', [0 0 255]', [], 1);
            else
                Screen('DrawDots', windowPtr, [xScreenRight; yScreenRight], [15]', [255 0 0]', [], 1);
                Screen('DrawDots', windowPtr, [xScreenLeft; yScreenLeft], [15]', [0 0 255]', [], 1);
            end
        end
    else
        Screen('DrawDots', windowPtr, [X; Y], [15]', [255 0 255]', [], 1);
        
    end
    
    
    [X, Y, buttons] = GetMouse(windowPtr);
    if buttons(1)
        if reset_error
            xErrRight = [];
            yErrRight = [];
            xErrLeft = [];
            yErrLeft = [];
            reset_error = 0;
        end
        fprintf(fileID, '%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n',...
        X, Y, xScreenRight, yScreenRight, xScreenLeft, yScreenLeft,...
        (X - xScreenRight), (Y - yScreenRight), (X - xScreenLeft), (Y - yScreenLeft));
        fprintf(fileID2, '%f,%f,%f,%f,%f,%f,\n', X, Y, xRawRight, yRawRight, xRawLeft, yRawLeft);
        if (size(xErrRight,1) < 20)
            xErrRight = [X - xScreenRight;xErrRight];
            yErrRight = [Y - yScreenRight;yErrRight];
            xErrLeft = [X - xScreenLeft;xErrLeft];
            yErrLeft = [Y - yScreenLeft;yErrLeft];
        else
            xErrRight = circshift(xErrRight,1);
            xErrRight(1) = X - xScreenRight;
            yErrRight = circshift(yErrRight,1);
            yErrRight(1) = Y - yScreenRight;
            xErrLeft = circshift(xErrLeft,1);
            xErrLeft(1) = X - xScreenLeft;
            yErrLeft = circshift(yErrLeft,1);
            yErrLeft(1) = Y - yScreenLeft;
        end
        Screen('TextSize', windowPtr, 16);
        Screen('Preference', 'TextAlphaBlending', 1);
        Screen('TextBackgroundColor', windowPtr, [250 248 200]);
        DrawFormattedText(windowPtr, sprintf('    %f  |  %f\n    %f  |  %f', mean(xErrRight),mean(yErrRight),mean(xErrLeft),mean(yErrLeft)), 'right', [], 10);
        Screen('Preference', 'TextAlphaBlending', 0);
    elseif buttons(3)
        Screen('TextSize', windowPtr, 16);
        Screen('Preference', 'TextAlphaBlending', 1);
        Screen('DrawText', windowPtr, sprintf('    %d  |  %d', X,Y), X, Y, 10, [250 248 200]);
        Screen('Preference', 'TextAlphaBlending', 0);
    else
        reset_error = 1;
    end
    
    Screen('TextSize', windowPtr, 14);
    Screen('Preference', 'TextAlphaBlending', 1);
    Screen('TextBackgroundColor', windowPtr, [250 248 200]);
    if (size(xErrRight,1) > 10)
        newX = 10;
        newY = 920;
        for i=1:10
            [newX,newY] = DrawFormattedText(windowPtr, sprintf('  %7.2f  |  %7.2f  |  %7.2f  |  %7.2f\n', xErrRight(i), yErrRight(i), xErrLeft(i), yErrLeft(i)), newX, newY, 5);
        end
    end
    Screen('TextBackgroundColor', windowPtr, [0 0 0 0]);
    Screen('Preference', 'TextAlphaBlending', 0);
    Screen('TextSize', windowPtr, 24);
    
    Screen('Flip', windowPtr);         
    [pressed dum keycode] = KbCheck;
    if pressed
        if keycode(KbName('escape'))
            Datapixx('ShowOverlay');
            Datapixx('SetAsleepPictureRequest');
            Datapixx('RegWrRd');
            Screen('CloseAll');
            Datapixx('Close');
%            fclose(fileID);
%            fclose(fileID2);
            break;
        end
        if keycode(KbName('h'))
            visible = 0;
        end
        if keycode(KbName('u'))
            visible = 1;
        end
        if keycode(KbName('f'))
            mfilter = 1;
        end
        if keycode(KbName('d'))
            mfilter = 0;
        end
        if keycode(KbName('l'))
            Datapixx('LoadCalibration');
        end

    end

end

fclose(fileID);
fclose(fileID2);

end