aboutsummaryrefslogtreecommitdiff
path: root/docs/user_guide/gaze_analysis_pipeline/logging.md
blob: 48808cc9e60dfcf06266060f34f684e286ceac33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
Log 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.

## 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.

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:

```json
{
    "name": "My FullHD screen",
    "size": [1920, 1080],
    "observers": "my_frame_logger.py",
    ...
    "layers": {
        "MyLayer": {
            "observers": "my_layer_logger.py",
            ...
        }
    }
}
```

!!! 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:

```python
from argaze import DataFeatures
from argaze.utils import UtilsFeatures

class ScanPathAnalysisLogger(DataFeatures.PipelineStepObserver, UtilsFeatures.FileWriter):

    def on_look(self, timestamp, ar_frame, exception):
        """Log scan path metrics"""

        if ar_frame.analysis_available:

            log = (
                timestamp, 
                ar_frame.scan_path_analyzers['argaze.GazeAnalysis.Basic'].path_duration, 
                ar_frame.scan_path_analyzers['argaze.GazeAnalysis.Basic'].steps_number
            )

            # Write to file
            self.write(log)

# Export logger as observer
__observers__ = {
    "Scan path analysis logger": ScanPathAnalysisLogger(path="./scan_path_metrics.csv", header=("Timestamp (ms)", "Duration (ms)", "Steps number"))
    }
```

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           |
|...           |...          |...         |

Here is *my_layer_logger.py* file:

```python
from argaze import DataFeatures
from argaze.utils import UtilsFeatures

class AOIScanPathAnalysisLogger(DataFeatures.PipelineStepObserver, UtilsFeatures.FileWriter):

    def on_look(self, timestamp, ar_layer, exception):
        """Log aoi scan path metrics."""

        if ar_layer.analysis_available:

            log = (
                timestamp,
                ar_layer.aoi_scan_path_analyzers['argaze.GazeAnalysis.NGram'].ngrams_count
            )

            # Write to file
            self.write(log)

# Export logger as observer
__observers__ = {
    "AOI Scan path analysis logger": AOIScanPathAnalysisLogger(path="./aoi_scan_path_metrics.csv", header=("Timestamp (ms)", "NGram counts"))
    }
```

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|
|:-------------|:-----------|
|5687          |"{3: {}, 4: {}, 5: {}}"|
|6208          |"{3: {('LeftPanel', 'GeoSector', 'CircularWidget'): 1}, 4: {}, 5: {}}"|
|...           |...         |

!!! note ""

    Learn to [script the pipeline](./advanced_topics/scripting.md) to know more about [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayers](../../argaze.md/#argaze.ArFeatures.ArLayer) attributes.

### Export gaze analysis to video file

As explained in [pipeline steps visualisation chapter](visualisation.md), it is possible to get [ArFrame.image](../../argaze.md/#argaze.ArFeatures.ArFrame.image) once timestamped gaze positions have been processed by [ArFrame.look](../../argaze.md/#argaze.ArFeatures.ArFrame.look) method.

```python
from argaze import DataFeatures
from argaze.utils import UtilsFeatures

class VideoRecorder(DataFeatures.PipelineStepObserver, UtilsFeatures.VideoWriter):

    def on_look(self, timestamp, ar_frame, exception):
        """Record frame image into video file."""

        self.write(ar_frame.image())

# Export recorder as observer
__observers__ = {
    "Video recorder": VideoRecorder(path="./video.mp4", width=1920, height=1080, fps=15)
    }
```

Assuming that [ArFrame.image_parameters](../../argaze.md/#argaze.ArFeatures.ArFrame.image_parameters) are provided, ***video.mp4*** file would be created.