DetectFixations360.m 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. % DetectFixations360.m
  2. %
  3. % This function detects fixations from the provided data. It is based on the
  4. % fixation detector desctibed in Dorr, Michael, et al. "Variability of eye
  5. % movements when viewing dynamic natural scenes." Journal of vision 10.10
  6. % (2010): 28-28.
  7. %
  8. % NOTE: It requires that saccades have already been detected.
  9. %
  10. % input:
  11. % data - data from the ARFF file
  12. % metadata - metadata from the ARFF file
  13. % attributes - attributes from the ARFF file
  14. % saccAtt - saccade attribute name
  15. % saccValue - integer value representing saccades
  16. % typeOfMotion- 1 -> eye FOV, 2 -> eye+head, 3 -> head
  17. % params - parameters to use for fixation detection
  18. %
  19. % output:
  20. % result - logical vector with the same length as data in inputfile and true where a fixation is detected
  21. %
  22. % params format:
  23. % params is a data structure with the following fields
  24. %
  25. % params.minDixationDur;
  26. % params.maxDistanceDeg;
  27. % params.velThresholdDdegDsec;
  28. % params.intersaccadicDist;
  29. % params.intersaccadicLength;
  30. % params.minConfidence;
  31. function m_result = DetectFixations360(data, metadata, attributes, saccAtt, saccValue, typeOfMotion, params)
  32. c_minFixationDurUs = params.minFixationDur;
  33. c_maxDistanceDeg = params.maxDistanceDeg;
  34. c_velThresholdDegSec = params.velThresholdDegSec;
  35. c_intersaccadicDist = params.intersaccadicDist;
  36. c_intersaccadicLength = params.intersaccadicLength;
  37. c_minConf = params.minConfidence;
  38. timeInd = GetAttPositionArff(attributes, 'time');
  39. xInd = GetAttPositionArff(attributes, 'x');
  40. yInd = GetAttPositionArff(attributes, 'y');
  41. confInd = GetAttPositionArff(attributes, 'confidence');
  42. % initialize return result
  43. m_result = false(size(data,1),1);
  44. if (size(data,1)<10)
  45. return;
  46. end
  47. [eyeFovVec, eyeHeadVec, headVec] = GetCartVectors(data, metadata, attributes);
  48. if (typeOfMotion == 1)
  49. vecList = eyeFovVec;
  50. elseif (typeOfMotion == 2)
  51. vecList = eyeHeadVec;
  52. elseif (typeOfMotion == 3)
  53. vecList = headVec;
  54. else
  55. error('Uknown motion');
  56. end
  57. % get inter-sacacdic intervals and start processing them
  58. intersaccInts = GetIntersaccadicIntervals();
  59. % member variables
  60. m_left = 0; % used in AnnotateFixation and the other local functions
  61. m_right = 0;
  62. % process each interval
  63. for intersaccIndex=1:size(intersaccInts,1)
  64. AnnotateFixation(intersaccInts(intersaccIndex,1), intersaccInts(intersaccIndex,2));
  65. end
  66. % remove noise from fixations
  67. m_result(data(:,confInd) < c_minConf) = 0;
  68. %-----------------------------------------------------------------------------------
  69. % local functions
  70. %-----------------------------------------------------------------------------------
  71. % function GetIntersaccadicIntervals:
  72. % Get the inter-saccadic intervals for the saccadic attribute of the ARFF file.
  73. function [l_intersaccInts] = GetIntersaccadicIntervals()
  74. [l_saccIndex] = GetAttPositionArff(attributes, saccAtt);
  75. l_intersaccInts = zeros(0,2);
  76. l_startOfInt = 1;
  77. l_isSaccActive = false;
  78. for l_i=1:size(data,1);
  79. % end of fixation interval found
  80. if (data(l_i,l_saccIndex) == saccValue && l_isSaccActive == false)
  81. l_isSaccActive = true;
  82. l_intersaccInts = [l_intersaccInts; l_startOfInt l_i-1];
  83. end
  84. if (data(l_i,l_saccIndex) ~= saccValue && l_isSaccActive == true)
  85. l_isSaccActive = false;
  86. l_startOfInt = l_i;
  87. end
  88. end
  89. % check for last interval
  90. if (data(end,l_saccIndex) ~= saccValue)
  91. l_intersaccInts = [l_intersaccInts; l_startOfInt size(data,1)];
  92. end
  93. end
  94. % function AnnotateFixation:
  95. % Processes the samples between the start and end indices.
  96. function AnnotateFixation(startIndex, endIndex)
  97. % if interval is too long check for its diplacement
  98. if (endIndex-startIndex > 1 && data(endIndex,timeInd)-data(startIndex,timeInd) > c_intersaccadicLength)
  99. l_maxDisp = GetMaxDispersion(vecList(startIndex:endIndex,:));
  100. % do not process if distance is too big
  101. if (l_maxDisp > c_intersaccadicDist)
  102. return;
  103. end
  104. end
  105. % continue processing
  106. m_left = startIndex;
  107. m_right = startIndex;
  108. while (DetermineSearchWindow(startIndex, endIndex))
  109. if (IsFixation())
  110. ExtendFixationWindow(startIndex, endIndex);
  111. m_left = m_right;
  112. else
  113. m_left = m_left+1;
  114. end
  115. end
  116. end
  117. % function DetermineSearchWindow:
  118. % Move m_right to accomodate the minimum fixation duration. If it can't return false.
  119. function l_result = DetermineSearchWindow(startIndex, endIndex)
  120. l_result = true;
  121. if (m_left > endIndex)
  122. l_result = false;
  123. return;
  124. end
  125. while (m_right <= endIndex && (data(m_right,timeInd)-data(m_left,timeInd)) < c_minFixationDurUs)
  126. m_right = m_right+1;
  127. end
  128. if (m_right > endIndex)
  129. l_result = false;
  130. return;
  131. end
  132. end
  133. % function ExtendFixationWindow:
  134. % Extend m_right until we reach end of interval of stops to be a fixation.
  135. function ExtendFixationWindow(startIndex, endIndex)
  136. while (true)
  137. m_right = m_right+1;
  138. if (m_right > endIndex || IsFixation()==false)
  139. break;
  140. end
  141. end
  142. % result of main function
  143. m_result(m_left:m_right-1) = 1;
  144. end
  145. % function IsFixation:
  146. % Determines from m_left, m_right if the interval is a valid fixation.
  147. function l_result = IsFixation()
  148. l_result = true;
  149. % get distance between first and last vector in list
  150. l_distance = GetDispersion(vecList(m_left,:), vecList(m_right,:));
  151. l_speed = 1000000*l_distance/(data(m_right,timeInd)-data(m_left,timeInd));
  152. if (l_speed > c_velThresholdDegSec)
  153. l_result = false;
  154. return;
  155. end
  156. meanVec = sum(vecList(m_left:m_right,:),1) / (m_right - m_left + 1);
  157. l_duration = data(m_right,timeInd) - data(m_left,timeInd);
  158. l_duration = (l_duration - c_minFixationDurUs)/1000 + 1;
  159. % increase threshold depending on fixation duration
  160. l_dispThres = c_maxDistanceDeg*(1+0.05*log2(l_duration));
  161. l_disp = GetDispersion(meanVec, vecList(m_left:m_right,:));
  162. if (l_disp > l_dispThres)
  163. l_result = false;
  164. end
  165. end
  166. end