From 14e7955c16ad8ed73824c811b54b46dc54203d34 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Tue, 16 May 2023 10:10:20 +0200 Subject: Renaming visual scan into aoi scan. --- src/argaze.test/GazeFeatures.py | 78 +++++++++++----------- src/argaze/GazeAnalysis/CoefficientK.py | 20 +++--- .../GazeAnalysis/TransitionProbabilityMatrix.py | 12 ++-- src/argaze/GazeFeatures.py | 38 +++++------ src/argaze/utils/demo_gaze_features_run.py | 28 ++++---- 5 files changed, 88 insertions(+), 88 deletions(-) diff --git a/src/argaze.test/GazeFeatures.py b/src/argaze.test/GazeFeatures.py index aebbcfc..4679929 100644 --- a/src/argaze.test/GazeFeatures.py +++ b/src/argaze.test/GazeFeatures.py @@ -209,11 +209,11 @@ class TestTimeStampedGazePositionsClass(unittest.TestCase): self.assertEqual(ts_gaze_positions_dataframe["value"].dtype, 'object') self.assertEqual(ts_gaze_positions_dataframe["precision"].dtype, 'O') # Python object type -class TestVisualScanStepClass(unittest.TestCase): - """Test VisualScanStep class.""" +class TestAOIScanStepClass(unittest.TestCase): + """Test AOIScanStep class.""" def test_new(self): - """Test VisualScanStep creation.""" + """Test AOIScanStep creation.""" movements = GazeFeatures.TimeStampedGazeMovements() @@ -225,17 +225,17 @@ class TestVisualScanStepClass(unittest.TestCase): ts, _ = saccade.positions.first movements[ts] = saccade - visual_scan_step = GazeFeatures.VisualScanStep(movements, 'Test') + aoi_scan_step = GazeFeatures.AOIScanStep(movements, 'Test') - # Check visual scan step creation - self.assertEqual(len(visual_scan_step.movements), 2) - self.assertEqual(visual_scan_step.aoi, 'Test') - self.assertEqual(visual_scan_step.first_fixation, fixation) - self.assertEqual(visual_scan_step.last_saccade, saccade) - self.assertGreater(visual_scan_step.duration, 0) + # Check aoi scan step creation + self.assertEqual(len(aoi_scan_step.movements), 2) + self.assertEqual(aoi_scan_step.aoi, 'Test') + self.assertEqual(aoi_scan_step.first_fixation, fixation) + self.assertEqual(aoi_scan_step.last_saccade, saccade) + self.assertGreater(aoi_scan_step.duration, 0) def test_error(self): - """Test VisualScanStep creation error.""" + """Test AOIScanStep creation error.""" movements = GazeFeatures.TimeStampedGazeMovements() @@ -247,81 +247,81 @@ class TestVisualScanStepClass(unittest.TestCase): ts, _ = fixation.positions.first movements[ts] = fixation - # Check that visual scan step creation fail - with self.assertRaises(GazeFeatures.VisualScanStepError): + # Check that aoi scan step creation fail + with self.assertRaises(GazeFeatures.AOIScanStepError): - visual_scan_step = GazeFeatures.VisualScanStep(movements, 'Test') + aoi_scan_step = GazeFeatures.AOIScanStep(movements, 'Test') -class TestVisualScanPathClass(unittest.TestCase): - """Test VisualScanPath class.""" +class TestAOIScanPathClass(unittest.TestCase): + """Test AOIScanPath class.""" def test_new(self): - """Test VisualScanPath creation.""" + """Test AOIScanPath creation.""" - # Check visual scan step creation - visual_scan_path = GazeFeatures.VisualScanPath() + # Check aoi scan step creation + aoi_scan_path = GazeFeatures.AOIScanPath() - self.assertEqual(len(visual_scan_path), 0) + self.assertEqual(len(aoi_scan_path), 0) def test_append(self): - """Test VisualScanPath append methods.""" + """Test AOIScanPath append methods.""" - visual_scan_path = GazeFeatures.VisualScanPath() + aoi_scan_path = GazeFeatures.AOIScanPath() # Append fixation on A aoi fixation = GazeFeatures.Fixation(random_gaze_positions(10)) ts, _ = fixation.positions.first - new_step = visual_scan_path.append_fixation(ts, fixation, 'A') + new_step = aoi_scan_path.append_fixation(ts, fixation, 'A') - # Check that no visual scan step have been created yet - self.assertEqual(len(visual_scan_path), 0) + # Check that no aoi scan step have been created yet + self.assertEqual(len(aoi_scan_path), 0) self.assertEqual(new_step, None) # Append saccade saccade = GazeFeatures.Saccade(random_gaze_positions(2)) ts, _ = saccade.positions.first - new_step = visual_scan_path.append_saccade(ts, saccade) + new_step = aoi_scan_path.append_saccade(ts, saccade) - # Check that no visual scan step have been created yet - self.assertEqual(len(visual_scan_path), 0) + # Check that no aoi scan step have been created yet + self.assertEqual(len(aoi_scan_path), 0) self.assertEqual(new_step, None) # Append fixation on B aoi fixation = GazeFeatures.Fixation(random_gaze_positions(10)) ts, _ = fixation.positions.first - new_step = visual_scan_path.append_fixation(ts, fixation, 'B') + new_step = aoi_scan_path.append_fixation(ts, fixation, 'B') - # Check a new visual scan step have been created - self.assertEqual(len(visual_scan_path), 1) + # Check a new aoi scan step have been created + self.assertEqual(len(aoi_scan_path), 1) self.assertEqual(len(new_step.movements), 2) self.assertEqual(new_step.aoi, 'A') def test_append_error(self): - """Test VisualScanPath append error.""" + """Test AOIScanPath append error.""" - visual_scan_path = GazeFeatures.VisualScanPath() + aoi_scan_path = GazeFeatures.AOIScanPath() # Append fixation on A aoi fixation = GazeFeatures.Fixation(random_gaze_positions(10)) ts, _ = fixation.positions.first - new_step = visual_scan_path.append_fixation(ts, fixation, 'A') + new_step = aoi_scan_path.append_fixation(ts, fixation, 'A') - # Check that no visual scan step have been created yet - self.assertEqual(len(visual_scan_path), 0) + # Check that no aoi scan step have been created yet + self.assertEqual(len(aoi_scan_path), 0) self.assertEqual(new_step, None) # Append fixation on B aoi fixation = GazeFeatures.Fixation(random_gaze_positions(10)) ts, _ = fixation.positions.first - # Check that visual scan step creation fail - with self.assertRaises(GazeFeatures.VisualScanStepError): + # Check that aoi scan step creation fail + with self.assertRaises(GazeFeatures.AOIScanStepError): - new_step = visual_scan_path.append_fixation(ts, fixation, 'B') + new_step = aoi_scan_path.append_fixation(ts, fixation, 'B') if __name__ == '__main__': diff --git a/src/argaze/GazeAnalysis/CoefficientK.py b/src/argaze/GazeAnalysis/CoefficientK.py index 724faac..7bcb3b3 100644 --- a/src/argaze/GazeAnalysis/CoefficientK.py +++ b/src/argaze/GazeAnalysis/CoefficientK.py @@ -9,26 +9,26 @@ from argaze import GazeFeatures import numpy @dataclass -class VisualScanPathAnalyzer(GazeFeatures.VisualScanPathAnalyzer): - """Implementation of transition probability matrix algorithm as described by Christophe Lounis in its thesis "Monitor the monitoring: pilot assistance through gaze tracking and visual scanning analyses". +class AOIScanPathAnalyzer(GazeFeatures.AOIScanPathAnalyzer): + """Implementation of transition probability matrix algorithm as described by Christophe Lounis in its thesis "Monitor the monitoring: pilot assistance through gaze tracking and aoi scanning analyses". """ def __post_init__(self): pass - def analyze(self, visual_scan_path: GazeFeatures.VisualScanPathType) -> Any: - """Analyze visual scan.""" + def analyze(self, aoi_scan_path: GazeFeatures.AOIScanPathType) -> Any: + """Analyze aoi scan.""" - assert(len(visual_scan_path) > 1) + assert(len(aoi_scan_path) > 1) durations = [] amplitudes = [] - for visual_scan_step in visual_scan_path: + for aoi_scan_step in aoi_scan_path: - durations.append(visual_scan_step.duration) - amplitudes.append(visual_scan_step.last_saccade.amplitude) + durations.append(aoi_scan_step.duration) + amplitudes.append(aoi_scan_step.last_saccade.amplitude) durations = numpy.array(durations) amplitudes = numpy.array(amplitudes) @@ -40,9 +40,9 @@ class VisualScanPathAnalyzer(GazeFeatures.VisualScanPathAnalyzer): amplitude_std = numpy.std(amplitudes) Ks = [] - for visual_scan_step in visual_scan_path: + for aoi_scan_step in aoi_scan_path: - Ks.append(((visual_scan_step.duration - duration_mean) / duration_std) - ((visual_scan_step.last_saccade.amplitude - amplitude_mean) / amplitude_std)) + Ks.append(((aoi_scan_step.duration - duration_mean) / duration_std) - ((aoi_scan_step.last_saccade.amplitude - amplitude_mean) / amplitude_std)) K = numpy.array(Ks).mean() diff --git a/src/argaze/GazeAnalysis/TransitionProbabilityMatrix.py b/src/argaze/GazeAnalysis/TransitionProbabilityMatrix.py index 55ea43b..9adabc5 100644 --- a/src/argaze/GazeAnalysis/TransitionProbabilityMatrix.py +++ b/src/argaze/GazeAnalysis/TransitionProbabilityMatrix.py @@ -9,7 +9,7 @@ from argaze import GazeFeatures import pandas @dataclass -class VisualScanPathAnalyzer(GazeFeatures.VisualScanPathAnalyzer): +class AOIScanPathAnalyzer(GazeFeatures.AOIScanPathAnalyzer): """Implementation of transition probability matrix algorithm as described in ... """ @@ -17,16 +17,16 @@ class VisualScanPathAnalyzer(GazeFeatures.VisualScanPathAnalyzer): pass - def analyze(self, visual_scan_path: GazeFeatures.VisualScanPathType) -> Any: - """Analyze visual scan.""" + def analyze(self, aoi_scan_path: GazeFeatures.AOIScanPathType) -> Any: + """Analyze aoi scan.""" - assert(len(visual_scan_path) > 1) + assert(len(aoi_scan_path) > 1) sequence = [] - for visual_scan_step in visual_scan_path: + for aoi_scan_step in aoi_scan_path: - sequence.append(visual_scan_step.aoi) + sequence.append(aoi_scan_step.aoi) return pandas.crosstab(pandas.Series(sequence[1:], name='to'), pandas.Series(sequence[:-1], name='from'), normalize=1) diff --git a/src/argaze/GazeFeatures.py b/src/argaze/GazeFeatures.py index fd43824..f0600bd 100644 --- a/src/argaze/GazeFeatures.py +++ b/src/argaze/GazeFeatures.py @@ -307,11 +307,11 @@ class GazeMovementIdentifier(): return ts_fixations, ts_saccades, ts_status -VisualScanStepType = TypeVar('VisualScanStep', bound="VisualScanStep") +AOIScanStepType = TypeVar('AOIScanStep', bound="AOIScanStep") # Type definition for type annotation convenience -class VisualScanStepError(Exception): - """Exception raised at VisualScanStepError creation if a visual scan step doesn't start by a fixation or doesn't end by a saccade.""" +class AOIScanStepError(Exception): + """Exception raised at AOIScanStepError creation if a aoi scan step doesn't start by a fixation or doesn't end by a saccade.""" def __init__(self, message, aoi=''): @@ -320,8 +320,8 @@ class VisualScanStepError(Exception): self.aoi = aoi @dataclass(frozen=True) -class VisualScanStep(): - """Define a visual scan step as a set of successive gaze movements onto a same AOI. +class AOIScanStep(): + """Define a aoi scan step as a set of successive gaze movements onto a same AOI. .. warning:: Visual scan step have to start by a fixation and then end by a saccade.""" @@ -339,12 +339,12 @@ class VisualScanStep(): # First movement have to be a fixation if not is_fixation(self.first_fixation): - raise VisualScanStepError('First step movement is not a fixation', self.aoi) + raise AOIScanStepError('First step movement is not a fixation', self.aoi) # Last movement have to be a saccade if not is_saccade(self.last_saccade): - raise VisualScanStepError('Last step movement is not a saccade', self.aoi) + raise AOIScanStepError('Last step movement is not a saccade', self.aoi) @property def first_fixation(self): @@ -372,11 +372,11 @@ class VisualScanStep(): return last_ts - first_ts -VisualScanPathType = TypeVar('VisualScanPathType', bound="VisualScanPathType") +AOIScanPathType = TypeVar('AOIScanPathType', bound="AOIScanPathType") # Type definition for type annotation convenience -class VisualScanPath(list): - """List of visual scan steps over successive AOI.""" +class AOIScanPath(list): + """List of aoi scan steps over successive AOI.""" def __init__(self): @@ -405,12 +405,12 @@ class VisualScanPath(list): @property def current_aoi(self): - """AOI name of visual scan step under construction""" + """AOI name of aoi scan step under construction""" return self.__current_aoi def append_saccade(self, ts, saccade): - """Append new saccade to visual scan path.""" + """Append new saccade to aoi scan path.""" # Ignore saccade if no fixation have been stored before if len(self.__movements) > 0: @@ -418,10 +418,10 @@ class VisualScanPath(list): self.__movements[ts] = saccade def append_fixation(self, ts, fixation, looked_aoi: str) -> bool: - """Append new fixation to visual scan path and return last new visual scan step if one have been created. + """Append new fixation to aoi scan path and return last new aoi scan step if one have been created. .. warning:: - It could raise VisualScanStepError""" + It could raise AOIScanStepError""" # Is it fixation onto a new aoi? if looked_aoi != self.__current_aoi and len(self.__movements) > 0: @@ -429,7 +429,7 @@ class VisualScanPath(list): try: # Edit new step - new_step = VisualScanStep(self.__movements, self.__current_aoi) + new_step = AOIScanStep(self.__movements, self.__current_aoi) # Append new step super().append(new_step) @@ -457,10 +457,10 @@ class VisualScanPath(list): return None -class VisualScanPathAnalyzer(): - """Abstract class to define what should provide a visual scan path analyzer.""" +class AOIScanPathAnalyzer(): + """Abstract class to define what should provide a aoi scan path analyzer.""" - def analyze(self, visual_scan_path: VisualScanPathType) -> Any: - """Analyze visual scan path.""" + def analyze(self, aoi_scan_path: AOIScanPathType) -> Any: + """Analyze aoi scan path.""" raise NotImplementedError('analyze() method not implemented') diff --git a/src/argaze/utils/demo_gaze_features_run.py b/src/argaze/utils/demo_gaze_features_run.py index 4fdc10d..022ad59 100644 --- a/src/argaze/utils/demo_gaze_features_run.py +++ b/src/argaze/utils/demo_gaze_features_run.py @@ -54,12 +54,12 @@ def main(): } identification_mode = 'I-DT' - visual_scan_path = GazeFeatures.VisualScanPath() + aoi_scan_path = GazeFeatures.AOIScanPath() - tpm = TransitionProbabilityMatrix.VisualScanPathAnalyzer() + tpm = TransitionProbabilityMatrix.AOIScanPathAnalyzer() tpm_analysis = pandas.DataFrame() - cK = CoefficientK.VisualScanPathAnalyzer() + cK = CoefficientK.AOIScanPathAnalyzer() cK_analysis = 0 gaze_movement_lock = threading.Lock() @@ -107,24 +107,24 @@ def main(): try: - # Append fixation to visual scan path - new_step = visual_scan_path.append_fixation(data_ts, gaze_movement, look_at) + # Append fixation to aoi scan path + new_step = aoi_scan_path.append_fixation(data_ts, gaze_movement, look_at) # Analyse transition probabilities - if new_step and len(visual_scan_path) > 1: + if new_step and len(aoi_scan_path) > 1: - tpm_analysis = tpm.analyze(visual_scan_path) + tpm_analysis = tpm.analyze(aoi_scan_path) - cK_analysis = cK.analyze(visual_scan_path) + cK_analysis = cK.analyze(aoi_scan_path) - except GazeFeatures.VisualScanStepError as e: + except GazeFeatures.AOIScanStepError as e: print(f'Error on {e.aoi} step:', e) elif GazeFeatures.is_saccade(gaze_movement): - # Append saccade to visual scan path - visual_scan_path.append_saccade(data_ts, gaze_movement) + # Append saccade to aoi scan path + aoi_scan_path.append_saccade(data_ts, gaze_movement) # Unlock gaze movement exploitation gaze_movement_lock.release() @@ -198,11 +198,11 @@ def main(): # Draw movement from start to next cv2.line(aoi_matrix, start_gaze_position, next_gaze_position, (0, 0, 255), 1) - # Write last 5 steps of visual scan path + # Write last 5 steps of aoi scan path path = '' - for step in visual_scan_path[-5:]: + for step in aoi_scan_path[-5:]: path += f'> {step.aoi} ' - path += f'> {visual_scan_path.current_aoi}' + path += f'> {aoi_scan_path.current_aoi}' cv2.putText(aoi_matrix, path, (20, window_size[1]-40), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 1, cv2.LINE_AA) -- cgit v1.1