aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThéo de la Hogue2023-06-27 16:45:13 +0200
committerThéo de la Hogue2023-06-27 16:45:13 +0200
commit4df82841d44fab86edaef7bc93b80d83a8a1980f (patch)
treea6c60488910caccf42e62caac02833c2c59984c0
parent05a4b79570d91db468abea44259e4a7f825906ca (diff)
downloadargaze-4df82841d44fab86edaef7bc93b80d83a8a1980f.zip
argaze-4df82841d44fab86edaef7bc93b80d83a8a1980f.tar.gz
argaze-4df82841d44fab86edaef7bc93b80d83a8a1980f.tar.bz2
argaze-4df82841d44fab86edaef7bc93b80d83a8a1980f.tar.xz
Adding new UnvalidGazeMovement class.
-rw-r--r--src/argaze/ArFeatures.py6
-rw-r--r--src/argaze/GazeAnalysis/DispersionThresholdIdentification.py11
-rw-r--r--src/argaze/GazeAnalysis/VelocityThresholdIdentification.py11
-rw-r--r--src/argaze/GazeFeatures.py47
4 files changed, 55 insertions, 20 deletions
diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py
index 321bd1b..493ca8a 100644
--- a/src/argaze/ArFeatures.py
+++ b/src/argaze/ArFeatures.py
@@ -545,7 +545,7 @@ class ArScreen():
# Init gaze data
self.__gaze_position = GazeFeatures.UnvalidGazePosition()
- self.__gaze_movement = None
+ self.__gaze_movement = GazeFeatures.UnvalidGazeMovement()
@classmethod
def from_scene(self, aoi_scene, aoi_name, size, gaze_movement_identifier) -> ArScreenType:
@@ -593,6 +593,4 @@ class ArScreen():
def draw_gaze_movement(self, color=(255, 255, 255)):
"""Draw current gaze movement into screen image."""
- if self.__gaze_movement:
-
- self.__gaze_movement.draw(self.__image, color)
+ self.__gaze_movement.draw_positions(self.__image, color)
diff --git a/src/argaze/GazeAnalysis/DispersionThresholdIdentification.py b/src/argaze/GazeAnalysis/DispersionThresholdIdentification.py
index 1883d69..147046a 100644
--- a/src/argaze/GazeAnalysis/DispersionThresholdIdentification.py
+++ b/src/argaze/GazeAnalysis/DispersionThresholdIdentification.py
@@ -124,7 +124,7 @@ class GazeMovementIdentifier(GazeFeatures.GazeMovementIdentifier):
# Ignore non valid gaze position
if not gaze_position.valid:
- return None if not terminate else self.current_fixation
+ return GazeFeatures.UnvalidGazeMovement() if not terminate else self.current_fixation
# Check if too much time elapsed since last gaze position
if len(self.__valid_positions) > 0:
@@ -199,6 +199,9 @@ class GazeMovementIdentifier(GazeFeatures.GazeMovementIdentifier):
first_ts, first_position = self.__valid_positions.pop_first()
self.__saccade_positions[first_ts] = first_position
+ # Always return unvalid gaze movement at least
+ return GazeFeatures.UnvalidGazeMovement()
+
@property
def current_fixation(self) -> FixationType:
@@ -206,9 +209,15 @@ class GazeMovementIdentifier(GazeFeatures.GazeMovementIdentifier):
return Fixation(self.__fixation_positions)
+ # Always return unvalid gaze movement at least
+ return GazeFeatures.UnvalidGazeMovement()
+
@property
def current_saccade(self) -> SaccadeType:
if len(self.__saccade_positions) > 0:
return Saccade(self.__saccade_positions)
+
+ # Always return unvalid gaze movement at least
+ return GazeFeatures.UnvalidGazeMovement()
diff --git a/src/argaze/GazeAnalysis/VelocityThresholdIdentification.py b/src/argaze/GazeAnalysis/VelocityThresholdIdentification.py
index 7d6c7b2..7131373 100644
--- a/src/argaze/GazeAnalysis/VelocityThresholdIdentification.py
+++ b/src/argaze/GazeAnalysis/VelocityThresholdIdentification.py
@@ -133,7 +133,7 @@ class GazeMovementIdentifier(GazeFeatures.GazeMovementIdentifier):
# Ignore non valid gaze position
if not gaze_position.valid:
- return None if not terminate else self.current_fixation
+ return GazeFeatures.UnvalidGazeMovement() if not terminate else self.current_fixation
# Store first valid position
if self.__last_ts < 0:
@@ -211,6 +211,9 @@ class GazeMovementIdentifier(GazeFeatures.GazeMovementIdentifier):
return self.current_fixation
+ # Always return unvalid gaze movement at least
+ return GazeFeatures.UnvalidGazeMovement()
+
@property
def current_fixation(self) -> FixationType:
@@ -218,9 +221,15 @@ class GazeMovementIdentifier(GazeFeatures.GazeMovementIdentifier):
return Fixation(self.__fixation_positions)
+ # Always return unvalid gaze movement at least
+ return GazeFeatures.UnvalidGazeMovement()
+
@property
def current_saccade(self) -> SaccadeType:
if len(self.__saccade_positions) > 0:
return Saccade(self.__saccade_positions)
+
+ # Always return unvalid gaze movement at least
+ return GazeFeatures.UnvalidGazeMovement()
diff --git a/src/argaze/GazeFeatures.py b/src/argaze/GazeFeatures.py
index 218858a..65afdf8 100644
--- a/src/argaze/GazeFeatures.py
+++ b/src/argaze/GazeFeatures.py
@@ -223,30 +223,40 @@ class GazeMovement():
def __post_init__(self):
- start_position_ts, start_position = self.positions.first
- end_position_ts, end_position = self.positions.last
+ if self.valid:
+
+ start_position_ts, start_position = self.positions.first
+ end_position_ts, end_position = self.positions.last
- # Update frozen duration attribute
- object.__setattr__(self, 'duration', end_position_ts - start_position_ts)
+ # Update frozen duration attribute
+ object.__setattr__(self, 'duration', end_position_ts - start_position_ts)
- _, start_position = self.positions.first
- _, end_position = self.positions.last
+ _, start_position = self.positions.first
+ _, end_position = self.positions.last
- amplitude = numpy.linalg.norm( numpy.array(start_position.value) - numpy.array(end_position.value))
+ amplitude = numpy.linalg.norm( numpy.array(start_position.value) - numpy.array(end_position.value))
- # Update frozen amplitude attribute
- object.__setattr__(self, 'amplitude', amplitude)
+ # Update frozen amplitude attribute
+ object.__setattr__(self, 'amplitude', amplitude)
def __str__(self) -> str:
"""String display"""
- output = f'{type(self)}:\n\tduration={self.duration}\n\tsize={len(self.positions)}'
+ if self.valid:
- for ts, position in self.positions.items():
+ output = f'{type(self)}:\n\tduration={self.duration}\n\tsize={len(self.positions)}'
- output += f'\n\t{ts}:\n\t\tvalue={position.value},\n\t\taccurracy={position.precision}'
+ for ts, position in self.positions.items():
- return output
+ output += f'\n\t{ts}:\n\t\tvalue={position.value},\n\t\taccurracy={position.precision}'
+
+ return output
+
+ @property
+ def valid(self) -> bool:
+ """Is there positions?"""
+
+ return len(self.positions) > 0
def draw_positions(self, image: numpy.array, color=(0, 55, 55)):
"""Draw gaze movement positions"""
@@ -262,7 +272,16 @@ class GazeMovement():
start_gaze_position.draw(image, draw_precision=False)
# Draw movement from start to next
- cv2.line(image, start_gaze_position, next_gaze_position, color, 1)
+ cv2.line(image, (int(start_gaze_position[0]), int(start_gaze_position[1])), (int(next_gaze_position[0]), int(next_gaze_position[1])), color, 1)
+
+class UnvalidGazeMovement(GazeMovement):
+ """Unvalid gaze movement."""
+
+ def __init__(self, message=None):
+
+ self.message = message
+
+ super().__init__([])
FixationType = TypeVar('Fixation', bound="Fixation")
# Type definition for type annotation convenience