From 63c302e81a9fb94b6953b1d71e4da80606dd8752 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Sun, 11 Dec 2022 05:14:57 +0100 Subject: Adding build_gaze_saccade function for testing purpose. --- .../DispersionBasedGazeMovementIdentifier.py | 95 +++++++++++++++++++++- 1 file changed, 92 insertions(+), 3 deletions(-) (limited to 'src/argaze.test/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py') diff --git a/src/argaze.test/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py b/src/argaze.test/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py index 7909362..c731cef 100644 --- a/src/argaze.test/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py +++ b/src/argaze.test/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py @@ -45,9 +45,45 @@ def build_gaze_fixation(size: int, center: tuple, dispersion: float, start_time: return ts_gaze_positions +def build_gaze_saccade(size: int, center_A: tuple, center_B: tuple, start_time: float, min_time: float, max_time: float, validity: list = []): + """ Generate N TimeStampedGazePsoitions between 2 center points for testing purpose. + Timestamps are current time after random sleep (second). + GazePositions are random values. + """ + ts_gaze_positions = GazeFeatures.TimeStampedGazePositions() + + for i in range(0, size): + + # Check position validity + valid = True + if len(validity) > i: + + valid = validity[i] + + if valid: + + # Edit gaze position + move_x = center_A[0] + (center_B[0] - center_A[0]) * (i / size) + move_y = center_A[1] + (center_B[1] - center_A[1]) * (i / size) + gaze_position = GazeFeatures.GazePosition((move_x, move_y)) + + else: + + gaze_position = GazeFeatures.UnvalidGazePosition() + + # Store gaze position + ts = time.time() - start_time + ts_gaze_positions[ts] = gaze_position + + # Sleep a random time + sleep_time = random.random() * (max_time - min_time) + min_time + time.sleep(sleep_time) + + return ts_gaze_positions + class TestDispersionBasedGazeMovementIdentifierClass(unittest.TestCase): """Test DispersionBasedGazeMovementIdentifier class.""" - + def test_fixation_identification(self): """Test DispersionBasedGazeMovementIdentifier fixation identification.""" @@ -76,7 +112,7 @@ class TestDispersionBasedGazeMovementIdentifierClass(unittest.TestCase): self.assertGreaterEqual(fixation.duration, size * min_time) self.assertLessEqual(fixation.duration, size * max_time) - def test_fixation_and_saccade_identification(self): + def test_fixation_and_direct_saccade_identification(self): """Test DispersionBasedGazeMovementIdentifier fixation and saccade identification.""" size = 10 @@ -123,7 +159,60 @@ class TestDispersionBasedGazeMovementIdentifierClass(unittest.TestCase): self.assertLessEqual(fixation.dispersion, dispersion) self.assertGreaterEqual(fixation.duration, size * min_time) self.assertLessEqual(fixation.duration, size * max_time) - + ''' + def test_fixation_and_short_saccade_identification(self): + """Test DispersionBasedGazeMovementIdentifier fixation and saccade identification.""" + + size = 10 + move = 2 + center_A = (0, 0) + out_A = (20, 20) + center_B = (50, 50) + dispersion = 10 + start_time = time.time() + min_time = 0.01 + max_time = 0.1 + + ts_gaze_positions_A = build_gaze_fixation(size, center_A, dispersion, start_time, min_time, max_time) + ts_move_positions = build_gaze_saccade(move, out_A, center_B, start_time, min_time, min_time) + ts_gaze_positions_B = build_gaze_fixation(size, center_B, dispersion, start_time, min_time, max_time) + + print(ts_move_positions) + + ts_gaze_positions = ts_gaze_positions_A.append(ts_move_positions).append(ts_gaze_positions_B) + + gaze_movement_identifier = DispersionBasedGazeMovementIdentifier.GazeMovementIdentifier(dispersion_threshold=dispersion, duration_threshold=max_time*2) + ts_fixations, ts_saccades, ts_unknown, ts_status = gaze_movement_identifier.identify(ts_gaze_positions) + + # Check result size + self.assertEqual(len(ts_fixations), 2) + self.assertEqual(len(ts_saccades), 1) + self.assertEqual(len(ts_unknown), 0) + self.assertEqual(len(ts_status), size*2 + move) + + # Check first fixation + ts, fixation = ts_fixations.pop_first() + + self.assertEqual(len(fixation.positions.keys()), size-1) + self.assertLessEqual(fixation.dispersion, dispersion) + self.assertGreaterEqual(fixation.duration, size * min_time) + self.assertLessEqual(fixation.duration, size * max_time) + + # Check first saccade + ts, saccade = ts_saccades.pop_first() + + self.assertEqual(len(saccade.positions.keys()), move + 2) + self.assertGreaterEqual(saccade.duration, min_time) + self.assertLessEqual(saccade.duration, max_time) + + # Check second fixation + ts, fixation = ts_fixations.pop_first() + + self.assertEqual(len(fixation.positions.keys()), size-1) + self.assertLessEqual(fixation.dispersion, dispersion) + self.assertGreaterEqual(fixation.duration, size * min_time) + self.assertLessEqual(fixation.duration, size * max_time) + ''' def test_invalid_gaze_position(self): """Test DispersionBasedGazeMovementIdentifier fixation and saccade identification with invalid gaze position.""" -- cgit v1.1