Tobiiのアイトラッカーを利用

Tobiiのアイトラッカー(X2-60およびX2-30)から注視点データを取得して、注視点の位置をリアルタイムに描画するサンプルプログラムをご紹介します。

このプログラムを動作させるには、Tobii Analytics SDK 3.0が必要です。(2014年3月現在、フリーでダウンロードできます)

SDKの中に、Matlabのサンプルプログラムが入っているのですが、このプログラムではPTBは利用されていません。(Matlabの標準関数のみが使われています)

今回、注視点の描画にPTBの関数を用いるプログラムを作成しましたので公開いたします。

基本的にはSDKのサンプルを元にしています。

ポイントとしては、tetio_startTracking を呼び出したあとは、注視点のデータがどんどんアイトラッカーに蓄積されますので、tetio_readGazeDataですぐにデータを取得する必要があります。

例えば、tetio_readGazeDataを呼び出して、次のtetio_readGazeDataを呼び出すのに1秒かかる場合には、サンプリングレートが30Hzの場合(X2-30)、約30個のデータが蓄積されています。

tetio_readGazeDataは1個の注視点データを返すわけではなく、その時点でアイトラッカーに蓄積されているすべてのデータを返してくるので注意してください。

なお、X2-60とX2-30では主にサンプリングレートが異なるのですが、実験の目的によっては30Hzでも十分かもしれません。プログラム自体はどちらでも動作します。

用途に応じて購入をご検討ください。

以下が、サンプルプログラムです。

% TobiiのX2-60 (X2-30) で動作確認をしています。
% 注視点の位置をリアルタイムで計測して画面上に表示します。
% function にすると適切に動作しないので注意してください。
%clc 
clear all
close all
addpath('functions');
addpath('../tetio');  
%-----------------------
strFontSize = 25; % string font size
bgColor = [200 200 200]; % back ground color
%-----------------------------------------
% 一度読み込んでおく必要がある関数たち
GetSecs;
WaitSecs(1);
%rand('state', sum(100*clock)); % 古いMatlab
rng('shuffle') % 新しいMatlab
% *************************************************************************
%
% Initialization and connection to the Tobii Eye-tracker
% SDK (3.0.83) のデモをそのまま使っています。
%
% *************************************************************************
 
disp('Initializing tetio...');
tetio_init();
% Set to tracker ID to the product ID of the tracker you want to connect to.
%  所有しているアイトラッカーのIDに書き換える必要があります。
trackerId = 'NOTSET';
%   FUNCTION "SEARCH FOR TRACKERS" IF NOTSET
%   trackerIdがセットされていないときに、候補を表示します。
if (strcmp(trackerId, 'NOTSET'))

warning('tetio_matlab:EyeTracking', 'Variable trackerId has not been set.');

disp('Browsing for trackers...');

trackerinfo = tetio_getTrackers();

for i = 1:size(trackerinfo,2)

disp(trackerinfo(i).ProductId);

end

tetio_cleanUp();

error('Error: the variable trackerId has not been set. Edit the EyeTrackingSample.m script and replace "NOTSET" with your tracker id (should be in the list above) before running this script again.');

end
fprintf('Connecting to tracker "%s"...\n', trackerId);
tetio_connectTracker(trackerId)


