aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThéo de la Hogue2023-01-30 17:51:48 +0100
committerThéo de la Hogue2023-01-30 17:51:48 +0100
commit837168f2f174bdb94c457601e529361b98e59101 (patch)
treeaa32a534a1028ca88cc31d623d963cb7f71d51fc /src
parentfdaaa5be7e99252cf0f25342b04485576a11bcea (diff)
downloadargaze-837168f2f174bdb94c457601e529361b98e59101.zip
argaze-837168f2f174bdb94c457601e529361b98e59101.tar.gz
argaze-837168f2f174bdb94c457601e529361b98e59101.tar.bz2
argaze-837168f2f174bdb94c457601e529361b98e59101.tar.xz
Refactoring realtime gaze movement identification.
Diffstat (limited to 'src')
-rw-r--r--src/argaze/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py96
1 files changed, 50 insertions, 46 deletions
diff --git a/src/argaze/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py b/src/argaze/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py
index 849223c..51286ee 100644
--- a/src/argaze/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py
+++ b/src/argaze/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py
@@ -370,86 +370,90 @@ class TobiiDataStream_GazeMovementIdentifier():
def __post_init__(self):
- self.__valid_gaze_positions = GazeFeatures.TimeStampedGazePositions()
- self.__current_fixation = None
- self.__current_saccade = None
+ self.__valid_positions = GazeFeatures.TimeStampedGazePositions()
+ self.__fixation_positions = GazeFeatures.TimeStampedGazePositions()
+ self.__saccade_positions = GazeFeatures.TimeStampedGazePositions()
def identify(self, ts, gaze_position):
+ # Ignore non valid gaze position
+ #if not gaze_position.valid:
+ # return
+
# Check if too much time elapsed since last gaze position
- if len(self.__valid_gaze_positions) > 0:
+ if len(self.__valid_positions) > 0:
- ts_last, _ = self.__valid_gaze_positions.last
+ ts_last, _ = self.__valid_positions.last
if (ts - ts_last) > self.duration_min_threshold:
- # Clear valid positions
- self.__valid_gaze_positions = GazeFeatures.TimeStampedGazePositions()
-
- # Clear current movements
- self.__current_fixation = None
- self.__current_saccade = None
+ # Clear all former gaze positions
+ self.__valid_positions = GazeFeatures.TimeStampedGazePositions()
+ self.__fixation_positions = GazeFeatures.TimeStampedGazePositions()
+ self.__saccade_positions = GazeFeatures.TimeStampedGazePositions()
# Store gaze positions until a minimal duration
- self.__valid_gaze_positions[ts] = gaze_position
+ self.__valid_positions[ts] = gaze_position
- first_ts, _ = self.__valid_gaze_positions.first
- last_ts, _ = self.__valid_gaze_positions.last
+ first_ts, _ = self.__valid_positions.first
+ last_ts, _ = self.__valid_positions.last
# Once the minimal duration is reached
if last_ts - first_ts >= self.duration_min_threshold:
# Calculate the deviation of valid gaze positions
- extended_fixation = Fixation(self.__valid_gaze_positions)
- deviation = extended_fixation.deviation_max
+ deviation = Fixation(self.__valid_positions).deviation_max
# Valid gaze positions deviation small enough
if deviation <= self.deviation_max_threshold:
- # Clear current saccade
- # Question : Should we emit a SaccadeStop event?
- self.__current_saccade = None
+ # Store last saccade
+ last_saccade = self.current_saccade
- # Start/extend current fixation
- # Question : Should we emit a FixationStart event?
- self.__current_fixation = extended_fixation
+ # Clear saccade positions
+ self.__saccade_positions = GazeFeatures.TimeStampedGazePositions()
- # Valid gaze positions deviation too wide while extending fixation
- elif self.__current_fixation != None:
+ # Copy valid gaze positions into fixation positions
+ self.__fixation_positions = self.__valid_positions.copy()
- # Create saccade from last position of current fixation to current gaze position
- # Question : Should we emit a SaccadeStart event?
- saccade_positions = GazeFeatures.TimeStampedGazePositions()
- last_ts, last_position = self.__current_fixation.positions.last
- saccade_positions[last_ts] = last_position
- saccade_positions[ts] = gaze_position
+ # Output last saccade
+ return last_saccade
+
+ # Valid gaze positions deviation too wide while identifying fixation
+ elif len(self.__fixation_positions) > 0:
- self.__current_saccade = Saccade(saccade_positions)
+ # Store last fixation
+ last_fixation = self.current_fixation
- # Clear current fixation
- # Question : Should we emit a FixationStop event?
- self.__current_fixation = None
+ # Start saccade positions with current gaze position
+ self.__saccade_positions[ts] = gaze_position
- # Reset valid positions with current gaze position
- self.__valid_gaze_positions = GazeFeatures.TimeStampedGazePositions()
- self.__valid_gaze_positions[ts] = gaze_position
+ # Clear fixation positions
+ self.__fixation_positions = GazeFeatures.TimeStampedGazePositions()
- # Valid gaze positions deviation too wide with no current fixation
- else:
+ # Clear valid positions
+ self.__valid_positions = GazeFeatures.TimeStampedGazePositions()
+
+ # Output last fixation
+ return last_fixation
- # Create saccade with valid gaze positions
- self.__current_saccade = Saccade(self.__valid_gaze_positions)
+ # Valid gaze positions deviation too wide while identifying saccade (or not)
+ else:
- # Reset valid positions with current gaze position
- self.__valid_gaze_positions = GazeFeatures.TimeStampedGazePositions()
- self.__valid_gaze_positions[ts] = gaze_position
+ # Move oldest valid position into saccade positions
+ first_ts, first_position = self.__valid_positions.pop_first()
+ self.__saccade_positions[first_ts] = first_position
@property
def current_fixation(self) -> FixationType:
- return self.__current_fixation
+ if len(self.__fixation_positions) > 0:
+
+ return Fixation(self.__fixation_positions)
@property
def current_saccade(self) -> SaccadeType:
- return self.__current_saccade
+ if len(self.__saccade_positions) > 0:
+
+ return Saccade(self.__saccade_positions)