From 293d1cc9b0fe6d7e871511cd716001f5765d9118 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Thu, 10 Aug 2023 09:04:31 +0200 Subject: Working on gaze analysis pipeline documentation. Still in progress... --- .../ar_frame_configuration_and_execution.md | 161 +++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 docs/user_guide/gaze_analysis_pipeline/ar_frame_configuration_and_execution.md (limited to 'docs/user_guide/gaze_analysis_pipeline/ar_frame_configuration_and_execution.md') diff --git a/docs/user_guide/gaze_analysis_pipeline/ar_frame_configuration_and_execution.md b/docs/user_guide/gaze_analysis_pipeline/ar_frame_configuration_and_execution.md new file mode 100644 index 0000000..00300a8 --- /dev/null +++ b/docs/user_guide/gaze_analysis_pipeline/ar_frame_configuration_and_execution.md @@ -0,0 +1,161 @@ +Configure and execute ArFrame +============================= + +The [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) class defines a rectangular area where timestamped gaze positions are projected in and inside which they need to be analyzed. + +![Timestamped Gaze Positions](../../img/ar_frame.png) + +## Load JSON configuration file + +The [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) internal pipeline is entirely customizable from a JSON configuration file thanks to [ArFrame.from_json](../../../argaze/#argaze.ArFeatures.ArFrame.from_json) class method. + +Here is a simple JSON ArFrame configuration file example: + +```json +{ + "name": "My FullHD screen", + "size": [1920, 1080], + "gaze_movement_identifier": { + "DispersionThresholdIdentification": { + "deviation_max_threshold": 50, + "duration_min_threshold": 200 + } + }, + "scan_path": { + "duration_max": 30000, + }, + "scan_path_analyzers": { + "Basic": {}, + "ExploitExploreRatio": { + "short_fixation_duration_threshold": 0 + } + }, + "heatmap": { + "size": [320, 180], + "sigma": 0.025, + "buffer": 0 + } +} +``` + +Then, here is how to load the JSON file: + +```python +from argaze import ArFeatures + +# Load ArFrame +ar_frame = ArFeatures.ArFrame.from_json('./configuration.json') + +# Print ArFrame attributes +print("name:", ar_frame.name) +print("size:", ar_frame.size) +print("gaze movement identifier type:", type(ar_frame.gaze_movement_identifier)) +print("scan path:", ar_frame.scan_path) + +for module, analyzer in ar_frame.scan_path_analyzers.items(): + print('scan path analyzer module:', module) + +print("heatmap:", ar_frame.heatmap) +``` + +Finally, here is what the program writes in console: + +``` +name: My FullHD screen +size: [1920, 1080] +gaze movement identifier type: +scan path: [] +scan path analyzer module: argaze.GazeAnalysis.Basic +scan path analyzer module: argaze.GazeAnalysis.ExploitExploreRatio +heatmap: Heatmap(size=[320, 180], buffer=0, sigma=0.025) +``` + +Now, let's understand the meaning of each JSON entry. + +### Name + +The name of the [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame). Basically useful for visualisation purpose. + +### Size + +The size of the [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) defines the dimension of the rectangular area where gaze positions are projected. Be aware that gaze positions have to be in the same range of value. + +### Gaze Movement Identifier + +The first [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) pipeline step is to identify fixations or saccades from consecutive timestamped gaze positions. + +![Gaze Movement Identifier](../../img/ar_frame_gaze_movement_identifier.png) + +The identification method can be selected by instantiating a particular [GazeMovementIdentifier](../../../argaze/#argaze.GazeFeatures.GazeMovementIdentifier) from the [argaze.GazeAnalysis](../../../argaze/#argaze.GazeAnalysis) submodule or [another python package](../advanced_topics/plugin_loading). + +In the example file, the choosen identification method is the [Dispersion Threshold Identification (I-DT)](../../../argaze/#argaze.GazeAnalysis.DispersionThresholdIdentification) which has two specific deviation_max_threshold and duration_min_threshold attributes. + +!!! note + In ArGaze, [Fixation](../../../argaze/#argaze.GazeFeatures.Fixation) and [Saccade](../../../argaze/#argaze.GazeFeatures.Saccade) are considered as particular [GazeMovements](../../../argaze/#argaze.GazeFeatures.GazeMovement). + +!!! warning + JSON *gaze_movement_identifier* entry is mandatory. Otherwise, the ScanPath and ScanPathAnalyzers steps are disabled. + +### Scan Path + +The second [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) pipeline step aims to build a [ScanPath](../../../argaze/#argaze.GazeFeatures.ScanPath) defined as a list of [ScanSteps](../../../argaze/#argaze.GazeFeatures.ScanStep) made by a fixation and a consecutive saccade. + +![Scan Path](../../img/ar_frame_scan_path.png) + +Once fixations and saccades are identified, they are automatically appended to the ScanPath if required. + +The [ScanPath.duration_max](../../../argaze/#argaze.GazeFeatures.ScanPath.duration_max) attribute is the duration from which older scan steps are removed each time new scan steps are added. + +### Scan Path Analyzers + +Finally, the last [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) pipeline step consists in passing the previously built [ScanPath](../../../argaze/#argaze.GazeFeatures.ScanPath) to each loaded [ScanPathAnalyzer](../../../argaze/#argaze.GazeFeatures.ScanPathAnalyzer). + +Each analysis algorithm can be selected by instantiating a particular [ScanPathAnalyzer](../../../argaze/#argaze.GazeFeatures.ScanPathAnalyzer) from the [argaze.GazeAnalysis](../../../argaze/#argaze.GazeAnalysis) submodule or [another python package](../advanced_topics/plugin_loading). + +!!! note + JSON *scan_path* entry is not mandatory. If scan_path_analyzers entry is not empty, the ScanPath step is automatically enabled. + +### Heatmap + +This is an optional [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) pipeline step. It is executed at each new gaze position to update Heatmap image. + +![Heatmap](../../img/ar_frame_heatmap.png) + +The Heatmap object have tree attributes to set its size, the sigma point spreading and optional buffer size (0 means no buffering). + +## Pipeline execution + +Timestamped gaze positions have to be passed one by one to [ArFrame.look](../../../argaze/#argaze.ArFeatures.ArFrame.look) method to execute the whole intanciated pipeline. + +```python +# Assuming that timestamp gaze positions are available +... + + # Look ArFrame at a timestamped gaze position + movement, scan_path_analysis, _, execution_times, exception = ar_frame.look(timestamp, gaze_position) + + # Check if a movement has been identified + if movement.valid and movement.finished: + + # Do something with identified fixation + if GazeFeatures.is_fixation(movement): + ... + + # Do something with identified saccade + elif GazeFeatures.is_saccade(movement): + ... + + # Do something with scan path analysis + for module, analysis in scan_path_analysis.items(): + for data, value in analysis.items(): + ... + + # Do something with pipeline execution times + ... + + # Do something with pipeline exception + if exception: + ... +``` + + -- cgit v1.1