From fc999063417c8f56f03ac120e3b4f482c8f4ed86 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Wed, 4 May 2022 16:09:47 +0200 Subject: Removing TimeStampedVisualScanSteps class as it not possible to have two timestamps equal. --- src/argaze/GazeFeatures.py | 56 +++++++++++++--------- .../export_tobii_segment_aruco_visual_scan.py | 4 +- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/argaze/GazeFeatures.py b/src/argaze/GazeFeatures.py index 723b289..ebe6fe5 100644 --- a/src/argaze/GazeFeatures.py +++ b/src/argaze/GazeFeatures.py @@ -7,6 +7,7 @@ from argaze import DataStructures from argaze.AreaOfInterest import AOIFeatures import numpy +import pandas GazePosition = tuple """Define gaze position as a tuple of coordinates.""" @@ -225,53 +226,61 @@ class DispersionBasedMovementIdentifier(MovementIdentifier): @dataclass class VisualScanStep(): - """Define a visual scan step as a duration, the name of the area of interest and where gaze looked at in each frame during the step.""" + """Define a visual scan step as a start timestamp, duration, the name of the area of interest and where gaze looked at in each frame during the step.""" + timestamp: int duration: float area: str look_at: DataStructures.TimeStampedBuffer -class TimeStampedVisualScanSteps(DataStructures.TimeStampedBuffer): - """Define timestamped buffer to store visual scan steps.""" - - def __setitem__(self, key, value: VisualScanStep): - """Force value to be a VisualScanStep""" - if type(value) != VisualScanStep: - raise ValueError('value must be a VisualScanStep') - - super().__setitem__(key, value) - class VisualScanGenerator(): """Abstract class to define when an aoi starts to be looked and when it stops.""" + visual_scan_steps: list + def __init__(self, ts_aoi_scenes: AOIFeatures.TimeStampedAOIScenes): if type(ts_aoi_scenes) != AOIFeatures.TimeStampedAOIScenes: raise ValueError('argument must be a TimeStampedAOIScenes') + self.visual_scan_steps = [] + + for step in self: + + if step == None: + continue + + self.visual_scan_steps.append(step) + def __iter__(self): raise NotImplementedError('__iter__() method not implemented') - def build(self): + def steps(self): + return self.visual_scan_steps - visual_scan_steps = TimeStampedVisualScanSteps() + def as_dataframe(self): + """Convert buffer as pandas dataframe.""" - for ts, step in self: + df = pandas.DataFrame.from_dict(self.visual_scan_steps) + df.set_index('timestamp', inplace=True) + df.sort_values(by=['timestamp'], inplace=True) - if step == None: - continue + return df + + def export_as_csv(self, filepath): + """Write buffer content into a csv file.""" + try: - visual_scan_steps[ts] = step + self.as_dataframe().to_csv(filepath, index=True) - return TimeStampedVisualScanSteps(sorted(visual_scan_steps.items())) + except: + raise RuntimeError(f'Can\' write {filepath}') class PointerBasedVisualScan(VisualScanGenerator): """Build visual scan on the basis of which AOI are looked.""" def __init__(self, ts_aoi_scenes: AOIFeatures.TimeStampedAOIScenes, ts_gaze_positions: TimeStampedGazePositions): - super().__init__(ts_aoi_scenes) - # process identification on a copy self.__ts_aoi_scenes = ts_aoi_scenes.copy() self.__ts_gaze_positions = ts_gaze_positions.copy() @@ -279,6 +288,9 @@ class PointerBasedVisualScan(VisualScanGenerator): # a dictionary to store when an aoi starts to be looked self.__step_dict = {} + # build visual scan + super().__init__(ts_aoi_scenes) + def __iter__(self): """Visual scan generator function.""" @@ -313,7 +325,7 @@ class PointerBasedVisualScan(VisualScanGenerator): ts_start = self.__step_dict[name]['start'] # aoi stops to be looked - yield round(ts_start), VisualScanStep(round(ts_current - ts_start), name, self.__step_dict[name]['look_at']) + yield VisualScanStep(round(ts_start), round(ts_current - ts_start), name, self.__step_dict[name]['look_at']) # forget the aoi del self.__step_dict[name] @@ -328,7 +340,7 @@ class PointerBasedVisualScan(VisualScanGenerator): ts_start = step['start'] # aoi stops to be looked - yield round(ts_start), VisualScanStep(round(ts_current - ts_start), name, step['look_at']) + yield VisualScanStep(round(ts_start), round(ts_current - ts_start), name, step['look_at']) class FixationBasedVisualScan(VisualScanGenerator): """Build visual scan on the basis of timestamped fixations.""" diff --git a/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py b/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py index 5d93beb..4622b00 100644 --- a/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py +++ b/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py @@ -178,9 +178,9 @@ def main(): print(f'\nAOIs video saved into {video_filepath}') # Build visual scan based on a pointer position - visual_scan = GazeFeatures.PointerBasedVisualScan(ts_aois_scenes, ts_gaze_positions).build() + visual_scan = GazeFeatures.PointerBasedVisualScan(ts_aois_scenes, ts_gaze_positions) - print(f'{len(visual_scan)} visual scan steps found') + print(f'{len(visual_scan.steps())} visual scan steps found') # Export visual scan visual_scan.export_as_csv(visual_scan_filepath) -- cgit v1.1