% X2-60では60Hzに、X2-30では30Hzになります。
currentFrameRate = tetio_getFrameRate;
fprintf('Frame rate: %d Hz.\n', currentFrameRate);
% *************************************************************************
%
% Calibration of a participant
%
% *************************************************************************
SetCalibParams; 
disp('Starting TrackStatus');
% Display the track status window showing the participant's eyes (to position the participant).
TrackStatus; % Track status window will stay open until user key press.
disp('TrackStatus stopped');
disp('Starting Calibration workflow');
% Perform calibration
HandleCalibWorkflow(Calib);
disp('Calibration workflow stopped');
% *************************************************************************
%
% Display a stimulus 
%
% For the demo this simply reads and display an image.
% Any method for generation and display of stimuli availble to Matlab could
% be inserted here, for example using Psychtoolbox or Cogent. 
%
% *************************************************************************
close all;
ListenChar(2);
AssertOpenGL;
KbName('UnifyKeyNames');
myKeyCheck; % 必要に応じて
HideCursor;
try
    screenNumber=max(Screen('Screens'));
    %ウィンドウでの呈示
    %[windowPtr, windowRect]=Screen('OpenWindow', screenNumber, [255 255 255], [100, 200, 700, 600]);
    %フルスクリーンでの呈示
    [windowPtr, windowRect]=Screen('OpenWindow', screenNumber, bgColor);
        
    %色
    strColor = BlackIndex(windowPtr);
  
    %画面の中央の座標
    [centerX, centerY] = RectCenter(windowRect); 
    
    Screen('TextFont', windowPtr, 'Courier New');    
    Screen('TextSize', windowPtr, strFontSize);
    DrawFormattedText(windowPtr, '注視点を表示します。スペースキーで終了です。', 'center', 'center',  strColor);
    Screen('Flip', windowPtr);    
    WaitSecs(2);
    % キャリブレーション結果の確認
    dist1 = 300; % ポイント間隔(水平)
    dist2 = 200; % ポイント間隔(垂直)
    tmpRadius1 = 30;
    tmpRadius2 = 10;
    
    tetio_startTracking; %計測開始
    % スペースキーを押すまで注視点を表示します。
    while 1
        [ keyIsDown, seconds, keyCode ] = KbCheck;
        if keyIsDown 
    
            if keyCode(KbName('space'))     
                break;
            end;
            while KbCheck; end;
        end;
        
        % 9つの参照点の描画
        for j = 1:3
            for i = 1:3
                cx = centerX - dist1 + dist1*(i-1);
                cy = centerY - dist2 + dist2*(j-1);
                Screen('FillOval', windowPtr, [255 0 0], [cx-tmpRadius2, cy-tmpRadius2, cx+tmpRadius2, cy+tmpRadius2]);                
            end;
        end;
        
        % 注視点情報を取得(同時に複数の注視点データを取得する可能性があることに注意)
        % つまりsize(lefteye, 1)=1とは限らない。
        [lefteye, righteye, timestamp, trigSignal] = tetio_readGazeData;
        if ~isempty(lefteye)
    
            % 左右眼の平均値を取る。
            % 左眼、右目、それぞれのデータの7列目と8列目を使用。データの詳細はSDKのマニュアルの
            % GazeDataArray および EyeArrayを参照のこと。
            gaze.x = mean([lefteye(:,7), righteye(:,7)], 2); 
            gaze.y = mean([lefteye(:,8), righteye(:,8)], 2);
                
            tmpx = transpose(gaze.x) .* windowRect(3); % gazeのデータは正規化されているので座標(ピクセル)に変換。
            tmpy = transpose(gaze.y) .* windowRect(4);
            Screen('FrameOval', windowPtr, [0, 0, 0], [tmpx - tmpRadius1; tmpy - tmpRadius1; tmpx + tmpRadius1; tmpy + tmpRadius1]);
                        
            Screen('Flip', windowPtr);
        end;
        
    end;
    tetio_stopTracking; % 注視点計測停止
    DrawFormattedText(windowPtr, 'しばらくお待ちください。', 'center', 'center',  strColor);
    Screen('Flip', windowPtr);    
    
    % tetio_startTracking を再び呼び出したあと、tetio_readGazeData を呼び出すまでにラグがあると
    % 注視点データがアイトラッカーにストックされているので注意。
    % 例えば次のように確認できる。
    tetio_startTracking;
    WaitSecs(3);
    [lefteye, righteye, timestamp, trigSignal] = tetio_readGazeData;
    CheckThisNumber = size(lefteye, 1) % 1ではないはずです。
    tetio_stopTracking;
        
    %終了処理
    tetio_disconnectTracker; 
    tetio_cleanUp;
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
 
    
catch
    
    %終了処理
    tetio_disconnectTracker; 
    tetio_cleanUp;
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
    psychrethrow(psychlasterror);
    
end;