diff options
-rw-r--r-- | docs/user_guide/gaze_analysis_pipeline/logging.md | 86 | ||||
-rw-r--r-- | src/argaze/__main__.py | 7 | ||||
-rw-r--r-- | src/argaze/utils/demo/gaze_analysis_pipeline.json | 16 | ||||
-rw-r--r-- | src/argaze/utils/demo/recorders.py (renamed from src/argaze/utils/demo/loggers.py) | 25 |
4 files changed, 71 insertions, 63 deletions
diff --git a/docs/user_guide/gaze_analysis_pipeline/logging.md b/docs/user_guide/gaze_analysis_pipeline/logging.md index 6ed497b..6ef3a85 100644 --- a/docs/user_guide/gaze_analysis_pipeline/logging.md +++ b/docs/user_guide/gaze_analysis_pipeline/logging.md @@ -1,30 +1,28 @@ -Log gaze analysis +Record gaze analysis ================= -[ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) analysis can be logged by registering observers to their **look** method. +[ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) analysis can be recorded by registering observers to their **look** method. ## Export gaze analysis to CSV file -[ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) have an observers attribute to enable pipeline execution logging. +[ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) have an *observers* attribute to enable pipeline execution recording. -Here is an extract from the JSON ArFrame configuration file where logging is enabled for the [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and for one [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) by pointing to dedicated Python files: +Here is an extract from the JSON ArFrame configuration file where recording is enabled for the [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and for one [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) by loaded classes from Python files: ```json { "name": "My FullHD screen", "size": [1920, 1080], "observers": { - "my_frame_logger.ScanPathAnalysisLogger": { - "path": "./scan_path_metrics.csv", - "header": ["Timestamp (ms)", "Duration (ms)", "Steps number"] + "my_recorders.ScanPathAnalysisRecorder": { + "path": "./scan_path_metrics.csv" }, ... "layers": { "MyLayer": { "observers": { - "my_layer_logger.AOIScanPathAnalysisLogger": { - "path": "./aoi_scan_path_metrics.csv", - "header": ["Timestamp (ms)", "NGram counts"] + "my_recorders.AOIScanPathAnalysisRecorder": { + "path": "./aoi_scan_path_metrics.csv" } }, ... @@ -36,67 +34,73 @@ Here is an extract from the JSON ArFrame configuration file where logging is ena !!! note [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and its [ArLayers](../../argaze.md/#argaze.ArFeatures.ArLayer) automatically notify **look** method observers after each call. -Here is *my_frame_logger.py* file: +Here is *my_recorders.py* file: ```python -from argaze import DataFeatures -from argaze.GazeAnalysis import Basic from argaze.utils import UtilsFeatures -class ScanPathAnalysisLogger(DataFeatures.PipelineStepObserver, UtilsFeatures.FileWriter): +class ScanPathAnalysisRecorder(UtilsFeatures.FileWriter): + + def __init__(self, **kwargs): + + # Init FileWriter + super().__init__(**kwargs) + + # Edit hearder line + self.header = "Timestamp (ms)", "Duration (ms)", "Steps number" def on_look(self, timestamp, ar_frame, exception): - """Log scan path metrics""" + """Record scan path metrics""" if ar_frame.is_analysis_available(): analysis = ar_frame.analysis() - log = ( + data = ( timestamp, - analysis[Basic.ScanPathAnalyzer].path_duration, - analysis[Basic.ScanPathAnalyzer].steps_number + analysis['argaze.GazeAnalysis.Basic.ScanPathAnalyzer'].path_duration, + analysis['argaze.GazeAnalysis.Basic.ScanPathAnalyzer'].steps_number ) # Write to file - self.write(log) -``` + self.write(data) -Assuming that [ArGaze.GazeAnalysis.Basic](../../argaze.md/#argaze.GazeAnalysis.Basic) scan path analysis module is enabled for 'My FullHD screen' ArFrame, a ***scan_path_metrics.csv*** file would be created: +class AOIScanPathAnalysisRecorder(UtilsFeatures.FileWriter): -|Timestamp (ms)|Duration (ms)|Steps number| -|:-------------|:------------|:-----------| -|3460 |1750 |2 | -|4291 |2623 |3 | -|4769 |3107 |4 | -|6077 |4411 |5 | -|6433 |4760 |6 | -|7719 |6050 |7 | -|... |... |... | + def __init__(self, **kwargs): -Here is *my_layer_logger.py* file: + # Init FileWriter + super().__init__(**kwargs) -```python -from argaze import DataFeatures -from argaze.GazeAnalysis import NGram -from argaze.utils import UtilsFeatures - -class AOIScanPathAnalysisLogger(DataFeatures.PipelineStepObserver, UtilsFeatures.FileWriter): + # Edit header line + self.header = "Timestamp (ms)", "NGram counts" def on_look(self, timestamp, ar_layer, exception): - """Log aoi scan path metrics.""" + """Record aoi scan path metrics.""" if ar_layer.is_analysis_available(): - log = ( + data = ( timestamp, - ar_layer.analysis[NGram.AOIScanPathAnalyzer].ngrams_count + ar_layer.analysis['argaze.GazeAnalysis.NGram.AOIScanPathAnalyzer'].ngrams_count ) # Write to file - self.write(log) + self.write(data) ``` +Assuming that [ArGaze.GazeAnalysis.Basic](../../argaze.md/#argaze.GazeAnalysis.Basic) scan path analysis module is enabled for 'My FullHD screen' ArFrame, a ***scan_path_metrics.csv*** file would be created: + +|Timestamp (ms)|Duration (ms)|Steps number| +|:-------------|:------------|:-----------| +|3460 |1750 |2 | +|4291 |2623 |3 | +|4769 |3107 |4 | +|6077 |4411 |5 | +|6433 |4760 |6 | +|7719 |6050 |7 | +|... |... |... | + Assuming that [ArGaze.GazeAnalysis.NGram](../../argaze.md/#argaze.GazeAnalysis.NGram) AOI scan path analysis module is enabled for 'MyLayer' ArLayer, a ***aoi_scan_path_metrics.csv*** file would be created: |Timestamp (ms)|NGram counts| diff --git a/src/argaze/__main__.py b/src/argaze/__main__.py index 0682583..0184d69 100644 --- a/src/argaze/__main__.py +++ b/src/argaze/__main__.py @@ -21,7 +21,7 @@ import logging import contextlib from .DataFeatures import from_json -from .ArFeatures import ArCamera +from .ArFeatures import ArCamera, ArContext import cv2 @@ -38,6 +38,11 @@ logging.basicConfig(format = '%(levelname)s: %(message)s', level = logging.DEBUG # Load context from JSON file with from_json(args.context_file) as context: + # Loaded object must be a subclass of ArContext + if not issubclass(type(context), ArContext): + + raise TypeError('Loaded object is not a subclass of ArContext') + if args.verbose: print(context) diff --git a/src/argaze/utils/demo/gaze_analysis_pipeline.json b/src/argaze/utils/demo/gaze_analysis_pipeline.json index 0d1062b..291b3e1 100644 --- a/src/argaze/utils/demo/gaze_analysis_pipeline.json +++ b/src/argaze/utils/demo/gaze_analysis_pipeline.json @@ -49,8 +49,8 @@ "argaze.GazeAnalysis.Entropy.AOIScanPathAnalyzer":{} }, "observers": { - "loggers.AOIScanPathAnalysisLogger": { - "path": "_export/logs/aoi_scan_path_metrics.csv" + "recorders.AOIScanPathAnalysisRecorder": { + "path": "_export/records/aoi_scan_path_metrics.csv" } } } @@ -115,14 +115,14 @@ } }, "observers": { - "loggers.FixationLogger": { - "path": "_export/logs/fixations.csv" + "recorders.FixationRecorder": { + "path": "_export/records/fixations.csv" }, - "loggers.ScanPathAnalysisLogger": { - "path": "_export/logs/scan_path_metrics.csv" + "recorders.ScanPathAnalysisRecorder": { + "path": "_export/records/scan_path_metrics.csv" }, - "loggers.VideoRecorder": { - "path": "_export/logs/video.mp4", + "recorders.VideoRecorder": { + "path": "_export/records/video.mp4", "width": 1920, "height": 1080, "fps": 15 diff --git a/src/argaze/utils/demo/loggers.py b/src/argaze/utils/demo/recorders.py index 25b55d3..75bca70 100644 --- a/src/argaze/utils/demo/loggers.py +++ b/src/argaze/utils/demo/recorders.py @@ -19,10 +19,9 @@ __license__ = "GPLv3" import logging from argaze import DataFeatures, GazeFeatures -from argaze.GazeAnalysis import * from argaze.utils import UtilsFeatures -class FixationLogger(UtilsFeatures.FileWriter): +class FixationRecorder(UtilsFeatures.FileWriter): def __init__(self, **kwargs): @@ -47,7 +46,7 @@ class FixationLogger(UtilsFeatures.FileWriter): self.write(log) -class ScanPathAnalysisLogger(UtilsFeatures.FileWriter): +class ScanPathAnalysisRecorder(UtilsFeatures.FileWriter): def __init__(self, **kwargs): @@ -66,11 +65,11 @@ class ScanPathAnalysisLogger(UtilsFeatures.FileWriter): log = ( timestamp, - analysis[Basic.ScanPathAnalyzer].path_duration, - analysis[Basic.ScanPathAnalyzer].steps_number, - analysis[KCoefficient.ScanPathAnalyzer].K, - analysis[NearestNeighborIndex.ScanPathAnalyzer].nearest_neighbor_index, - analysis[ExploreExploitRatio.ScanPathAnalyzer].explore_exploit_ratio + analysis['argaze.GazeAnalysis.Basic.ScanPathAnalyzer'].path_duration, + analysis['argaze.GazeAnalysis.Basic.ScanPathAnalyzer'].steps_number, + analysis['argaze.GazeAnalysis.KCoefficient.ScanPathAnalyzer'].K, + analysis['argaze.GazeAnalysis.NearestNeighborIndex.ScanPathAnalyzer'].nearest_neighbor_index, + analysis['argaze.GazeAnalysis.ExploreExploitRatio.ScanPathAnalyzer'].explore_exploit_ratio ) self.write(log) @@ -88,7 +87,7 @@ class VideoRecorder(UtilsFeatures.VideoWriter): self.write(frame.image()) -class AOIScanPathAnalysisLogger(UtilsFeatures.FileWriter): +class AOIScanPathAnalysisRecorder(UtilsFeatures.FileWriter): def __init__(self, **kwargs): @@ -107,10 +106,10 @@ class AOIScanPathAnalysisLogger(UtilsFeatures.FileWriter): log = ( timestamp, - analysis[Basic.AOIScanPathAnalyzer].path_duration, - analysis[Basic.AOIScanPathAnalyzer].steps_number, - analysis[KCoefficient.AOIScanPathAnalyzer].K, - analysis[LempelZivComplexity.AOIScanPathAnalyzer].lempel_ziv_complexity + analysis['argaze.GazeAnalysis.Basic.AOIScanPathAnalyzer'].path_duration, + analysis['argaze.GazeAnalysis.Basic.AOIScanPathAnalyzer'].steps_number, + analysis['argaze.GazeAnalysis.KCoefficient.AOIScanPathAnalyzer'].K, + analysis['argaze.GazeAnalysis.LempelZivComplexity.AOIScanPathAnalyzer'].lempel_ziv_complexity ) self.write(log) |