From 6cce228412f3f3b074fdaf87775b8d62a5adb060 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Wed, 30 Aug 2023 22:26:31 +0200 Subject: Reorganizing gaze analizis pipeline documentation. --- .../gaze_analysis_logging.md | 97 ----------- docs/user_guide/gaze_analysis_pipeline/heatmap.md | 71 ++++++++ .../heatmap_visualisation.md | 71 -------- docs/user_guide/gaze_analysis_pipeline/logging.md | 97 +++++++++++ .../gaze_analysis_pipeline/visualisation.md | 190 +++++++++++++++++++++ 5 files changed, 358 insertions(+), 168 deletions(-) delete mode 100644 docs/user_guide/gaze_analysis_pipeline/gaze_analysis_logging.md create mode 100644 docs/user_guide/gaze_analysis_pipeline/heatmap.md delete mode 100644 docs/user_guide/gaze_analysis_pipeline/heatmap_visualisation.md create mode 100644 docs/user_guide/gaze_analysis_pipeline/logging.md create mode 100644 docs/user_guide/gaze_analysis_pipeline/visualisation.md (limited to 'docs/user_guide') diff --git a/docs/user_guide/gaze_analysis_pipeline/gaze_analysis_logging.md b/docs/user_guide/gaze_analysis_pipeline/gaze_analysis_logging.md deleted file mode 100644 index 422b43b..0000000 --- a/docs/user_guide/gaze_analysis_pipeline/gaze_analysis_logging.md +++ /dev/null @@ -1,97 +0,0 @@ -Log gaze analysis -================= - -[ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) logging are optional pipeline steps. They are executed at each new scan path step to update logs. - -## Enable ArFrame and ArLayer logging - -[ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) have a log attribute to enable analysis logging. - -Here is the JSON ArFrame configuration file example where logging is enabled for the ArFrame and for one ArLayer: - -```json -{ - "name": "My FullHD screen", - "size": [1920, 1080], - "log": true, - ... - "layers": { - "MyLayer": { - "log": true, - ... - } - } -} -``` - -Then, here is how to access to logs dictionaries: - -```python -# Assuming that all timestamped gaze positions have been processed by ArFrame.look method -... - -# Access to ArFame scan path analysis logs -for analysis, log in ar_frame.logs.items(): - - # Do something with scan path analysis log - ... - -# Access to ArLayers AOI scan path analysis logs -for layer_name, layer in ar_frame.layers.items(): - - for analysis, log in layer.logs.items(): - - # Do something with AOI scan path analysis log - ... -``` - -!!! note - [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and its [ArLayers](../../argaze.md/#argaze.ArFeatures.ArLayer) logging are automatically done each time the [ArFrame.look](../../argaze.md/#argaze.ArFeatures.ArFrame.look) method is called. - [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) logging records each scan path analysis into a dedicated timestamped data buffer each time a new scan path step happens. - [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) logging records each AOI scan path analysis into a dedicated timestamped data buffer each time a new AOI scan path step happens. - -## Export gaze analysis logs to CSV file - -It is possible to convert gaze analysis log as [Pandas DataFrame](https://pandas.pydata.org/docs/getting_started/intro_tutorials/01_table_oriented.html#min-tut-01-tableoriented) object which can be writen into a CSV file. - -```python -import pandas - -# Assuming that all timestamped gaze positions have been processed by ArFrame.look method -... - -# Export ArFame scan path analysis logs -for analysis, log in ar_frame.logs.items(): - - log.as_dataframe().to_csv(f'./{ar_frame.name}_{analysis}.csv') - -# Export ArLayers layers AOI scan path analysis logs -for layer_name, layer in ar_frame.layers.items(): - - for analysis, log in layer.logs.items(): - - log.as_dataframe().to_csv(f'./{ar_frame.name}_{layer_name}_{analysis}.csv') - -``` - -Assuming that [ArGaze.GazeAnalysis.Basic](../../argaze.md/#argaze.GazeAnalysis.Basic) scan path analysis module is enabled for 'My FullHD screen' ArFrame, a ***My FullHD screen_argaze.GazeAnalysis.Basic.csv*** file would be created: - -|timestamped|path_duration|step_fixation_durations_average|steps_number| -|:----------|:------------|:------------------------------|:-----------| -|3460 |1750 |563.0 |2 | -|4291 |2623 |652.0 |3 | -|4769 |3107 |544.0 |4 | -|6077 |4411 |652.8 |5 | -|6433 |4760 |595.1 |6 | -|7719 |6050 |652.8 |7 | -|... |... |... |... | - -Assuming that [ArGaze.GazeAnalysis.NGram](../../argaze.md/#argaze.GazeAnalysis.NGram) AOI scan path analysis module is enabled for 'MyLayer' ArLayer, a ***My FullHD screen_MyLayer_argaze.GazeAnalysis.NGram.csv*** file would be created: - -|timestamped|ngrams_count| -|:----------|:-----------| -|5687 |"{3: {}, 4: {}, 5: {}}"| -|6208 |"{3: {('upper_left_corner', 'lower_left_corner', 'lower_right_corner'): 1}, 4: {}, 5: {}}"| -|... |... | - - diff --git a/docs/user_guide/gaze_analysis_pipeline/heatmap.md b/docs/user_guide/gaze_analysis_pipeline/heatmap.md new file mode 100644 index 0000000..35674a1 --- /dev/null +++ b/docs/user_guide/gaze_analysis_pipeline/heatmap.md @@ -0,0 +1,71 @@ +Add Heatmap +=========== + +Heatmap is an optional [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) pipeline step. It is executed at each new gaze position to update heatmap image. + +![Heatmap](../../img/ar_frame_heatmap.png) + +## Enable ArFrame heatmap + +[ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) heatmap visualization can be enabled thanks to a dedicated JSON entry. + +Here is the JSON ArFrame configuration file example where heatmap visualization is enabled: + +```json +{ + "name": "My FullHD screen", + "size": [1920, 1080], + ... + "heatmap": { + "size": [320, 180], + "sigma": 0.025, + "buffer": 0 + } +} +``` + +Then, here is how to access to heatmap object: + +```python + +# Assuming an ArFrame is loaded +... + +print("heatmap:", ar_frame.heatmap) +``` + +Finally, here is what the program writes in console: + +```txt +heatmap: Heatmap(size=[320, 180], buffer=0, sigma=0.025) +``` + +Now, let's understand the meaning of each JSON entry. + +### Size + +The heatmap image size in pixel. Higher size implies higher CPU load. + +### Sigma + +The gaussian point spreading to draw at each gaze position. + +![Point spread](../../img/point_spread.png) + +### Buffer + +The size of point spread images buffer (0 means no buffering) to visualize only last N gaze positions. + +## Export heatmap to PNG file + +Once timestamped gaze positions have been processed by [ArFrame.look](../../argaze.md/#argaze.ArFeatures.ArFrame.look) method, it is possible to write heatmap image thanks to OpenCV package. + +```python +import cv2 + +# Assuming that timestamped gaze positions have been processed by ArFrame.look method +... + +# Export heatmap image +cv2.imwrite('./heatmap.png', ar_frame.heatmap.image) +``` \ No newline at end of file diff --git a/docs/user_guide/gaze_analysis_pipeline/heatmap_visualisation.md b/docs/user_guide/gaze_analysis_pipeline/heatmap_visualisation.md deleted file mode 100644 index a1f1672..0000000 --- a/docs/user_guide/gaze_analysis_pipeline/heatmap_visualisation.md +++ /dev/null @@ -1,71 +0,0 @@ -Visualize heatmap -================= - -Heatmap is an optional [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) pipeline step. It is executed at each new gaze position to update heatmap image. - -![Heatmap](../../img/ar_frame_heatmap.png) - -## Enable ArFrame heatmap - -[ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) heatmap visualization can be enabled thanks to a dedicated JSON entry. - -Here is the JSON ArFrame configuration file example where heatmap visualization is enabled: - -```json -{ - "name": "My FullHD screen", - "size": [1920, 1080], - ... - "heatmap": { - "size": [320, 180], - "sigma": 0.025, - "buffer": 0 - } -} -``` - -Then, here is how to access to heatmap object: - -```python - -# Assuming an ArFrame is loaded -... - -print("heatmap:", ar_frame.heatmap) -``` - -Finally, here is what the program writes in console: - -```txt -heatmap: Heatmap(size=[320, 180], buffer=0, sigma=0.025) -``` - -Now, let's understand the meaning of each JSON entry. - -### Size - -The heatmap image size in pixel. Higher size implies higher CPU load. - -### Sigma - -The gaussian point spreading to draw at each gaze position. - -![Point spread](../../img/point_spread.png) - -### Buffer - -The size of point spread images buffer (0 means no buffering) to visualize only last N gaze positions. - -## Export heatmap to PNG file - -Once timestamped gaze positions have been processed by [ArFrame.look](../../argaze.md/#argaze.ArFeatures.ArFrame.look) method, it is possible to write heatmap image thanks to OpenCV package. - -```python -import cv2 - -# Assuming that timestamped gaze positions have been processed by ArFrame.look method -... - -# Export heatmap image -cv2.imwrite('./heatmap.png', ar_frame.heatmap.image) -``` \ No newline at end of file diff --git a/docs/user_guide/gaze_analysis_pipeline/logging.md b/docs/user_guide/gaze_analysis_pipeline/logging.md new file mode 100644 index 0000000..422b43b --- /dev/null +++ b/docs/user_guide/gaze_analysis_pipeline/logging.md @@ -0,0 +1,97 @@ +Log gaze analysis +================= + +[ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) logging are optional pipeline steps. They are executed at each new scan path step to update logs. + +## Enable ArFrame and ArLayer logging + +[ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) have a log attribute to enable analysis logging. + +Here is the JSON ArFrame configuration file example where logging is enabled for the ArFrame and for one ArLayer: + +```json +{ + "name": "My FullHD screen", + "size": [1920, 1080], + "log": true, + ... + "layers": { + "MyLayer": { + "log": true, + ... + } + } +} +``` + +Then, here is how to access to logs dictionaries: + +```python +# Assuming that all timestamped gaze positions have been processed by ArFrame.look method +... + +# Access to ArFame scan path analysis logs +for analysis, log in ar_frame.logs.items(): + + # Do something with scan path analysis log + ... + +# Access to ArLayers AOI scan path analysis logs +for layer_name, layer in ar_frame.layers.items(): + + for analysis, log in layer.logs.items(): + + # Do something with AOI scan path analysis log + ... +``` + +!!! note + [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and its [ArLayers](../../argaze.md/#argaze.ArFeatures.ArLayer) logging are automatically done each time the [ArFrame.look](../../argaze.md/#argaze.ArFeatures.ArFrame.look) method is called. + [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) logging records each scan path analysis into a dedicated timestamped data buffer each time a new scan path step happens. + [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) logging records each AOI scan path analysis into a dedicated timestamped data buffer each time a new AOI scan path step happens. + +## Export gaze analysis logs to CSV file + +It is possible to convert gaze analysis log as [Pandas DataFrame](https://pandas.pydata.org/docs/getting_started/intro_tutorials/01_table_oriented.html#min-tut-01-tableoriented) object which can be writen into a CSV file. + +```python +import pandas + +# Assuming that all timestamped gaze positions have been processed by ArFrame.look method +... + +# Export ArFame scan path analysis logs +for analysis, log in ar_frame.logs.items(): + + log.as_dataframe().to_csv(f'./{ar_frame.name}_{analysis}.csv') + +# Export ArLayers layers AOI scan path analysis logs +for layer_name, layer in ar_frame.layers.items(): + + for analysis, log in layer.logs.items(): + + log.as_dataframe().to_csv(f'./{ar_frame.name}_{layer_name}_{analysis}.csv') + +``` + +Assuming that [ArGaze.GazeAnalysis.Basic](../../argaze.md/#argaze.GazeAnalysis.Basic) scan path analysis module is enabled for 'My FullHD screen' ArFrame, a ***My FullHD screen_argaze.GazeAnalysis.Basic.csv*** file would be created: + +|timestamped|path_duration|step_fixation_durations_average|steps_number| +|:----------|:------------|:------------------------------|:-----------| +|3460 |1750 |563.0 |2 | +|4291 |2623 |652.0 |3 | +|4769 |3107 |544.0 |4 | +|6077 |4411 |652.8 |5 | +|6433 |4760 |595.1 |6 | +|7719 |6050 |652.8 |7 | +|... |... |... |... | + +Assuming that [ArGaze.GazeAnalysis.NGram](../../argaze.md/#argaze.GazeAnalysis.NGram) AOI scan path analysis module is enabled for 'MyLayer' ArLayer, a ***My FullHD screen_MyLayer_argaze.GazeAnalysis.NGram.csv*** file would be created: + +|timestamped|ngrams_count| +|:----------|:-----------| +|5687 |"{3: {}, 4: {}, 5: {}}"| +|6208 |"{3: {('upper_left_corner', 'lower_left_corner', 'lower_right_corner'): 1}, 4: {}, 5: {}}"| +|... |... | + + diff --git a/docs/user_guide/gaze_analysis_pipeline/visualisation.md b/docs/user_guide/gaze_analysis_pipeline/visualisation.md new file mode 100644 index 0000000..5eae7f5 --- /dev/null +++ b/docs/user_guide/gaze_analysis_pipeline/visualisation.md @@ -0,0 +1,190 @@ +Visualize ArFrame and ArLayers +============================== + +All [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayers](../../argaze.md/#argaze.ArFeatures.ArFrame) pipeline steps can be drawn in real time or afterward. + +![ArFrame visualisation](../../img/ar_frame_visualisation.png) + +## Export to PNG file + +Once timestamped gaze positions have been processed by [ArFrame.look](../../argaze.md/#argaze.ArFeatures.ArFrame.look) method, it is possible to write [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) image into a file thanks to [OpenCV package](https://pypi.org/project/opencv-python/). + +```python +import cv2 + +# Assuming that timestamped gaze positions have been processed by ArFrame.look method +... + +# Export heatmap image +cv2.imwrite('./ar_frame.png', ar_frame.image()) +``` + +## Export to MP4 file + +While timestamped gaze positions are processed by [ArFrame.look](../../argaze.md/#argaze.ArFeatures.ArFrame.look) method, it is possible to write [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) image into a video file thanks to [OpenCV package](https://pypi.org/project/opencv-python/). + +```python +import cv2 + +# Assuming ArFrame is loaded +... + +# Create a video file to save ArFrame +video = cv2.VideoWriter('ar_frame.avi', cv2.VideoWriter_fourcc(*'MJPG'), 10, ar_frame.size) + +# Assuming that timestamped gaze positions are being processed by ArFrame.look method +... + + # Write ArFrame image into video file + video.write(ar_frame.image()) + +# Close video file +video.release() +``` + +## Live window display + +While timestamped gaze positions are processed by [ArFrame.look](../../argaze.md/#argaze.ArFeatures.ArFrame.look) method, it is possible to display [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) image thanks to [OpenCV package](https://pypi.org/project/opencv-python/). + +```python +import cv2 + +def main(): + + # Assuming ArFrame is loaded + ... + + # Create a window to display ArFrame + cv2.namedWindow(ar_frame.name, cv2.WINDOW_AUTOSIZE) + + # Assuming that timestamped gaze positions are being processed by ArFrame.look method + ... + + # Update ArFrame image display + cv2.imshow(ar_frame.name, ar_frame.image()) + + # Wait 10 ms + cv2.waitKey(10) + +if __name__ == '__main__': + + main() +``` + +## Edit ArFrame image parameters + +[ArFrame.image](../../argaze.md/#argaze.ArFeatures.ArFrame.image) method parameters can be configured thanks to dictionary. + +```python +# Edit ArFrame image parameters +image_parameters = { + "draw_scan_path": { + "draw_fixations": { + "deviation_circle_color": [255, 0, 255], + "duration_border_color": [127, 0, 127], + "duration_factor": 1e-2 + }, + "draw_saccades": { + "line_color": [255, 0, 255] + }, + "deepness": 0 + }, + "draw_layers": { + "MyLayer": { + "draw_aoi_scene": { + "draw_aoi": { + "color": [255, 255, 255], + "border_size": 1 + } + }, + "draw_aoi_matching": { + "draw_matched_fixation": { + "deviation_circle_color": [255, 255, 255] + }, + "draw_matched_fixation_positions": { + "position_color": [0, 255, 255], + "line_color": [0, 0, 0] + }, + "draw_matched_region": { + "color": [0, 255, 0], + "border_size": 4 + }, + "draw_looked_aoi": { + "color": [0, 255, 0], + "border_size": 2 + }, + "looked_aoi_name_color": [255, 255, 255], + "looked_aoi_name_offset": [0, -10] + } + } + }, + "draw_gaze_position": { + "color": [0, 255, 255] + } +} + +# Pass image parameters to ArFrame +ar_frame_image = ar_frame.image(**image_parameters) + +# Do something with ArFrame image +... +``` + +## Configure ArFrame image parameters + +[ArFrame.image](../../argaze.md/#argaze.ArFeatures.ArFrame.image) method parameters can also be configured thanks to a dedicated JSON entry. + +Here is the JSON ArFrame configuration file example with image parameters included: + +```json +{ + "name": "My FullHD screen", + "size": [1920, 1080], + ... + "image_parameters": { + "draw_scan_path": { + "draw_fixations": { + "deviation_circle_color": [255, 0, 255], + "duration_border_color": [127, 0, 127], + "duration_factor": 1e-2 + }, + "draw_saccades": { + "line_color": [255, 0, 255] + }, + "deepness": 0 + }, + "draw_layers": { + "MyLayer": { + "draw_aoi_scene": { + "draw_aoi": { + "color": [255, 255, 255], + "border_size": 1 + } + }, + "draw_aoi_matching": { + "draw_matched_fixation": { + "deviation_circle_color": [255, 255, 255] + }, + "draw_matched_fixation_positions": { + "position_color": [0, 255, 255], + "line_color": [0, 0, 0] + }, + "draw_matched_region": { + "color": [0, 255, 0], + "border_size": 4 + }, + "draw_looked_aoi": { + "color": [0, 255, 0], + "border_size": 2 + }, + "looked_aoi_name_color": [255, 255, 255], + "looked_aoi_name_offset": [0, -10] + } + } + }, + "draw_gaze_position": { + "color": [0, 255, 255] + } + } +} +``` \ No newline at end of file -- cgit v1.1