aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/argaze/utils/tobii_segment_gaze_movements_export.py120
1 files changed, 36 insertions, 84 deletions
diff --git a/src/argaze/utils/tobii_segment_gaze_movements_export.py b/src/argaze/utils/tobii_segment_gaze_movements_export.py
index 1b38fd9..7dd2dad 100644
--- a/src/argaze/utils/tobii_segment_gaze_movements_export.py
+++ b/src/argaze/utils/tobii_segment_gaze_movements_export.py
@@ -16,7 +16,7 @@ import pandas
def main():
"""
- Analyse Tobii segment fixations
+ Project gaze positions into an AOI and identify particular gaze movements like fixations and saccades
"""
# Manage arguments
@@ -60,16 +60,14 @@ def main():
aoi_filepath = f'{destination_path}/../aoi.json'
- fixations_filepath = f'{destination_path}/gaze_fixations.csv'
- saccades_filepath = f'{destination_path}/gaze_saccades.csv'
- unknown_filepath = f'{destination_path}/gaze_unknown.csv'
+ fixations_json_filepath = f'{destination_path}/gaze_fixations.json'
+ saccades_json_filepath = f'{destination_path}/gaze_saccades.json'
+ unknown_json_filepath = f'{destination_path}/gaze_unknown.json'
+ gaze_status_json_filepath = f'{destination_path}/gaze_status.json'
- gaze_status_filepath = f'{destination_path}/gaze_status.csv'
gaze_status_video_filepath = f'{destination_path}/gaze_status.mp4'
gaze_status_image_filepath = f'{destination_path}/gaze_status.png'
- gaze_metrics_filepath = f'{destination_path}/gaze_metrics.csv'
-
# Load aoi scene projection
ts_aois_projections = DataStructures.TimeStampedBuffer.from_json(aoi_filepath)
@@ -114,13 +112,13 @@ def main():
current_aoi = AOIFeatures.AreaOfInterest()
# Initialise progress bar
- #MiscFeatures.printProgressBar(0, tobii_segment_video.duration, prefix = '\nGazePositions projection:', suffix = 'Complete', length = 100)
+ MiscFeatures.printProgressBar(0, tobii_segment_video.duration, prefix = '\nGazePositions projection:', suffix = 'Complete', length = 100)
for ts, tobii_gaze_position in tobii_ts_gaze_positions.items():
# Update Progress Bar
progress = ts - int(args.time_range[0] * 1e6)
- #MiscFeatures.printProgressBar(progress, tobii_segment_video.duration, prefix = 'GazePositions projection:', suffix = 'Complete', length = 100)
+ MiscFeatures.printProgressBar(progress, tobii_segment_video.duration, prefix = 'GazePositions projection:', suffix = 'Complete', length = 100)
try:
@@ -216,7 +214,7 @@ def main():
ts_status = GazeFeatures.TimeStampedGazeStatus()
# Initialise progress bar
- #MiscFeatures.printProgressBar(0, tobii_segment_video.duration, prefix = '\nGazeMovements identification:', suffix = 'Complete', length = 100)
+ MiscFeatures.printProgressBar(0, tobii_segment_video.duration, prefix = '\nGazeMovements identification:', suffix = 'Complete', length = 100)
for gaze_movement in movement_identifier(ts_gaze_positions):
@@ -252,75 +250,24 @@ def main():
# Update Progress Bar
progress = start_ts - int(args.time_range[0] * 1e6)
- #MiscFeatures.printProgressBar(progress, tobii_segment_video.duration, prefix = 'GazeMovements identification:', suffix = 'Complete', length = 100)
+ MiscFeatures.printProgressBar(progress, tobii_segment_video.duration, prefix = 'GazeMovements identification:', suffix = 'Complete', length = 100)
print(f'\nGazeMovements identification metrics:')
print(f'\t{len(ts_fixations)} fixations found')
print(f'\t{len(ts_saccades)} saccades found')
print(f'\t{len(ts_unknown)} unknown movements found')
- # Prepare gaze metrics
- metrics = {}
- segment_duration = tobii_segment_video.duration * 1e-3
- metrics['segment_duration (ms)'] = segment_duration
-
- fixations_exist = len(ts_fixations) > 0
- saccades_exist = len(ts_saccades) > 0
- unknown_exist = len(ts_unknown) > 0
- status_exist = len(ts_status) > 0
-
- # Analyse fixations
- if fixations_exist:
-
- fixations_dataframe = ts_fixations.as_dataframe()
- fixations_dataframe.to_csv(fixations_filepath, index=True)
- print(f'\nFixations saved into {fixations_filepath}')
-
- exploitation_time = fixations_dataframe.duration.sum() * 1e-3
-
- metrics['fixations_number'] = fixations_dataframe.shape[0]
- metrics['fixations_duration_mean (ms)'] = fixations_dataframe.duration.mean() * 1e-3
- metrics['exploitation_ratio (%)'] = exploitation_time / segment_duration * 100
-
- # Analyse saccades
- if saccades_exist:
-
- saccades_dataframe = ts_saccades.as_dataframe()
- saccades_dataframe.to_csv(saccades_filepath, index=True)
- print(f'Saccades saved into {saccades_filepath}')
+ ts_fixations.to_json(fixations_json_filepath)
+ print(f'\nFixations saved into {fixations_json_filepath}')
- exploration_time = saccades_dataframe.duration.sum() * 1e-3
+ ts_saccades.to_json(saccades_json_filepath)
+ print(f'Saccades saved into {saccades_json_filepath}')
- metrics['saccades_number'] = saccades_dataframe.shape[0]
- metrics['saccades_duration_mean (ms)'] = saccades_dataframe.duration.mean() * 1e-3
- metrics['exploration_ratio (%)'] = exploration_time / segment_duration * 100
-
- # Export unknown movements analysis
- if unknown_exist:
-
- unknown_dataframe = ts_unknown.as_dataframe()
- unknown_dataframe.to_csv(unknown_filepath, index=True)
- print(f'Unknown movements saved into {unknown_filepath}')
-
- unknown_time = unknown_dataframe.duration.sum() * 1e-3
-
- metrics['unknown_number'] = unknown_dataframe.shape[0]
- metrics['unknown_duration_mean (ms)'] = unknown_dataframe.duration.mean() * 1e-3
- metrics['unknown_ratio (%)'] = unknown_time / segment_duration * 100
+ ts_unknown.to_json(unknown_json_filepath)
+ print(f'Unknown movements saved into {unknown_json_filepath}')
- if fixations_exist and saccades_exist:
- metrics['exploit_explore_ratio'] = exploitation_time / exploration_time
-
- # Export gaze status analysis
- if status_exist:
-
- ts_status.as_dataframe().to_csv(gaze_status_filepath, index=True)
- print(f'Gaze status saved into {gaze_status_filepath}')
-
- # Export gaze metrics
- metrics_dataframe = pandas.DataFrame(metrics, index=[participant_name])
- metrics_dataframe.to_csv(gaze_metrics_filepath, index=True)
- print(f'Gaze metrics saved into {gaze_metrics_filepath}')
+ ts_status.to_json(gaze_status_json_filepath)
+ print(f'Gaze status saved into {gaze_status_json_filepath}')
# Prepare video exportation at the same format than segment video
output_video = TobiiVideo.TobiiVideoOutput(gaze_status_video_filepath, tobii_segment_video.stream)
@@ -328,14 +275,19 @@ def main():
# Reload aoi scene projection
ts_aois_projections = DataStructures.TimeStampedBuffer.from_json(aoi_filepath)
- #
- heatmap_matrix = numpy.zeros((1080, 1920, 3), numpy.uint8)
+ # Prepare gaze satus image
+ gaze_status_matrix = numpy.zeros((1080, 1920, 3), numpy.uint8)
- # Video and data loop
+ # Video loop
try:
# Initialise progress bar
- MiscFeatures.printProgressBar(0, tobii_segment_video.duration, prefix = '\nGazeMovements visualisation:', suffix = 'Complete', length = 100)
+ MiscFeatures.printProgressBar(0, tobii_segment_video.duration, prefix = '\nGaze status video processing:', suffix = 'Complete', length = 100)
+
+ fixations_exist = len(ts_fixations) > 0
+ saccades_exist = len(ts_saccades) > 0
+ unknown_exist = len(ts_unknown) > 0
+ status_exist = len(ts_status) > 0
if fixations_exist:
current_fixation_ts, current_fixation = ts_fixations.pop_first()
@@ -402,7 +354,7 @@ def main():
int_next_position = (int(next_gaze_position[0]), int(next_gaze_position[1]))
cv.line(visu_matrix, int_start_position, int_next_position, (0, 255, 0), 3)
- cv.line(heatmap_matrix, int_start_position, int_next_position, (0, 255, 0), 3)
+ cv.line(gaze_status_matrix, int_start_position, int_next_position, (0, 255, 0), 3)
# Empty gaze position
except IndexError:
@@ -410,7 +362,7 @@ def main():
# Draw current fixation
cv.circle(visu_matrix, (int(current_fixation.centroid[0]), int(current_fixation.centroid[1])), int(current_fixation.dispersion), (0, 255, 0), current_fixation_time_counter)
- cv.circle(heatmap_matrix, (int(current_fixation.centroid[0]), int(current_fixation.centroid[1])), int(current_fixation.dispersion), (0, 255, 0))
+ cv.circle(gaze_status_matrix, (int(current_fixation.centroid[0]), int(current_fixation.centroid[1])), int(current_fixation.dispersion), (0, 255, 0))
if saccades_exist:
@@ -441,7 +393,7 @@ def main():
int_next_position = (int(next_gaze_position[0]), int(next_gaze_position[1]))
cv.line(visu_matrix, int_start_position, int_next_position, (0, 0, 255), 3)
- cv.line(heatmap_matrix, int_start_position, int_next_position, (0, 0, 255), 3)
+ cv.line(gaze_status_matrix, int_start_position, int_next_position, (0, 0, 255), 3)
# Empty gaze position
except IndexError:
@@ -476,7 +428,7 @@ def main():
int_next_position = (int(next_gaze_position[0]), int(next_gaze_position[1]))
cv.line(visu_matrix, int_start_position, int_next_position, (255, 0, 0), 3)
- cv.line(heatmap_matrix, int_start_position, int_next_position, (255, 0, 0), 3)
+ cv.line(gaze_status_matrix, int_start_position, int_next_position, (255, 0, 0), 3)
# Empty gaze position
except IndexError:
@@ -501,11 +453,11 @@ def main():
int_next_position = (int(next_gaze_position[0]), int(next_gaze_position[1]))
cv.line(visu_matrix, int_start_position, int_next_position, (0, 255, 255), 1)
- cv.line(heatmap_matrix, int_start_position, int_next_position, (0, 255, 255), 1)
+ cv.line(gaze_status_matrix, int_start_position, int_next_position, (0, 255, 255), 1)
# Draw gaze
next_gaze_position.draw(visu_matrix)
- next_gaze_position.draw(heatmap_matrix)
+ next_gaze_position.draw(gaze_status_matrix)
# Write last gaze position
if next_gaze_position.valid:
@@ -548,18 +500,18 @@ def main():
# Update Progress Bar
progress = video_ts - int(args.time_range[0] * 1e6)
- MiscFeatures.printProgressBar(progress, tobii_segment_video.duration, prefix = 'Video with movements processing:', suffix = 'Complete', length = 100)
+ MiscFeatures.printProgressBar(progress, tobii_segment_video.duration, prefix = 'Gaze status video processing:', suffix = 'Complete', length = 100)
# Exit on 'ctrl+C' interruption
except KeyboardInterrupt:
pass
- #
- cv.imwrite(gaze_status_image_filepath, heatmap_matrix)
+ # Saving gaze status image
+ cv.imwrite(gaze_status_image_filepath, gaze_status_matrix)
# End output video file
output_video.close()
- print(f'\nVideo with movements saved into {gaze_status_video_filepath}\n')
+ print(f'\nGaze status video saved into {gaze_status_video_filepath}\n')
if __name__ == '__main__':