From e35e90d161ffb9202459631a0049448cde905b3c Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Wed, 31 May 2023 15:35:28 +0200 Subject: Testing all gaze analysis algorithm. Unifying paper citation. --- src/argaze.test/GazeFeatures.py | 72 +++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 24 deletions(-) (limited to 'src/argaze.test/GazeFeatures.py') diff --git a/src/argaze.test/GazeFeatures.py b/src/argaze.test/GazeFeatures.py index 8206baf..f73eefe 100644 --- a/src/argaze.test/GazeFeatures.py +++ b/src/argaze.test/GazeFeatures.py @@ -8,12 +8,13 @@ __copyright__ = "Copyright 2023, Ecole Nationale de l'Aviation Civile (ENAC)" __license__ = "BSD" import unittest +from dataclasses import dataclass from argaze import GazeFeatures import numpy -def random_gaze_positions(size): +def random_gaze_positions(size, screen_dimension: tuple[float, float] = (1, 1)): """ Generate random TimeStampedGazePsoitions for testing purpose. Timestamps are current time. GazePositions are random values. @@ -27,13 +28,36 @@ def random_gaze_positions(size): for i in range(0, size): # Edit gaze position - random_gaze_position = GazeFeatures.GazePosition((random.random(), random.random())) + random_gaze_position = GazeFeatures.GazePosition((random.random() * screen_dimension[0], random.random() * screen_dimension[1])) # Store gaze position ts_gaze_positions[time.time()] = random_gaze_position return ts_gaze_positions +@dataclass(frozen=True) +class TestFixation(GazeFeatures.Fixation): + """Define basic fixation class for test.""" + + def __post_init__(self): + + super().__post_init__() + + points = self.positions.values() + points_x, points_y = [p[0] for p in points], [p[1] for p in points] + points_array = numpy.column_stack([points_x, points_y]) + centroid_array = numpy.array([numpy.mean(points_x), numpy.mean(points_y)]) + + # Update frozen focus attribute using centroid + object.__setattr__(self, 'focus', (centroid_array[0], centroid_array[1])) + +@dataclass(frozen=True) +class TestSaccade(GazeFeatures.Saccade): + """Define basic saccade for test.""" + + def __post_init__(self): + super().__post_init__() + class TestGazePositionClass(unittest.TestCase): """Test GazePosition class.""" @@ -222,8 +246,8 @@ class TestScanStepClass(unittest.TestCase): def test_new(self): """Test ScanStep creation.""" - fixation = GazeFeatures.Fixation(random_gaze_positions(10)) - saccade = GazeFeatures.Saccade(random_gaze_positions(2)) + fixation = TestFixation(random_gaze_positions(10)) + saccade = TestSaccade(random_gaze_positions(2)) scan_step = GazeFeatures.ScanStep(fixation, saccade) @@ -232,18 +256,18 @@ class TestScanStepClass(unittest.TestCase): self.assertEqual(scan_step.last_saccade, saccade) self.assertGreater(scan_step.duration, 0) -def build_scan_path(size): +def build_scan_path(size, screen_dimension: tuple[float, float] = (1, 1)): """Build scan path""" scan_path = GazeFeatures.ScanPath() for i in range(size): - fixation = GazeFeatures.Fixation(random_gaze_positions(10)) + fixation = TestFixation(random_gaze_positions(10, screen_dimension)) ts, _ = fixation.positions.first scan_path.append_fixation(ts, fixation) - saccade = GazeFeatures.Saccade(random_gaze_positions(2)) + saccade = TestSaccade(random_gaze_positions(2, screen_dimension)) ts, _ = saccade.positions.first scan_path.append_saccade(ts, saccade) @@ -266,7 +290,7 @@ class TestScanPathClass(unittest.TestCase): scan_path = GazeFeatures.ScanPath() # Append a saccade that should be ignored - saccade = GazeFeatures.Saccade(random_gaze_positions(2)) + saccade = TestSaccade(random_gaze_positions(2)) ts, _ = saccade.positions.first new_step = scan_path.append_saccade(ts, saccade) @@ -276,7 +300,7 @@ class TestScanPathClass(unittest.TestCase): self.assertEqual(new_step, None) # Append first fixation - fixation_A = GazeFeatures.Fixation(random_gaze_positions(10)) + fixation_A = TestFixation(random_gaze_positions(10)) ts, _ = fixation_A.positions.first new_step = scan_path.append_fixation(ts, fixation_A) @@ -286,7 +310,7 @@ class TestScanPathClass(unittest.TestCase): self.assertEqual(new_step, None) # Append consecutive saccade - saccade_A = GazeFeatures.Saccade(random_gaze_positions(2)) + saccade_A = TestSaccade(random_gaze_positions(2)) ts, _ = saccade_A.positions.first new_step = scan_path.append_saccade(ts, saccade_A) @@ -297,7 +321,7 @@ class TestScanPathClass(unittest.TestCase): self.assertEqual(new_step.last_saccade, saccade_A) # Append 2 consecutive fixations then a saccade - fixation_B1 = GazeFeatures.Fixation(random_gaze_positions(10)) + fixation_B1 = TestFixation(random_gaze_positions(10)) ts, _ = fixation_B1.positions.first new_step = scan_path.append_fixation(ts, fixation_B1) @@ -306,7 +330,7 @@ class TestScanPathClass(unittest.TestCase): self.assertEqual(len(scan_path), 1) self.assertEqual(new_step, None) - fixation_B2 = GazeFeatures.Fixation(random_gaze_positions(10)) + fixation_B2 = TestFixation(random_gaze_positions(10)) ts, _ = fixation_B2.positions.first new_step = scan_path.append_fixation(ts, fixation_B2) @@ -315,7 +339,7 @@ class TestScanPathClass(unittest.TestCase): self.assertEqual(len(scan_path), 1) self.assertEqual(new_step, None) - saccade_B = GazeFeatures.Saccade(random_gaze_positions(2)) + saccade_B = TestSaccade(random_gaze_positions(2)) ts, _ = saccade_B.positions.first new_step = scan_path.append_saccade(ts, saccade_B) @@ -333,11 +357,11 @@ class TestAOIScanStepClass(unittest.TestCase): movements = GazeFeatures.TimeStampedGazeMovements() - fixation = GazeFeatures.Fixation(random_gaze_positions(10)) + fixation = TestFixation(random_gaze_positions(10)) ts, _ = fixation.positions.first movements[ts] = fixation - saccade = GazeFeatures.Saccade(random_gaze_positions(2)) + saccade = TestSaccade(random_gaze_positions(2)) ts, _ = saccade.positions.first movements[ts] = saccade @@ -355,11 +379,11 @@ class TestAOIScanStepClass(unittest.TestCase): movements = GazeFeatures.TimeStampedGazeMovements() - saccade = GazeFeatures.Saccade(random_gaze_positions(2)) + saccade = TestSaccade(random_gaze_positions(2)) ts, _ = saccade.positions.first movements[ts] = saccade - fixation = GazeFeatures.Fixation(random_gaze_positions(10)) + fixation = TestFixation(random_gaze_positions(10)) ts, _ = fixation.positions.first movements[ts] = fixation @@ -378,11 +402,11 @@ def build_aoi_scan_path(expected_aois, aoi_path): for aoi in aoi_path: - fixation = GazeFeatures.Fixation(random_gaze_positions(10)) + fixation = TestFixation(random_gaze_positions(10)) ts, _ = fixation.positions.first aoi_scan_path.append_fixation(ts, fixation, aoi) - saccade = GazeFeatures.Saccade(random_gaze_positions(2)) + saccade = TestSaccade(random_gaze_positions(2)) ts, _ = saccade.positions.first aoi_scan_path.append_saccade(ts, saccade) @@ -405,7 +429,7 @@ class TestAOIScanPathClass(unittest.TestCase): aoi_scan_path = GazeFeatures.AOIScanPath(['Foo', 'Bar']) # Append fixation on A aoi - fixation = GazeFeatures.Fixation(random_gaze_positions(10)) + fixation = TestFixation(random_gaze_positions(10)) ts, _ = fixation.positions.first new_step = aoi_scan_path.append_fixation(ts, fixation, 'Foo') @@ -415,7 +439,7 @@ class TestAOIScanPathClass(unittest.TestCase): self.assertEqual(new_step, None) # Append saccade - saccade = GazeFeatures.Saccade(random_gaze_positions(2)) + saccade = TestSaccade(random_gaze_positions(2)) ts, _ = saccade.positions.first new_step = aoi_scan_path.append_saccade(ts, saccade) @@ -425,7 +449,7 @@ class TestAOIScanPathClass(unittest.TestCase): self.assertEqual(new_step, None) # Append fixation on B aoi - fixation = GazeFeatures.Fixation(random_gaze_positions(10)) + fixation = TestFixation(random_gaze_positions(10)) ts, _ = fixation.positions.first new_step = aoi_scan_path.append_fixation(ts, fixation, 'Bar') @@ -445,7 +469,7 @@ class TestAOIScanPathClass(unittest.TestCase): aoi_scan_path = GazeFeatures.AOIScanPath(['Foo', 'Bar']) # Append fixation on A aoi - fixation = GazeFeatures.Fixation(random_gaze_positions(10)) + fixation = TestFixation(random_gaze_positions(10)) ts, _ = fixation.positions.first new_step = aoi_scan_path.append_fixation(ts, fixation, 'Foo') @@ -455,7 +479,7 @@ class TestAOIScanPathClass(unittest.TestCase): self.assertEqual(new_step, None) # Append fixation on B aoi - fixation = GazeFeatures.Fixation(random_gaze_positions(10)) + fixation = TestFixation(random_gaze_positions(10)) ts, _ = fixation.positions.first # Check that aoi scan step creation fail when fixation is appened after another fixation -- cgit v1.1