aboutsummaryrefslogtreecommitdiff
path: root/src/argaze/GazeFeatures.py
diff options
context:
space:
mode:
authorThéo de la Hogue2022-05-10 11:19:43 +0200
committerThéo de la Hogue2022-05-10 11:19:43 +0200
commitf59fae48f03fc29b315b9ea750c01e147697e3ff (patch)
tree36ed8096bbf6d36045aebfb9a28d25d4d8b4bbeb /src/argaze/GazeFeatures.py
parent5c734e16bb35377d786f14bf9181044e67025a0a (diff)
downloadargaze-f59fae48f03fc29b315b9ea750c01e147697e3ff.zip
argaze-f59fae48f03fc29b315b9ea750c01e147697e3ff.tar.gz
argaze-f59fae48f03fc29b315b9ea750c01e147697e3ff.tar.bz2
argaze-f59fae48f03fc29b315b9ea750c01e147697e3ff.tar.xz
Exporting new movements.csv and movements.mp4 files.
Diffstat (limited to 'src/argaze/GazeFeatures.py')
-rw-r--r--src/argaze/GazeFeatures.py57
1 files changed, 52 insertions, 5 deletions
diff --git a/src/argaze/GazeFeatures.py b/src/argaze/GazeFeatures.py
index 32ec571..d7466df 100644
--- a/src/argaze/GazeFeatures.py
+++ b/src/argaze/GazeFeatures.py
@@ -22,6 +22,7 @@ class TimeStampedGazePositions(DataStructures.TimeStampedBuffer):
class Fixation():
"""Define gaze fixation."""
+ index: int
duration: float
dispersion: float
centroid: GazePosition
@@ -31,12 +32,18 @@ class TimeStampedFixations(DataStructures.TimeStampedBuffer):
"""Define timestamped buffer to store fixations."""
def __setitem__(self, key, value: Fixation):
+ """Force value to be a Fixation"""
+
+ if not isinstance(value, Fixation):
+ raise ValueError('value must be a Fixation')
+
super().__setitem__(key, value)
@dataclass
class Saccade():
"""Define gaze saccade."""
+ index: int
duration: float
start_position: GazePosition
end_position: GazePosition
@@ -46,11 +53,31 @@ class TimeStampedSaccades(DataStructures.TimeStampedBuffer):
def __setitem__(self, key, value: Saccade):
"""Force value to be a Saccade"""
+
if not isinstance(value, Saccade):
raise ValueError('value must be a Saccade')
super().__setitem__(key, value)
+@dataclass
+class Movement():
+ """Define movement."""
+
+ index: int
+ type: str
+ position: GazePosition
+
+class TimeStampedMovements(DataStructures.TimeStampedBuffer):
+ """Define timestamped buffer to store movement."""
+
+ def __setitem__(self, key, value: Movement):
+ """Force value to be a Movement"""
+
+ if not isinstance(value, Movement):
+ raise ValueError('value must be a Movement')
+
+ super().__setitem__(key, value)
+
class MovementIdentifier():
"""Abstract class to define what should provide a movement identifier."""
@@ -67,21 +94,31 @@ class MovementIdentifier():
def identify(self):
- fixations = GazeFeatures.TimeStampedFixations()
- saccades = GazeFeatures.TimeStampedSaccades()
+ fixations = TimeStampedFixations()
+ saccades = TimeStampedSaccades()
+ movements = TimeStampedMovement()
for ts, item in self:
if isinstance(item, GazeFeatures.Fixation):
+
fixations[ts] = item
+ for ts, position in item.positions.items():
+
+ movements[ts] = Movement(item.index, type(item).__name__, position)
+
elif isinstance(item, GazeFeatures.Saccade):
+
saccades[ts] = item
+ movements[ts] = Movement(item.index, type(item).__name__, item.start_position)
+ movements[ts + item.duration] = Movement(item.index, type(item).__name__, item.end_position)
+
else:
continue
- return fixations, saccades
+ return fixations, saccades, movements
class DispersionBasedMovementIdentifier(MovementIdentifier):
"""Implementation of the I-DT algorithm as described in:
@@ -105,6 +142,9 @@ class DispersionBasedMovementIdentifier(MovementIdentifier):
self.__last_fixation = None
self.__last_fixation_ts = -1
+ self.__fixations_count = 0
+ self.__saccades_count = 0
+
def __getEuclideanDispersion(self, ts_gaze_positions_list):
"""Euclidian dispersion algorithm"""
@@ -201,7 +241,9 @@ class DispersionBasedMovementIdentifier(MovementIdentifier):
for (ts, gp) in ts_gaze_positions_list:
ts_gaze_positions[round(ts)] = gp
- new_fixation = Fixation(round(duration), dispersion, (round(cx), round(cy)), ts_gaze_positions)
+ self.__fixations_count += 1
+
+ new_fixation = Fixation(self.__fixations_count, round(duration), dispersion, (round(cx), round(cy)), ts_gaze_positions)
new_fixation_ts = ts_list[0]
if self.__last_fixation != None:
@@ -211,7 +253,12 @@ class DispersionBasedMovementIdentifier(MovementIdentifier):
if new_saccade_duration > 0:
- new_saccade = Saccade(round(new_saccade_duration), self.__last_fixation.positions.pop_last()[1], new_fixation.positions.pop_first()[1])
+ start_position_ts, start_position = self.__last_fixation.positions.pop_last()
+ end_position_ts, end_position = new_fixation.positions.pop_first()
+
+ self.__saccades_count += 1
+
+ new_saccade = Saccade(self.__saccades_count, round(new_saccade_duration), start_position, end_position)
yield round(new_saccade_ts), new_saccade