aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThéo de la Hogue2022-12-19 17:00:56 +0100
committerThéo de la Hogue2022-12-19 17:00:56 +0100
commit366b6add45ec4be430be8f0ce7ccfe1d5b3d7072 (patch)
tree529d766cd85c88e1a86600960bb9c7a9ec5f6e1f /src
parente185fa9e39d3fc0d2029da2404bca320fead41a2 (diff)
downloadargaze-366b6add45ec4be430be8f0ce7ccfe1d5b3d7072.zip
argaze-366b6add45ec4be430be8f0ce7ccfe1d5b3d7072.tar.gz
argaze-366b6add45ec4be430be8f0ce7ccfe1d5b3d7072.tar.bz2
argaze-366b6add45ec4be430be8f0ce7ccfe1d5b3d7072.tar.xz
Fixing GazeAnalysis test (rare) case.
Diffstat (limited to 'src')
-rw-r--r--src/argaze.test/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py92
-rw-r--r--src/argaze/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py55
2 files changed, 81 insertions, 66 deletions
diff --git a/src/argaze.test/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py b/src/argaze.test/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py
index 55fab29..b342ea9 100644
--- a/src/argaze.test/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py
+++ b/src/argaze.test/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py
@@ -9,7 +9,7 @@ from argaze.GazeAnalysis import DispersionBasedGazeMovementIdentifier
import numpy
-def build_gaze_fixation(size: int, center: tuple, dispersion: float, start_time: float, min_time: float, max_time: float, validity: list = []):
+def build_gaze_fixation(size: int, center: tuple, deviation_max: float, start_time: float, min_time: float, max_time: float, 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.
@@ -27,8 +27,8 @@ def build_gaze_fixation(size: int, center: tuple, dispersion: float, start_time:
if valid:
# Edit gaze position
- random_x = center[0] + dispersion * (random.random() - 0.5)
- random_y = center[1] + dispersion * (random.random() - 0.5)
+ random_x = center[0] + deviation_max * (random.random() - 0.5)
+ random_y = center[1] + deviation_max * (random.random() - 0.5)
gaze_position = GazeFeatures.GazePosition((random_x, random_y))
else:
@@ -89,26 +89,26 @@ class TestDispersionBasedGazeMovementIdentifierClass(unittest.TestCase):
size = 10
center = (0, 0)
- dispersion = 10
+ deviation_max = 10
start_time = time.time()
min_time = 0.01
max_time = 0.1
- ts_gaze_positions = build_gaze_fixation(size, center, dispersion, start_time, min_time, max_time)
- gaze_movement_identifier = DispersionBasedGazeMovementIdentifier.GazeMovementIdentifier(deviation_max_threshold=dispersion, duration_min_threshold=max_time*2)
- ts_fixations, ts_saccades, ts_unknown, ts_status = gaze_movement_identifier.identify(ts_gaze_positions)
+ ts_gaze_positions = build_gaze_fixation(size, center, deviation_max, start_time, min_time, max_time)
+ gaze_movement_identifier = DispersionBasedGazeMovementIdentifier.GazeMovementIdentifier(deviation_max_threshold=deviation_max, duration_min_threshold=max_time*2)
+ ts_fixations, ts_saccades, ts_movements, ts_status = gaze_movement_identifier.identify(ts_gaze_positions)
# Check result size
self.assertEqual(len(ts_fixations), 1)
self.assertEqual(len(ts_saccades), 0)
- self.assertEqual(len(ts_unknown), 0)
+ self.assertEqual(len(ts_movements), 0)
self.assertEqual(len(ts_status), size)
# Check fixation
ts, fixation = ts_fixations.pop_first()
self.assertEqual(len(fixation.positions.keys()), size)
- self.assertLessEqual(fixation.dispersion, dispersion)
+ self.assertLessEqual(fixation.deviation_max, deviation_max)
self.assertGreaterEqual(fixation.duration, size * min_time)
self.assertLessEqual(fixation.duration, size * max_time)
@@ -118,30 +118,30 @@ class TestDispersionBasedGazeMovementIdentifierClass(unittest.TestCase):
size = 10
center_A = (0, 0)
center_B = (50, 50)
- dispersion = 10
+ deviation_max = 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_gaze_positions_B = build_gaze_fixation(size, center_B, dispersion, start_time, min_time, max_time)
+ ts_gaze_positions_A = build_gaze_fixation(size, center_A, deviation_max, start_time, min_time, max_time)
+ ts_gaze_positions_B = build_gaze_fixation(size, center_B, deviation_max, start_time, min_time, max_time)
ts_gaze_positions = ts_gaze_positions_A.append(ts_gaze_positions_B)
- gaze_movement_identifier = DispersionBasedGazeMovementIdentifier.GazeMovementIdentifier(deviation_max_threshold=dispersion, duration_min_threshold=max_time*2)
- ts_fixations, ts_saccades, ts_unknown, ts_status = gaze_movement_identifier.identify(ts_gaze_positions)
+ gaze_movement_identifier = DispersionBasedGazeMovementIdentifier.GazeMovementIdentifier(deviation_max_threshold=deviation_max, duration_min_threshold=max_time*2)
+ ts_fixations, ts_saccades, ts_movements, 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_movements), 0)
self.assertEqual(len(ts_status), size*2)
# Check first fixation
ts, fixation = ts_fixations.pop_first()
self.assertEqual(len(fixation.positions.keys()), size-1)
- self.assertLessEqual(fixation.dispersion, dispersion)
+ self.assertLessEqual(fixation.deviation_max, deviation_max)
self.assertGreaterEqual(fixation.duration, size * min_time)
self.assertLessEqual(fixation.duration, size * max_time)
@@ -156,7 +156,7 @@ class TestDispersionBasedGazeMovementIdentifierClass(unittest.TestCase):
ts, fixation = ts_fixations.pop_first()
self.assertEqual(len(fixation.positions.keys()), size-1)
- self.assertLessEqual(fixation.dispersion, dispersion)
+ self.assertLessEqual(fixation.deviation_max, deviation_max)
self.assertGreaterEqual(fixation.duration, size * min_time)
self.assertLessEqual(fixation.duration, size * max_time)
'''
@@ -168,33 +168,33 @@ class TestDispersionBasedGazeMovementIdentifierClass(unittest.TestCase):
center_A = (0, 0)
out_A = (20, 20)
center_B = (50, 50)
- dispersion = 10
+ deviation_max = 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_gaze_positions_A = build_gaze_fixation(size, center_A, deviation_max, 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)
+ ts_gaze_positions_B = build_gaze_fixation(size, center_B, deviation_max, 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(deviation_max_threshold=dispersion, duration_min_threshold=max_time*2)
- ts_fixations, ts_saccades, ts_unknown, ts_status = gaze_movement_identifier.identify(ts_gaze_positions)
+ gaze_movement_identifier = DispersionBasedGazeMovementIdentifier.GazeMovementIdentifier(deviation_max_threshold=deviation_max, duration_min_threshold=max_time*2)
+ ts_fixations, ts_saccades, ts_movements, 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_movements), 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.assertLessEqual(fixation.deviation_max, deviation_max)
self.assertGreaterEqual(fixation.duration, size * min_time)
self.assertLessEqual(fixation.duration, size * max_time)
@@ -209,37 +209,37 @@ class TestDispersionBasedGazeMovementIdentifierClass(unittest.TestCase):
ts, fixation = ts_fixations.pop_first()
self.assertEqual(len(fixation.positions.keys()), size-1)
- self.assertLessEqual(fixation.dispersion, dispersion)
+ self.assertLessEqual(fixation.deviation_max, deviation_max)
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."""
- size = 10
+ size = 15
center = (0, 0)
- dispersion = 10
+ deviation_max = 10
start_time = time.time()
min_time = 0.01
max_time = 0.1
- validity = [True, True, True, True, False, False, True, True, True, True]
+ validity = [True, True, True, True, False, True, True, True, False, False, True, True, True, True, True]
- ts_gaze_positions = build_gaze_fixation(size, center, dispersion, start_time, min_time, max_time, validity)
+ ts_gaze_positions = build_gaze_fixation(size, center, deviation_max, start_time, min_time, max_time, validity)
- gaze_movement_identifier = DispersionBasedGazeMovementIdentifier.GazeMovementIdentifier(deviation_max_threshold=dispersion, duration_min_threshold=max_time*2)
- ts_fixations, ts_saccades, ts_unknown, ts_status = gaze_movement_identifier.identify(ts_gaze_positions)
+ gaze_movement_identifier = DispersionBasedGazeMovementIdentifier.GazeMovementIdentifier(deviation_max_threshold=deviation_max, duration_min_threshold=max_time*2)
+ ts_fixations, ts_saccades, ts_movements, ts_status = gaze_movement_identifier.identify(ts_gaze_positions)
# Check result size
self.assertEqual(len(ts_fixations), 1)
self.assertEqual(len(ts_saccades), 0)
- self.assertEqual(len(ts_unknown), 0)
- self.assertEqual(len(ts_status), size-2)
+ self.assertEqual(len(ts_movements), 0)
+ self.assertEqual(len(ts_status), size-3)
# Check fixation
ts, fixation = ts_fixations.pop_first()
- self.assertEqual(len(fixation.positions.keys()), size-2)
- self.assertLessEqual(fixation.dispersion, dispersion)
+ self.assertEqual(len(fixation.positions.keys()), size-3)
+ self.assertLessEqual(fixation.deviation_max, deviation_max)
self.assertGreaterEqual(fixation.duration, size * min_time)
self.assertLessEqual(fixation.duration, size * max_time)
@@ -250,14 +250,14 @@ class TestDispersionBasedGazeMovementIdentifierClass(unittest.TestCase):
center_A = (0, 0)
center_B = (50, 50)
center_C = (55, 55)
- dispersion = 10
+ deviation_max = 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_gaze_positions_B = build_gaze_fixation(size, center_B, dispersion, start_time, min_time, max_time)
- ts_gaze_positions_C = build_gaze_fixation(size, center_C, dispersion, start_time, min_time, max_time)
+ ts_gaze_positions_A = build_gaze_fixation(size, center_A, deviation_max, start_time, min_time, max_time)
+ ts_gaze_positions_B = build_gaze_fixation(size, center_B, deviation_max, start_time, min_time, max_time)
+ ts_gaze_positions_C = build_gaze_fixation(size, center_C, deviation_max, start_time, min_time, max_time)
fixation_A = DispersionBasedGazeMovementIdentifier.Fixation(ts_gaze_positions_A)
fixation_B = DispersionBasedGazeMovementIdentifier.Fixation(ts_gaze_positions_B)
@@ -277,30 +277,30 @@ class TestDispersionBasedGazeMovementIdentifierClass(unittest.TestCase):
size = 50
center_A = (-5, 0)
center_B = (5, 0)
- dispersion = 15
+ deviation_max = 15
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_gaze_positions_B = build_gaze_fixation(size, center_B, dispersion, start_time, min_time, max_time)
+ ts_gaze_positions_A = build_gaze_fixation(size, center_A, deviation_max, start_time, min_time, max_time)
+ ts_gaze_positions_B = build_gaze_fixation(size, center_B, deviation_max, start_time, min_time, max_time)
ts_gaze_positions = ts_gaze_positions_A.append(ts_gaze_positions_B)
- gaze_movement_identifier = DispersionBasedGazeMovementIdentifier.GazeMovementIdentifier(deviation_max_threshold=dispersion, duration_min_threshold=max_time*2)
- ts_fixations, ts_saccades, ts_unknown, ts_status = gaze_movement_identifier.identify(ts_gaze_positions)
+ gaze_movement_identifier = DispersionBasedGazeMovementIdentifier.GazeMovementIdentifier(deviation_max_threshold=deviation_max, duration_min_threshold=max_time*2)
+ ts_fixations, ts_saccades, ts_movements, ts_status = gaze_movement_identifier.identify(ts_gaze_positions)
# Check result size
self.assertEqual(len(ts_fixations), 1)
self.assertEqual(len(ts_saccades), 0)
- self.assertEqual(len(ts_unknown), 0)
+ self.assertEqual(len(ts_movements), 0)
self.assertEqual(len(ts_status), size*2)
# Check unique fixation
ts, fixation = ts_fixations.pop_first()
self.assertEqual(len(fixation.positions.keys()), size*2)
- #self.assertGreaterEqual(fixation.dispersion, dispersion)
+ #self.assertGreaterEqual(fixation.deviation_max, deviation_max)
self.assertGreaterEqual(fixation.duration, 2 * size * min_time)
self.assertLessEqual(fixation.duration, 2 * size * max_time)
diff --git a/src/argaze/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py b/src/argaze/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py
index 1364c99..5cbf6c4 100644
--- a/src/argaze/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py
+++ b/src/argaze/GazeAnalysis/DispersionBasedGazeMovementIdentifier.py
@@ -204,32 +204,25 @@ class GazeMovementIdentifier(GazeFeatures.GazeMovementIdentifier):
# Does a former fixation have been identified ?
if self.__last_fixation != None:
- # Inter fixations movement should:
- # - starts at last position of last fixation (this position is out so it have to be popped)
- # - stops at the first position inside new fixation
- start_movement_ts, start_position = self.__last_fixation.positions.pop_last()
- stop_movement_ts, stop_position = new_fixation.positions.pop_first()
-
# Remove last gaze position of the new fixation as it is it's out position
last_new_ts, last_new_position = new_fixation.positions.pop_last()
- # Rare case : the last fixation position is the same than the first position of the new fixation
- if start_movement_ts == stop_movement_ts:
- start_movement_ts, start_position = self.__last_fixation.positions.pop_last()
-
- # Update last and new fixations
- self.__last_fixation.update()
- new_fixation.update()
-
# Edit inter fixations movement gaze positions
movement_gaze_positions = GazeFeatures.TimeStampedGazePositions()
- # Edit first movement gaze position
- movement_gaze_positions[start_movement_ts] = start_position
-
- # Is there unmatched gaze positions that belong to the movement?
+ # If such unmatched positions exist
if len(unmatched_gaze_positions) > 0:
+ # Inter fixations movement should:
+ # - starts at last position of last fixation (this position is out so it have to be popped)
+ # - stops at the first position inside new fixation
+ start_movement_ts, start_position = self.__last_fixation.positions.pop_last()
+ stop_movement_ts, stop_position = new_fixation.positions.pop_first()
+
+ # Edit first movement gaze position
+ movement_gaze_positions[start_movement_ts] = start_position
+
+ # Edit movement positions with unmatched positions if there are between the 2 fixations
start_unmatched_ts, _ = unmatched_gaze_positions.first
end_unmatched_ts, _ = unmatched_gaze_positions.last
@@ -245,12 +238,34 @@ class GazeMovementIdentifier(GazeFeatures.GazeMovementIdentifier):
# Ignore them: GazeMovementIdentifier have to output movements according their time apparition
pass
- # Edit last movement gaze position
- movement_gaze_positions[stop_movement_ts] = stop_position
+ # Edit last movement gaze position
+ movement_gaze_positions[stop_movement_ts] = stop_position
+
+ # When there is no unmatched positions between 2 fixations (*rare case)
+ else:
+
+ # the last fixation position is the same than the first position of the new fixation
+ stop_movement_ts, stop_position = self.__last_fixation.positions.pop_last()
+ start_movement_ts, start_position = self.__last_fixation.positions.pop_last()
+
+ # Edit first movement gaze position
+ movement_gaze_positions[start_movement_ts] = start_position
+
+ # Edit last movement gaze position
+ movement_gaze_positions[stop_movement_ts] = stop_position
+
+ # Update last and new fixations
+ self.__last_fixation.update()
+ new_fixation.update()
# Does new fixation overlap last fixation?
if self.__last_fixation.overlap(new_fixation):
+ # (*rare case)
+ if len(unmatched_gaze_positions) == 0:
+ self.__last_fixation.positions[start_movement_ts] = start_position
+ self.__last_fixation.positions[stop_movement_ts] = stop_position
+
# Merge new fixation into last fixation
self.__last_fixation.merge(new_fixation)