Ioannis Agtzidis 4 роки тому
батько
коміт
c3bb7ebdbe
1 змінених файлів з 92 додано та 0 видалено
  1. 92 0
      DetectOKN360.m

+ 92 - 0
DetectOKN360.m

@@ -0,0 +1,92 @@
+% DetectOKN360.m
+%
+% This function detects optokinetic nystagmus for 360 degrees data. It uses a 
+% two step process. In the first step it detects points were the direction 
+% difference around a point is greater than 90 degrees. In the second step
+% it compares the FOV speed of the intervals. If it is above a threshold then
+% it is considered as OKN
+%
+% NOTE: OKN is calculated only in FOV representation. Also saccades have to be
+% annotated in advance.
+%
+% input:
+%   arffFile    - file with ARFF data
+%   saccAttName - name of the saccade attribute
+%   saccValue   - integer value representing saccades
+%
+% output:
+%   result      - a logical vector of the same size as the data in the ARFF with true value
+%                 when OKN occurs
+
+function result = DetectOKN360(arffFile, saccAttName, saccValue)
+    c_minIntAngle = 90; % minimum angle between saccade and subsequent interval
+    c_maxIntSaccAngle = 70; % maximum angle between saccades
+    c_minIntSpeed = 10; % degrees/sec
+    c_saccAttVal = saccValue;
+    c_OKNlabel = 1;
+
+    [data, metadata, attributes] = LoadArff(arffFile);
+    timeInd = GetAttPositionArff(attributes, 'time');
+
+    [eyeFovVec, eyeHeadVec, headVec] = GetCartVectors(data, metadata, attributes);
+
+    saccInts = GetIntervalsIndexArff(data, attributes, saccAttName, c_saccAttVal);
+
+    result = zeros(size(data,1),1);
+    attInd = GetAttPositionArff(attributes, saccAttName);
+    %result(data(:,attInd) == c_saccAttVal) = c_OKNlabel;
+    for ind=1:size(saccInts,1)-1
+        saccDir1 = eyeFovVec(saccInts(ind,2),:) - eyeFovVec(saccInts(ind,1),:);
+        saccDir2 = eyeFovVec(saccInts(ind+1,2),:) - eyeFovVec(saccInts(ind+1,1),:);
+
+        % inter-saccadic direction
+        intSaccDir = eyeFovVec(saccInts(ind+1,1)-1,:) - eyeFovVec(saccInts(ind,2)+1,:);
+
+        if (sum(saccDir1) == 0 || sum(saccDir2) == 0 || sum(intSaccDir) == 0)
+            continue;
+        end
+
+        saccDir1 = saccDir1 / norm(saccDir1);
+        saccDir2 = saccDir2 / norm(saccDir2);
+        intSaccDir = intSaccDir / norm(intSaccDir);
+
+        relDirSacc = GetDispersion(saccDir1, saccDir2);
+        relDirIntSacc1 = GetDispersion(saccDir1, intSaccDir);
+        relDirIntSacc2 = GetDispersion(saccDir2, intSaccDir);
+        dur = data(saccInts(ind+1,1)-1, timeInd) - data(saccInts(ind,2)+1, timeInd);
+        dur = dur / 1000000;
+        ampl = GetDispersion(eyeFovVec(saccInts(ind+1,1)-1,:), eyeFovVec(saccInts(ind,2)+1,:));
+        speed = ampl / dur;
+
+        if (relDirSacc < c_maxIntSaccAngle && ...
+            relDirIntSacc1 > c_minIntAngle && ...
+            relDirIntSacc2 > c_minIntAngle && ...
+            speed > c_minIntSpeed)
+        %if ((relDirIntSacc1 > c_minIntAngle || ...
+        %    relDirIntSacc2 > c_minIntAngle) && ...
+        %    speed > c_minIntSpeed)
+            result(saccInts(ind,2)+1:saccInts(ind+1,1)-1) = c_OKNlabel;
+        end
+    end
+
+    % Iterate again through saccade intervals and make sure that at least two
+    % OKN intervals exist continuously.
+    for ind=2:size(saccInts,1)-1
+        if (result(saccInts(ind,2)+1) == c_OKNlabel)
+            if (result(saccInts(ind,1) -1) ~= c_OKNlabel && ... % previous interval
+                    result(saccInts(ind+1,2)+1) ~= c_OKNlabel) % next interval
+                result(saccInts(ind,2)+1:saccInts(ind+1,1)-1) = 0;
+            end
+        end
+        % assign OKN label to saccades between OKN intervals
+        if (result(saccInts(ind,1) -1) == c_OKNlabel && ... 
+                result(saccInts(ind,2)+1) == c_OKNlabel) 
+            result(saccInts(ind,1):saccInts(ind,2)) = c_OKNlabel;
+        end
+   end
+
+    confInd = GetAttPositionArff(attributes, 'confidence');
+    result(data(:,confInd) < 1) = 0;
+
+    result = logical(result);
+end