From fe8c843e3bf16a43ceabd8be0d5b7ae574118dc2 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Sat, 10 Dec 2022 18:31:26 +0100 Subject: Removing gaze movement metrics. --- .../utils/tobii_segment_gaze_movements_export.py | 120 +++++++-------------- 1 file 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__': -- cgit v1.1