extract_sp.m 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. function [ result ] = extract_sp(data, metadata, attributes, labelVec, typeOfMotion, prelInt, t_min, eta_D, eta_CD, eta_PD, eta_maxFix, eta_minSmp, phi)
  2. %Classifies intervals as fixations or SP
  3. % @data of gaze recordings
  4. % @metadata of the ARFF data
  5. % @attributes describing data
  6. % @labelVec label vector to consider for intervals with value 0 (unassigned)
  7. % @typeOfMotion gets the values 1 -> eye FOV, 2 -> eye+head
  8. % @prelInt preliminary intervals for labelVec
  9. %
  10. % @t_min is the threshold for minimal fixation duration us, default is 40000us
  11. % @eta_D is the threshold for p_D (dispersion), default is 0.45
  12. % @eta_CD is the threshold for consistency of direction, default is 0.5
  13. % @eta_PD is the threshold for position displacement, default is 0.2
  14. % @eta_maxFix is the threshold for spacial range, default is 1.9 deg
  15. % @eta_minSmp is the threshold for merged segments spacial range, default is
  16. % 1.7 deg
  17. % @phi is the threshold for mean direction difference, default is 45 degrees
  18. %
  19. % @result is the same length as labelVec with fixations and sp labelled
  20. if nargin < 12
  21. phi = 180 / 4;
  22. end
  23. if nargin < 11
  24. eta_minSmp = 1.7;
  25. end
  26. if nargin < 10
  27. eta_maxFix = 1.9;
  28. end
  29. if nargin < 9
  30. eta_PD = 0.2;
  31. end
  32. if nargin < 8
  33. eta_CD = 0.5;
  34. end
  35. if nargin < 7
  36. eta_D = 0.45;
  37. end
  38. if nargin < 6
  39. t_min = 40000;
  40. end
  41. [eyeFovVec, eyeHeadVec, headVec] = GetCartVectors(data, metadata, attributes);
  42. if (typeOfMotion == 1)
  43. vecList = eyeFovVec;
  44. elseif (typeOfMotion == 2)
  45. vecList = eyeHeadVec;
  46. elseif (typeOfMotion == 3)
  47. vecList = headVec;
  48. else
  49. error('Uknown motion');
  50. end
  51. c_fix = 1;
  52. c_sp = 3;
  53. % convert minSp,maxFix to pixels
  54. eta_minSmp = eta_minSmp;
  55. eta_maxFix = eta_maxFix;
  56. % find position of attributes
  57. timeIndex = GetAttPositionArff(attributes, 'time');
  58. moveId = 0; % unassigned
  59. index = GetIntervalsIndex(labelVec, moveId);
  60. segment_class = zeros(size(prelInt,1),1); % 0 is unsure, 1 is SP, -1 if fixation
  61. segment_parameters = zeros(size(prelInt, 1), 7); % 4 criteria and mean direction (x,y,z)
  62. segment_intersacc_index = zeros(size(prelInt,1),1);
  63. segm_i = 1;
  64. for i = 1:size(index, 1)
  65. start_ind = index(i,1);
  66. end_ind = index(i,2);
  67. while segm_i < size(prelInt, 1)
  68. segm_begin = prelInt(segm_i,1);
  69. segm_end = prelInt(segm_i,2);
  70. if segm_begin < start_ind || segm_end > end_ind
  71. break;
  72. end
  73. if segm_begin == segm_end
  74. segment_class(segm_i) = -1; % segment of 0 length, let's label it as a fixation
  75. segm_i = segm_i + 1;
  76. continue
  77. end
  78. if (data(segm_end, timeIndex) - data(segm_begin, timeIndex)) < t_min
  79. segment_class(segm_i) = -1; % too short segment, let it be a fixation
  80. segm_i = segm_i + 1;
  81. continue
  82. elseif (segm_end-segm_begin < 3) %% added by ioannis for jumps in time
  83. segment_class(segm_i) = -1; % too short segment, let it be a fixation
  84. segm_i = segm_i + 1;
  85. continue
  86. end
  87. segment_intersacc_index(segm_i) = i;
  88. part = vecList(segm_begin:segm_end,:);
  89. [coeff, transformed, d_pc] = pca(part);
  90. maxDisp = GetMaxDispersion(part);
  91. d_ed = GetDispersion(part(end, :), part(1, :));
  92. shifts = zeros(size(part,1)-1,1);
  93. for shiftInd=1:size(shifts,1)
  94. shifts(shiftInd) = GetDispersion(part(shiftInd,:), part(shiftInd+1,:));
  95. end
  96. traj_len = sum(shifts);
  97. sp_range = GetMaxDispersion(part);
  98. dirs = diff(part); % vectors to the direction of gaze
  99. dirsTmp = dirs;
  100. % normalize all direction vectors in order to have same contribution to mean vector
  101. for dirInd=1:size(dirs,1)
  102. if (sum(dirs(dirInd,:)) == 0)
  103. if (dirInd > 1)
  104. dirs(dirInd,:) = dirs(dirInd-1,:);
  105. else
  106. dirs(dirInd,:) = [1 0 0];
  107. end
  108. end
  109. dirs(dirInd,:) = dirs(dirInd,:) / norm(dirs(dirInd,:));
  110. end
  111. mean_dir = sum(dirs,1) / size(dirs,1);
  112. p_D = d_pc(2) / d_pc(1);
  113. p_CD = d_ed / maxDisp;
  114. p_PD = d_ed / traj_len;
  115. p_R = sp_range;
  116. duration = data(segm_end,timeIndex) - data(segm_begin,timeIndex);
  117. l_eta_maxFix = eta_maxFix * (1 + 0.05 * log2(duration)); % increase/decrease spread based on duration of segment
  118. %criteria = [-p_D, p_CD, p_PD, p_R] > [-eta_D, eta_CD, eta_PD, eta_maxFix];
  119. criteria = [-p_D, p_CD, p_PD, p_R] > [-eta_D, eta_CD, eta_PD, l_eta_maxFix];
  120. segment_parameters(segm_i, 1:4) = criteria;
  121. segment_parameters(segm_i, 5:7) = mean_dir;
  122. if sum(criteria) == 4
  123. segment_class(segm_i) = 1;
  124. elseif sum(criteria) == 0
  125. segment_class(segm_i) = -1;
  126. else
  127. % uncertain segment
  128. % do nothing yet
  129. end
  130. segm_i = segm_i + 1;
  131. end
  132. end
  133. % initialize result to the labelled input vector
  134. result = labelVec;
  135. for segm_i = 1:size(prelInt, 1)
  136. if segment_class(segm_i) == 0
  137. % uncertain segment
  138. if segment_parameters(segm_i, 3) == 0 %similar to fixation
  139. if segment_parameters(segm_i, 4) == 1
  140. segment_class(segm_i) = 2; % SP, as determined on 2nd stage
  141. else
  142. segment_class(segm_i) = -1; % fixation
  143. end
  144. else % similar to SP
  145. % FIXME subject to change if a typo in a paper is found around Table 1
  146. % Removed assertion because of adaptive eta_maxFix
  147. %assert(eta_maxFix >= eta_minSmp)
  148. % then if we find any SP segments within the same intersaccadic interval, it's a SP
  149. target_ISI = segment_intersacc_index(segm_i);
  150. for search_i = 1:size(prelInt, 1)
  151. if segment_intersacc_index(search_i) < target_ISI
  152. continue
  153. elseif segment_intersacc_index(search_i) > target_ISI
  154. break
  155. end
  156. if segment_class(search_i) ~= 1
  157. continue
  158. end
  159. % angle comparisson
  160. dir1 = segment_parameters(search_i, 5:7);
  161. dir2 = segment_parameters(segm_i, 5:7);
  162. rel_angle = GetDispersion(dir1, dir2);
  163. if (rel_angle <= phi)
  164. segment_class(segm_i) = 2; % SP, as determined on 2nd stage
  165. end
  166. end
  167. if segment_class(segm_i) == 0
  168. segment_class(segm_i) = -1; % if no similar SP were found, it's a fixation
  169. end
  170. end
  171. end
  172. if segment_class(segm_i) > 0 %any of SP
  173. result(prelInt(segm_i,1):prelInt(segm_i,2)) = c_sp; % assign sp
  174. end
  175. if segment_class(segm_i) < 0 % -1 fixation
  176. result(prelInt(segm_i,1):prelInt(segm_i,2)) = c_fix; % assign fixation
  177. end
  178. end
  179. end