June 22, 2011 Notes: This function codes the eye track sequence according to the fixations It checks to make sure that the fixation is not immediately at start of sequence (from fixation slide) and eliminates this fixation if necessary We identify fixations using the IDT algorithm syntax: [ fixStruct ] = codeFixations( eyeTrack, windowSize, viewThreshold ) Inputs: eyeTrack: vector of complex (x+i*y) coordinates. -1-i1 to identify missing data. Data should be scaled according to the image dimensions. See function 'scaleEyeTrack'. windowSize: integer of consecutive frames which should be within a threshold of distance from one another (to be considered a fixation) , ( 6 is good value for 60 Hz) viewThreshold: euclidean distance within which eye positions are considered part of same fixation, 15 is a good number for 30 px diameter Outputs: fixStruct, having fixStruct.fixDurVector: vector of (fx1), for duration of fications fixStruct.fixPosVector: in format [ x x x ... x; y y y ... y] fixStruct.fixationVector: (N by1) vector having 0 where no fixations, then 1, 2 ,3, and so on for the fixations in the sequence
0001 % June 22, 2011 0002 % Notes: This function codes the eye track sequence according to the fixations 0003 % It checks to make sure that the fixation is not immediately at start of 0004 % sequence (from fixation slide) and eliminates this fixation if necessary 0005 % We identify fixations using the IDT algorithm 0006 % 0007 % syntax: [ fixStruct ] = codeFixations( eyeTrack, windowSize, viewThreshold ) 0008 % 0009 % Inputs: 0010 % eyeTrack: vector of complex (x+i*y) coordinates. -1-i1 to identify 0011 % missing data. Data should be scaled according to the image dimensions. 0012 % See function 'scaleEyeTrack'. 0013 % windowSize: integer of consecutive frames which should be within a 0014 % threshold of distance from one another (to be considered a 0015 % fixation) , ( 6 is good value for 60 Hz) 0016 % viewThreshold: euclidean distance within which eye positions are 0017 % considered part of same fixation, 15 is a good number for 30 px 0018 % diameter 0019 % 0020 % Outputs: 0021 % fixStruct, having 0022 % fixStruct.fixDurVector: vector of (fx1), for duration of fications 0023 % fixStruct.fixPosVector: in format [ x x x ... x; 0024 % y y y ... y] 0025 % fixStruct.fixationVector: (N by1) vector having 0 where no fixations, then 1, 2 ,3, 0026 % and so on for the fixations in the sequence 0027 0028 0029 function [ fixStruct ] = codeFixationsDist( eyeTrack, windowSize, viewThreshold ) 0030 0031 if nargin < 2 0032 windowSize = 6; 0033 end 0034 if nargin < 3 0035 viewThreshold = 15; 0036 end 0037 0038 numSamples = length( eyeTrack); 0039 fixationVector = zeros(numSamples ,1); 0040 fixDurVector = zeros(numSamples ,1); 0041 fixPosVector = zeros( 2, numSamples ); 0042 startPos = 1; 0043 0044 fixIndex = 1; fixLength = 0; k1 = 1; 0045 while ( fixIndex~=-1 ) && (startPos < numSamples ) 0046 % [k1 fixIndex fixLength] 0047 [fixIndex fixPosition fixLength] = findFixation( eyeTrack, windowSize, viewThreshold, startPos ); 0048 startPos = fixIndex + fixLength; 0049 if fixIndex~=-1 0050 fixationVector( fixIndex:(fixIndex+fixLength-1)) = k1; 0051 fixPosVector(:,k1 ) = fixPosition(:); 0052 fixDurVector(k1,1) = fixLength; 0053 k1 = k1+1; 0054 end 0055 0056 end 0057 fixPosVector(:,k1:end) = []; %clean up unused parts 0058 fixDurVector( k1+1:end) = []; 0059 0060 0061 % eliminate first fixation if it coincides with the 0062 % fixation slide ( start of sequence) 0063 if fixationVector(1) == 1 0064 fixationVector( fixationVector==1) = 0; 0065 fixationVector( fixationVector ~= 0 ) = fixationVector( fixationVector ~= 0 )-1; 0066 fixPosVector( :,1) = []; 0067 fixDurVector(1) = []; 0068 end 0069 0070 fixStruct.fixPosVector = fixPosVector; 0071 fixStruct.fixDurVector = fixDurVector; 0072 fixStruct.fixationVector = fixationVector; 0073 0074 end 0075 %--------------------------------------------------- 0076 0077 % Outputs: 0078 % fixIndex: integer index for beginning of fixation. -1 if none found 0079 % fixPosition: vector of the fixation position (mean of the window) -1 if none found 0080 % fixLength: : integer specifying total length of fixation, -1 if none found 0081 0082 function [fixIndex, fixPosition, fixLength] = findFixation( eyeTrack, windowSize, viewThreshold, startPos ) 0083 0084 %-------------------------------------------------------- 0085 %--------------- initialize ----------------------- 0086 0087 minTracksToConsider = floor( 2/3 * windowSize ); % integer, specifying minimum samples 0088 % tracked when calculating fixation 0089 eyeTrack = [ real( eyeTrack(:)) imag(eyeTrack(:)) ]'; % in [ x x ... x; y y ... y ] 0090 maxPos = size( eyeTrack,2) - windowSize+1; 0091 fixPosition = -1; fixLength = -1; 0092 fixIndex = -1; % will stay -1 if none found 0093 0094 % specify search start position 0095 if nargin < 4 || isempty( startPos ) 0096 i1 = 0; 0097 else 0098 i1 = startPos-1; 0099 end 0100 0101 %-------------------------------------------------------- 0102 %-----------find fixation position -------------------------- 0103 while (i1 < maxPos) && (fixIndex==-1) 0104 %increment, until start with not missing if necessary 0105 i1 = i1+1; 0106 while (i1 < maxPos) && (eyeTrack(1,i1)==-1) 0107 i1 = i1+1; 0108 end 0109 0110 % select window of windowSize samples, expand if 0111 % too much missing data or if last sample is missing 0112 i2 = 0; %for expanding window 0113 window = eyeTrack(:, i1:(i1+windowSize-1)); 0114 missIdx = find( window(1,:) == -1 ); 0115 window( :, missIdx ) = []; 0116 0117 while ( (size( window,2) < minTracksToConsider ) || ... 0118 (eyeTrack(1, i1+windowSize-1+i2)==-1) ) ... 0119 && (i1+i2)<maxPos % do not expand too far 0120 i2 = i2+1; 0121 window = eyeTrack(:, i1:(i1+windowSize-1+i2)); 0122 missIdx = find( window(1,:) == -1 ); 0123 window( :, missIdx ) = []; 0124 end 0125 0126 % determine if fixation based on viewThreshold 0127 if size( window,2) >= minTracksToConsider %handle missing data 0128 dist = calc2Dist( mean(window,2), window); %euclidean distance from mean to all 0129 if max( dist ) < viewThreshold 0130 fixIndex = i1; %store fixation position 0131 fixPosition = mean(window,2); 0132 end 0133 end 0134 0135 end 0136 0137 %--------------------------------------------------------- 0138 %-----------find fixation duration ( if fixation found)------------ 0139 0140 if fixIndex ~= -1 0141 0142 % initialize for keeping track/convenience 0143 eyeTrack(:,1:fixIndex-1) = []; 0144 missingIndices = 1:size(eyeTrack,2); 0145 knownIndices = missingIndices( eyeTrack(1,:)~=-1); 0146 missingIndices( eyeTrack(1,:)~=-1) = []; 0147 eyeTrack( :, missingIndices) = []; 0148 0149 % find furthest index within threshold distance 0150 dist = calc2Dist( fixPosition, eyeTrack); 0151 i1 =1; 0152 while (i1<=length(dist)) && (dist(i1) < viewThreshold) 0153 i1 = i1+1; 0154 end; 0155 fixLength = knownIndices(i1-1); 0156 end 0157 end