DataReprojDetection.m 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. % DataReprojDetection.m
  2. %
  3. % This function detects eye movements by reprojectinig the 360-degree
  4. % equirectangular data and calling an external eye movement detection function.
  5. % It woks by splitting the equirectangular input data into intervals where the
  6. % vertical spread is no more than 45 degrees. It then reprojects them around
  7. % the equatorial line of the sphere and creates coordinates that are equivalent
  8. % to a monitor recorded experiment. Finally we can call the provided monitor
  9. % designed algorithm with the new ARFF object as input. The input data should
  10. % have the relation "gaze_360" to mark they were recorded in 360-degree
  11. % equirectangular experiment.
  12. %
  13. % The eye movement detection function is provided as string in the input
  14. % arguments. This function should have at least 3 input variables, namely
  15. % data, metadata, and attributes as loaded from the LoadArff function. If the
  16. % provided detection function requires more input than the 3 default arguments,
  17. % these can be provided as extra arguments in the argument list of the current
  18. % function. The extra arguments are placed in the order that they appear after
  19. % the 3 default arguments in the detection function. The output of the
  20. % detection function should be a vector with a unique integer value for each
  21. % detected eye movement. These should correspond to the provided attValues
  22. % input argument as in the case of an enumeration.
  23. %
  24. % input:
  25. % arffFile - file to process
  26. % outFile - file to store results
  27. % outputAtt - name of the attribute in the output ARFF
  28. % attValues - nominal values of the added attributes. They are a string in the
  29. % form '{unassigned, fixation, sacacde, sp, noise}'
  30. % detFuncName - detection function name
  31. % varargin - required extra arguments for calling the detection function.
  32. % The data, metadata, attributes are used by default in this
  33. % order followed by the varargin arguments
  34. function DataReprojDetection(arffFile, outFile, outputAtt, attValues, detFuncName, varargin)
  35. DetectionFunction = str2func(detFuncName);
  36. c_maxVertDiff = 45 * pi / 180;
  37. [data, metadata, attributes, relation, comments] = LoadArff(arffFile);
  38. xInd = GetAttPositionArff(attributes, 'x');
  39. yInd = GetAttPositionArff(attributes, 'y');
  40. assert(strcmp(relation, 'gaze_360'), 'Input data should be from 360-degree recordings');
  41. % create metadata representing a monitor experiment
  42. metaMonitor = metadata;
  43. % ppd for 360 experiment
  44. ppdx = metadata.width_px / 360;
  45. ppdy = metadata.height_px / 180;
  46. metaMonitor.distance_mm = 800; % this stays fixed
  47. metaMonitor.width_mm = ppd2distance(ppdx, metaMonitor.width_px, metaMonitor.distance_mm);
  48. metaMonitor.height_mm = ppd2distance(ppdy, metaMonitor.height_px, metaMonitor.distance_mm);
  49. iniData = data;
  50. RemoveChanges();
  51. [~, eyeHeadVec] = GetCartVectors(data, metadata, attributes);
  52. labelledAtt = zeros(size(data,1),1);
  53. ints = GetIntervals(eyeHeadVec);
  54. for ind=1:size(ints,1)
  55. intData = data(ints(ind,1):ints(ind,2),:);
  56. coords = Project3dVectors(eyeHeadVec(ints(ind,1):ints(ind,2),:), metadata);
  57. % change x,y to the projected data
  58. intData(:,xInd) = coords(:,1);
  59. intData(:,yInd) = coords(:,2);
  60. if (isempty(varargin))
  61. labelledAtt(ints(ind,1):ints(ind,2)) = DetectionFunction(intData, metaMonitor, attributes);
  62. else
  63. labelledAtt(ints(ind,1):ints(ind,2)) = DetectionFunction(intData, metaMonitor, attributes, varargin{:});
  64. end
  65. end
  66. [newData, newAttributes] = AddAttArff(iniData, attributes, labelledAtt, outputAtt, attValues);
  67. SaveArff(outFile, newData, metadata, newAttributes, relation, comments);
  68. function RemoveChanges()
  69. confInd = GetAttPositionArff(attributes, 'confidence');
  70. c_minConf = 0.75;
  71. for i=2:size(data,1)
  72. if (data(i,confInd) < c_minConf)
  73. data(i, xInd) = data(i-1, xInd);
  74. data(i, yInd) = data(i-1, yInd);
  75. end
  76. end
  77. end
  78. % This function returns intervals, which have all the samples within the maximum range
  79. % specified by c_maxVertDiff
  80. function [l_ints] = GetIntervals(vectors)
  81. l_ints = zeros(0,2);
  82. startInd = 1;
  83. [~, minVert] = CartToSpherical(vectors(startInd,:));
  84. maxVert = minVert;
  85. for i=1:size(vectors,1)
  86. [hor, vert] = CartToSpherical(vectors(i,:));
  87. if (vert < minVert)
  88. minVert = vert;
  89. end
  90. if (vert > maxVert)
  91. maxVert = vert;
  92. end
  93. if (maxVert - minVert > c_maxVertDiff)
  94. l_ints = [l_ints; startInd i];
  95. startInd = i+1;
  96. if (startInd <= size(vectors,1))
  97. [~, minVert] = CartToSpherical(vectors(startInd,:));
  98. maxVert = minVert;
  99. end
  100. end
  101. end
  102. if (startInd <= size(vectors,1))
  103. l_ints = [l_ints; startInd size(vectors,1)];
  104. end
  105. end
  106. end