From eb8915ec0750699695e4d70af4abef56f56fbe9f Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Wed, 23 Aug 2023 16:40:28 +0200 Subject: Adding log analysis feature to ArFrame an ArLayer. --- src/argaze/ArFeatures.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py index 4811a0b..ad755e8 100644 --- a/src/argaze/ArFeatures.py +++ b/src/argaze/ArFeatures.py @@ -77,6 +77,7 @@ class ArLayer(): aoi_matcher: AOI matcher object aoi_scan_path: AOI scan path object aoi_scan_path_analyzers: dictionary of AOI scan path analyzers + log: enable aoi scan path analysis logging """ name: str @@ -85,6 +86,7 @@ class ArLayer(): aoi_matcher: GazeFeatures.AOIMatcher = field(default_factory=GazeFeatures.AOIMatcher) aoi_scan_path: GazeFeatures.AOIScanPath = field(default_factory=GazeFeatures.AOIScanPath) aoi_scan_path_analyzers: dict = field(default_factory=dict) + log: bool = field(default=False) def __post_init__(self): @@ -106,6 +108,16 @@ class ArLayer(): self.aoi_scene = AOI3DScene.AOI3DScene(self.aoi_scene) + # Prepare logging if needed + self.__ts_logs = {} + + if self.log: + + # Create timestamped buffers to log each aoi scan path analysis + for aoi_scan_path_analyzer_module_path in self.aoi_scan_path_analyzers.keys(): + + self.__ts_logs[aoi_scan_path_analyzer_module_path] = DataStructures.TimeStampedBuffer() + @classmethod def from_dict(self, layer_data, working_directory: str = None) -> ArLayerType: """Load attributes from dictionary. @@ -262,13 +274,23 @@ class ArLayer(): pass + # Load log status + try: + + new_layer_log = layer_data.pop('log') + + except KeyError: + + new_layer_log = False + # Create layer return ArLayer(new_layer_name, \ new_aoi_color, \ new_aoi_scene, \ new_aoi_matcher, \ new_aoi_scan_path, \ - new_aoi_scan_path_analyzers \ + new_aoi_scan_path_analyzers, \ + new_layer_log \ ) @classmethod @@ -299,6 +321,14 @@ class ArLayer(): self.__parent = parent + @property + def logs(self): + """ + Get stored logs + """ + + return self.__ts_logs + def look(self, timestamp: int|float, gaze_movement: GazeFeatures.GazePosition = GazeFeatures.UnvalidGazePosition()) -> dict: """ Project timestamped gaze movement into layer. @@ -380,6 +410,11 @@ class ArLayer(): # Store analysis aoi_scan_path_analysis[aoi_scan_path_analyzer_module_path] = aoi_scan_path_analyzer.analysis + # Log analysis + if self.log: + + self.__ts_logs[aoi_scan_path_analyzer_module_path][timestamp] = aoi_scan_path_analyzer.analysis + elif GazeFeatures.is_saccade(gaze_movement): # Append saccade to aoi scan path @@ -477,6 +512,7 @@ class ArFrame(): scan_path_analyzers: dictionary of scan path analyzers heatmap: heatmap object aoi_layers: dictionary of AOI layers + log: enable scan path analysis logging """ name: str @@ -488,7 +524,8 @@ class ArFrame(): scan_path_analyzers: dict = field(default_factory=dict) heatmap: AOIFeatures.Heatmap = field(default_factory=AOIFeatures.Heatmap) layers: dict = field(default_factory=dict) - + log: bool = field(default=False) + def __post_init__(self): # Define parent attribute: it will be setup by parent later @@ -505,6 +542,16 @@ class ArFrame(): # Init lock to share looked data with multiples threads self.__look_lock = threading.Lock() + # Prepare logging if needed + self.__ts_logs = {} + + if self.log: + + # Create timestamped buffers to log each aoi scan path analysis + for scan_path_analyzer_module_path in self.scan_path_analyzers.keys(): + + self.__ts_logs[scan_path_analyzer_module_path] = DataStructures.TimeStampedBuffer() + @classmethod def from_dict(self, frame_data, working_directory: str = None) -> ArFrameType: """Load attributes from dictionary. @@ -672,6 +719,15 @@ class ArFrame(): pass + # Load log status + try: + + new_frame_log = frame_data.pop('log') + + except KeyError: + + new_frame_log = False + # Create frame return ArFrame(new_frame_name, \ new_frame_size, \ @@ -681,7 +737,8 @@ class ArFrame(): new_scan_path, \ new_scan_path_analyzers, \ new_heatmap, \ - new_layers \ + new_layers, \ + new_frame_log \ ) @classmethod @@ -734,6 +791,14 @@ class ArFrame(): return image + @property + def logs(self): + """ + Get stored logs + """ + + return self.__ts_logs + def look(self, timestamp: int|float, gaze_position: GazeFeatures.GazePosition = GazeFeatures.UnvalidGazePosition()) -> Tuple[GazeFeatures.GazeMovement, dict, dict, dict]: """ Project gaze position into frame. @@ -826,6 +891,11 @@ class ArFrame(): # Store analysis scan_step_analysis[scan_path_analyzer_module_path] = scan_path_analyzer.analysis + # Log analysis + if self.log: + + self.__ts_logs[scan_path_analyzer_module_path][timestamp] = scan_path_analyzer.analysis + # No valid finished gaze movement: optionnaly stop in progress fixation filtering elif self.gaze_movement_identifier and not self.filter_in_progress_fixation: -- cgit v1.1