diff options
Diffstat (limited to 'src/argaze.test/GazeAnalysis')
-rw-r--r-- | src/argaze.test/GazeAnalysis/VelocityThresholdIdentification.py | 514 |
1 files changed, 257 insertions, 257 deletions
diff --git a/src/argaze.test/GazeAnalysis/VelocityThresholdIdentification.py b/src/argaze.test/GazeAnalysis/VelocityThresholdIdentification.py index e7431b5..9bb07cb 100644 --- a/src/argaze.test/GazeAnalysis/VelocityThresholdIdentification.py +++ b/src/argaze.test/GazeAnalysis/VelocityThresholdIdentification.py @@ -28,301 +28,301 @@ from argaze.GazeAnalysis import VelocityThresholdIdentification import numpy def build_gaze_fixation(size: int, center: tuple, deviation_max: float, min_time: float, max_time: float, start_ts: float = 0., validity: list = []): - """ Generate N TimeStampedGazePsoitions dispersed around a center point for testing purpose. - Timestamps are current time after random sleep (second). - GazePositions are random values. - """ - ts_gaze_positions = GazeFeatures.TimeStampedGazePositions() + """ Generate N TimeStampedGazePsoitions dispersed around a center point for testing purpose. + Timestamps are current time after random sleep (second). + GazePositions are random values. + """ + ts_gaze_positions = GazeFeatures.TimeStampedGazePositions() - start_time = time.time() + start_time = time.time() - for i in range(0, size): + for i in range(0, size): - # Sleep a random time - sleep_time = random.random() * (max_time - min_time) + min_time - time.sleep(sleep_time) + # Sleep a random time + sleep_time = random.random() * (max_time - min_time) + min_time + time.sleep(sleep_time) - # Check position validity - valid = True - if len(validity) > i: + # Check position validity + valid = True + if len(validity) > i: - valid = validity[i] + valid = validity[i] - if valid: + if valid: - # Edit gaze position - random_x = center[0] + deviation_max * (random.random() - 0.5) / math.sqrt(2) - random_y = center[1] + deviation_max * (random.random() - 0.5) / math.sqrt(2) - gaze_position = GazeFeatures.GazePosition((random_x, random_y)) + # Edit gaze position + random_x = center[0] + deviation_max * (random.random() - 0.5) / math.sqrt(2) + random_y = center[1] + deviation_max * (random.random() - 0.5) / math.sqrt(2) + gaze_position = GazeFeatures.GazePosition((random_x, random_y)) - else: + else: - gaze_position = GazeFeatures.GazePosition() + gaze_position = GazeFeatures.GazePosition() - # Timestamp gaze position - gaze_position.timestamp = time.time() - start_time + start_ts + # Timestamp gaze position + gaze_position.timestamp = time.time() - start_time + start_ts - # Store gaze position - ts_gaze_positions.append(gaze_position) + # Store gaze position + ts_gaze_positions.append(gaze_position) - return ts_gaze_positions + return ts_gaze_positions def build_gaze_saccade(size: int, center_A: tuple, center_B: tuple, min_time: float, max_time: float, start_ts: float = 0., 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() + """ 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() - start_time = time.time() + start_time = time.time() - for i in range(0, size): + for i in range(0, size): - # Sleep a random time - sleep_time = random.random() * (max_time - min_time) + min_time - time.sleep(sleep_time) + # Sleep a random time + sleep_time = random.random() * (max_time - min_time) + min_time + time.sleep(sleep_time) - # Check position validity - valid = True - if len(validity) > i: + # Check position validity + valid = True + if len(validity) > i: - valid = validity[i] + valid = validity[i] - if valid: + 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)) + # 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: + else: - gaze_position = GazeFeatures.GazePosition() + gaze_position = GazeFeatures.GazePosition() - # Timestamp gaze position - gaze_position.timestamp = time.time() - start_time + start_ts + # Timestamp gaze position + gaze_position.timestamp = time.time() - start_time + start_ts - # Store gaze position - ts_gaze_positions.append(gaze_position) + # Store gaze position + ts_gaze_positions.append(gaze_position) - return ts_gaze_positions + return ts_gaze_positions class TestVelocityThresholdIdentificationClass(unittest.TestCase): - """Test VelocityThresholdIdentification class.""" - - def test_fixation_identification(self): - """Test VelocityThresholdIdentification fixation identification.""" - - size = 10 - center = (0, 0) - deviation_max = 10 - min_time = 0.05 - max_time = 0.1 - velocity_max = deviation_max / min_time - - ts_gaze_positions = build_gaze_fixation(size, center, deviation_max, min_time, max_time) - gaze_movement_identifier = VelocityThresholdIdentification.GazeMovementIdentifier(velocity_max_threshold=velocity_max, duration_min_threshold=max_time*2) - ts_fixations, ts_saccades, ts_status = gaze_movement_identifier.browse(ts_gaze_positions) - - # Check result size - self.assertEqual(len(ts_fixations), 1) - self.assertEqual(len(ts_saccades), 0) - self.assertEqual(len(ts_status), size - 1) - - # Check fixation - fixation = ts_fixations.pop(0) - - self.assertEqual(len(fixation), size - 1) - self.assertGreaterEqual(fixation.duration, (size - 2) * min_time) - self.assertLessEqual(fixation.duration, (size - 2) * max_time) - self.assertLessEqual(fixation.is_finished(), True) - - def test_fixation_and_direct_saccade_identification(self): - """Test VelocityThresholdIdentification fixation and saccade identification.""" - - size = 10 - center_A = (0, 0) - center_B = (500, 500) - deviation_max = 10 - min_time = 0.05 - max_time = 0.1 - velocity_max = deviation_max / min_time - - ts_gaze_positions_A = build_gaze_fixation(size, center_A, deviation_max, min_time, max_time) - ts_gaze_positions_B = build_gaze_fixation(size, center_B, deviation_max, min_time, max_time, start_ts=ts_gaze_positions_A[-1].timestamp) - - ts_gaze_positions = ts_gaze_positions_A + ts_gaze_positions_B - - gaze_movement_identifier = VelocityThresholdIdentification.GazeMovementIdentifier(velocity_max_threshold=velocity_max, duration_min_threshold=max_time*2) - ts_fixations, ts_saccades, ts_status = gaze_movement_identifier.browse(ts_gaze_positions) - - # Check result size - self.assertEqual(len(ts_fixations), 2) - self.assertEqual(len(ts_saccades), 1) - self.assertEqual(len(ts_status), size * 2 - 1) - - # Check first fixation - fixation = ts_fixations.pop(0) - - self.assertEqual(len(fixation), size - 1) - self.assertGreaterEqual(fixation.duration, (size - 2) * min_time) - self.assertLessEqual(fixation.duration, (size - 2) * max_time) - self.assertLessEqual(fixation.is_finished(), True) - - # Check first saccade - saccade = ts_saccades.pop(0) - - self.assertEqual(len(saccade), 2) - self.assertGreaterEqual(saccade.duration, min_time) - self.assertLessEqual(saccade.duration, max_time) - self.assertLessEqual(saccade.is_finished(), True) - - # Check that last position of a movement is equal to first position of next movement - self.assertEqual(fixation[-1].timestamp, saccade[0].timestamp) - self.assertEqual(fixation[-1].value, saccade[0].value) - - # Check second fixation - fixation = ts_fixations.pop(0) - - self.assertEqual(len(fixation), size) - self.assertGreaterEqual(fixation.duration, (size - 1) * min_time) - self.assertLessEqual(fixation.duration, (size - 1) * max_time) - self.assertLessEqual(fixation.is_finished(), True) - - # Check that last position of a movement is equal to first position of next movement - self.assertEqual(saccade[-1].timestamp, fixation[0].timestamp) - self.assertEqual(saccade[-1].value, fixation[0].value) - - def test_fixation_and_short_saccade_identification(self): - """Test VelocityThresholdIdentification fixation and saccade identification.""" - - size = 10 - move = 2 - center_A = (0, 0) - out_A = (10, 10) - center_B = (50, 50) - deviation_max = 10 - min_time = 0.05 - max_time = 0.1 - velocity_max = deviation_max / min_time - - ts_gaze_positions_A = build_gaze_fixation(size, center_A, deviation_max, min_time, max_time) - ts_move_positions = build_gaze_saccade(move, out_A, center_B, min_time, min_time, start_ts=ts_gaze_positions_A[-1].timestamp) - ts_gaze_positions_B = build_gaze_fixation(size, center_B, deviation_max, min_time, max_time, start_ts=ts_move_positions[-1].timestamp) - - ts_gaze_positions = ts_gaze_positions_A + ts_move_positions + ts_gaze_positions_B - - gaze_movement_identifier = VelocityThresholdIdentification.GazeMovementIdentifier(velocity_max_threshold=velocity_max, duration_min_threshold=max_time*2) - ts_fixations, ts_saccades, ts_status = gaze_movement_identifier.browse(ts_gaze_positions) - - # Check result size - self.assertEqual(len(ts_fixations), 2) - self.assertEqual(len(ts_saccades), 1) - self.assertEqual(len(ts_status), 2 * size + move - 1) - - # Check first fixation - fixation = ts_fixations.pop(0) - - self.assertEqual(len(fixation), size - 1) # BUG: NOT ALWAYS TRUE !!! - self.assertGreaterEqual(fixation.duration, (size - 2) * min_time) - self.assertLessEqual(fixation.duration, (size - 2) * max_time) - self.assertLessEqual(fixation.is_finished(), True) - - # Check first saccade - saccade = ts_saccades.pop(0) - - self.assertEqual(len(saccade), move + 2) - self.assertGreaterEqual(saccade.duration, (move + 1) * min_time) - self.assertLessEqual(saccade.duration, (move + 1) * max_time) - self.assertLessEqual(saccade.is_finished(), True) - - # Check that last position of a movement is equal to first position of next movement - self.assertEqual(fixation[-1].timestamp, saccade[0].timestamp) - self.assertEqual(fixation[-1].value, saccade[0].value) - - # Check second fixation - fixation = ts_fixations.pop(0) - - self.assertEqual(len(fixation), size) - self.assertGreaterEqual(fixation.duration, (size - 1) * min_time) - self.assertLessEqual(fixation.duration, (size - 1) * max_time) - self.assertLessEqual(fixation.is_finished(), True) - - # Check that last position of a movement is equal to first position of next movement - self.assertEqual(saccade[-1], fixation[0]) - self.assertEqual(saccade[-1].value, fixation[0].value) - - def test_invalid_gaze_position(self): - """Test VelocityThresholdIdentification fixation and saccade identification with invalid gaze position.""" - - size = 15 - center = (0, 0) - deviation_max = 10 - min_time = 0.05 - max_time = 0.1 - velocity_max = deviation_max / min_time - validity = [True, True, True, True, True, True, True, False, False, False, True, True, True, True, True] - - ts_gaze_positions = build_gaze_fixation(size, center, deviation_max, min_time, max_time, validity=validity) - - gaze_movement_identifier = VelocityThresholdIdentification.GazeMovementIdentifier(velocity_max_threshold=velocity_max, duration_min_threshold=max_time*2) - ts_fixations, ts_saccades, ts_status = gaze_movement_identifier.browse(ts_gaze_positions) - - # Check result size - self.assertEqual(len(ts_fixations), 2) - self.assertEqual(len(ts_saccades), 0) - self.assertEqual(len(ts_status), len(validity)-5) - - # Check first fixation - fixation = ts_fixations.pop(0) - - self.assertEqual(len(fixation), 6) - self.assertGreaterEqual(fixation.duration, 5 * min_time) - self.assertLessEqual(fixation.duration, 5 * max_time) - self.assertLessEqual(fixation.is_finished(), True) + """Test VelocityThresholdIdentification class.""" + + def test_fixation_identification(self): + """Test VelocityThresholdIdentification fixation identification.""" + + size = 10 + center = (0, 0) + deviation_max = 10 + min_time = 0.05 + max_time = 0.1 + velocity_max = deviation_max / min_time + + ts_gaze_positions = build_gaze_fixation(size, center, deviation_max, min_time, max_time) + gaze_movement_identifier = VelocityThresholdIdentification.GazeMovementIdentifier(velocity_max_threshold=velocity_max, duration_min_threshold=max_time*2) + ts_fixations, ts_saccades, ts_status = gaze_movement_identifier.browse(ts_gaze_positions) + + # Check result size + self.assertEqual(len(ts_fixations), 1) + self.assertEqual(len(ts_saccades), 0) + self.assertEqual(len(ts_status), size - 1) + + # Check fixation + fixation = ts_fixations.pop(0) + + self.assertEqual(len(fixation), size - 1) + self.assertGreaterEqual(fixation.duration, (size - 2) * min_time) + self.assertLessEqual(fixation.duration, (size - 2) * max_time) + self.assertLessEqual(fixation.is_finished(), True) + + def test_fixation_and_direct_saccade_identification(self): + """Test VelocityThresholdIdentification fixation and saccade identification.""" + + size = 10 + center_A = (0, 0) + center_B = (500, 500) + deviation_max = 10 + min_time = 0.05 + max_time = 0.1 + velocity_max = deviation_max / min_time + + ts_gaze_positions_A = build_gaze_fixation(size, center_A, deviation_max, min_time, max_time) + ts_gaze_positions_B = build_gaze_fixation(size, center_B, deviation_max, min_time, max_time, start_ts=ts_gaze_positions_A[-1].timestamp) + + ts_gaze_positions = ts_gaze_positions_A + ts_gaze_positions_B + + gaze_movement_identifier = VelocityThresholdIdentification.GazeMovementIdentifier(velocity_max_threshold=velocity_max, duration_min_threshold=max_time*2) + ts_fixations, ts_saccades, ts_status = gaze_movement_identifier.browse(ts_gaze_positions) + + # Check result size + self.assertEqual(len(ts_fixations), 2) + self.assertEqual(len(ts_saccades), 1) + self.assertEqual(len(ts_status), size * 2 - 1) + + # Check first fixation + fixation = ts_fixations.pop(0) + + self.assertEqual(len(fixation), size - 1) + self.assertGreaterEqual(fixation.duration, (size - 2) * min_time) + self.assertLessEqual(fixation.duration, (size - 2) * max_time) + self.assertLessEqual(fixation.is_finished(), True) + + # Check first saccade + saccade = ts_saccades.pop(0) + + self.assertEqual(len(saccade), 2) + self.assertGreaterEqual(saccade.duration, min_time) + self.assertLessEqual(saccade.duration, max_time) + self.assertLessEqual(saccade.is_finished(), True) + + # Check that last position of a movement is equal to first position of next movement + self.assertEqual(fixation[-1].timestamp, saccade[0].timestamp) + self.assertEqual(fixation[-1].value, saccade[0].value) + + # Check second fixation + fixation = ts_fixations.pop(0) + + self.assertEqual(len(fixation), size) + self.assertGreaterEqual(fixation.duration, (size - 1) * min_time) + self.assertLessEqual(fixation.duration, (size - 1) * max_time) + self.assertLessEqual(fixation.is_finished(), True) + + # Check that last position of a movement is equal to first position of next movement + self.assertEqual(saccade[-1].timestamp, fixation[0].timestamp) + self.assertEqual(saccade[-1].value, fixation[0].value) + + def test_fixation_and_short_saccade_identification(self): + """Test VelocityThresholdIdentification fixation and saccade identification.""" + + size = 10 + move = 2 + center_A = (0, 0) + out_A = (10, 10) + center_B = (50, 50) + deviation_max = 10 + min_time = 0.05 + max_time = 0.1 + velocity_max = deviation_max / min_time + + ts_gaze_positions_A = build_gaze_fixation(size, center_A, deviation_max, min_time, max_time) + ts_move_positions = build_gaze_saccade(move, out_A, center_B, min_time, min_time, start_ts=ts_gaze_positions_A[-1].timestamp) + ts_gaze_positions_B = build_gaze_fixation(size, center_B, deviation_max, min_time, max_time, start_ts=ts_move_positions[-1].timestamp) + + ts_gaze_positions = ts_gaze_positions_A + ts_move_positions + ts_gaze_positions_B + + gaze_movement_identifier = VelocityThresholdIdentification.GazeMovementIdentifier(velocity_max_threshold=velocity_max, duration_min_threshold=max_time*2) + ts_fixations, ts_saccades, ts_status = gaze_movement_identifier.browse(ts_gaze_positions) + + # Check result size + self.assertEqual(len(ts_fixations), 2) + self.assertEqual(len(ts_saccades), 1) + self.assertEqual(len(ts_status), 2 * size + move - 1) + + # Check first fixation + fixation = ts_fixations.pop(0) + + self.assertEqual(len(fixation), size - 1) # BUG: NOT ALWAYS TRUE !!! + self.assertGreaterEqual(fixation.duration, (size - 2) * min_time) + self.assertLessEqual(fixation.duration, (size - 2) * max_time) + self.assertLessEqual(fixation.is_finished(), True) + + # Check first saccade + saccade = ts_saccades.pop(0) + + self.assertEqual(len(saccade), move + 2) + self.assertGreaterEqual(saccade.duration, (move + 1) * min_time) + self.assertLessEqual(saccade.duration, (move + 1) * max_time) + self.assertLessEqual(saccade.is_finished(), True) + + # Check that last position of a movement is equal to first position of next movement + self.assertEqual(fixation[-1].timestamp, saccade[0].timestamp) + self.assertEqual(fixation[-1].value, saccade[0].value) + + # Check second fixation + fixation = ts_fixations.pop(0) + + self.assertEqual(len(fixation), size) + self.assertGreaterEqual(fixation.duration, (size - 1) * min_time) + self.assertLessEqual(fixation.duration, (size - 1) * max_time) + self.assertLessEqual(fixation.is_finished(), True) + + # Check that last position of a movement is equal to first position of next movement + self.assertEqual(saccade[-1], fixation[0]) + self.assertEqual(saccade[-1].value, fixation[0].value) + + def test_invalid_gaze_position(self): + """Test VelocityThresholdIdentification fixation and saccade identification with invalid gaze position.""" + + size = 15 + center = (0, 0) + deviation_max = 10 + min_time = 0.05 + max_time = 0.1 + velocity_max = deviation_max / min_time + validity = [True, True, True, True, True, True, True, False, False, False, True, True, True, True, True] + + ts_gaze_positions = build_gaze_fixation(size, center, deviation_max, min_time, max_time, validity=validity) + + gaze_movement_identifier = VelocityThresholdIdentification.GazeMovementIdentifier(velocity_max_threshold=velocity_max, duration_min_threshold=max_time*2) + ts_fixations, ts_saccades, ts_status = gaze_movement_identifier.browse(ts_gaze_positions) + + # Check result size + self.assertEqual(len(ts_fixations), 2) + self.assertEqual(len(ts_saccades), 0) + self.assertEqual(len(ts_status), len(validity)-5) + + # Check first fixation + fixation = ts_fixations.pop(0) + + self.assertEqual(len(fixation), 6) + self.assertGreaterEqual(fixation.duration, 5 * min_time) + self.assertLessEqual(fixation.duration, 5 * max_time) + self.assertLessEqual(fixation.is_finished(), True) - # Check second fixation - fixation = ts_fixations.pop(0) - - self.assertEqual(len(fixation), 4) - self.assertGreaterEqual(fixation.duration, 3 * min_time) - self.assertLessEqual(fixation.duration, 3 * max_time) - self.assertLessEqual(fixation.is_finished(), True) + # Check second fixation + fixation = ts_fixations.pop(0) + + self.assertEqual(len(fixation), 4) + self.assertGreaterEqual(fixation.duration, 3 * min_time) + self.assertLessEqual(fixation.duration, 3 * max_time) + self.assertLessEqual(fixation.is_finished(), True) - def test_identification_browsing(self): - """Test VelocityThresholdIdentification identification browsing.""" - - size = 10 - center_A = (0, 0) - center_B = (50, 50) - deviation_max = 10 - min_time = 0.01 - max_time = 0.1 - velocity_max = deviation_max / min_time - - ts_gaze_positions_A = build_gaze_fixation(size, center_A, deviation_max, min_time, max_time) - ts_gaze_positions_B = build_gaze_fixation(size, center_B, deviation_max, min_time, max_time, start_ts=ts_gaze_positions_A[-1].timestamp) + def test_identification_browsing(self): + """Test VelocityThresholdIdentification identification browsing.""" + + size = 10 + center_A = (0, 0) + center_B = (50, 50) + deviation_max = 10 + min_time = 0.01 + max_time = 0.1 + velocity_max = deviation_max / min_time + + ts_gaze_positions_A = build_gaze_fixation(size, center_A, deviation_max, min_time, max_time) + ts_gaze_positions_B = build_gaze_fixation(size, center_B, deviation_max, min_time, max_time, start_ts=ts_gaze_positions_A[-1].timestamp) - ts_gaze_positions = ts_gaze_positions_A + ts_gaze_positions_B + ts_gaze_positions = ts_gaze_positions_A + ts_gaze_positions_B - gaze_movement_identifier = VelocityThresholdIdentification.GazeMovementIdentifier(velocity_max_threshold=velocity_max, duration_min_threshold=max_time*2) + gaze_movement_identifier = VelocityThresholdIdentification.GazeMovementIdentifier(velocity_max_threshold=velocity_max, duration_min_threshold=max_time*2) - # Iterate on gaze positions - for gaze_position in ts_gaze_positions: + # Iterate on gaze positions + for gaze_position in ts_gaze_positions: - finished_gaze_movement = gaze_movement_identifier.identify(gaze_position, terminate=(gaze_position.timestamp == ts_gaze_positions[-1])) + finished_gaze_movement = gaze_movement_identifier.identify(gaze_position, terminate=(gaze_position.timestamp == ts_gaze_positions[-1])) - # Check that last gaze position date is not equal to given gaze position date - if finished_gaze_movement: + # Check that last gaze position date is not equal to given gaze position date + if finished_gaze_movement: - self.assertNotEqual(finished_gaze_movement[-1].timestamp, gaze_position.timestamp) + self.assertNotEqual(finished_gaze_movement[-1].timestamp, gaze_position.timestamp) - # Check that last gaze position date of current movement is equal to given gaze position date - current_gaze_movement = gaze_movement_identifier.current_gaze_movement() - if current_gaze_movement: + # Check that last gaze position date of current movement is equal to given gaze position date + current_gaze_movement = gaze_movement_identifier.current_gaze_movement() + if current_gaze_movement: - self.assertEqual(current_gaze_movement[-1].timestamp, gaze_position.timestamp) + self.assertEqual(current_gaze_movement[-1].timestamp, gaze_position.timestamp) if __name__ == '__main__': - unittest.main()
\ No newline at end of file + unittest.main()
\ No newline at end of file |