monitor selection, model prototype and 2 more recordings
This commit is contained in:
@@ -18,6 +18,19 @@ Press `Esc` or `Q` to close it. For a preview in a normal resizable window:
|
||||
python show_apriltag_surface.py --windowed
|
||||
```
|
||||
|
||||
On a multi-monitor setup, list detected displays (Windows display number,
|
||||
resolution, position, physical diagonal) and target one of them:
|
||||
|
||||
```powershell
|
||||
python show_apriltag_surface.py --list-monitors
|
||||
python show_apriltag_surface.py --monitor 2
|
||||
```
|
||||
|
||||
`gaze_exercises.py` accepts the same `--monitor`/`--list-monitors` flags and
|
||||
uses the selected monitor's resolution and EDID-reported diagonal
|
||||
automatically, so `--screen-diagonal` only needs to be passed to override an
|
||||
inaccurate or missing EDID value.
|
||||
|
||||
By default, every marker is flush with both adjacent screen edges. Useful
|
||||
options include `--tag-size 240`, `--margin 32`, and
|
||||
`--tag-ids 10 11 12 13`. The requested size is rounded down to a multiple of
|
||||
@@ -126,6 +139,55 @@ CSV columns beyond the basic error metrics:
|
||||
every row so CSVs from different subjects, screens, and distances can be
|
||||
concatenated directly for training/evaluation.
|
||||
|
||||
## Training the adaptive filter
|
||||
|
||||
Once you have one or more recordings in `results/`:
|
||||
|
||||
```powershell
|
||||
python train_filter_model.py
|
||||
```
|
||||
|
||||
This concatenates every `gaze_exercises_*.csv`, builds causal windowed
|
||||
features (`gaze_features.py`), splits by whole trial (never by row, to avoid
|
||||
leaking adjacent-in-time samples between train/test), trains a
|
||||
`RandomForestClassifier` predicting `event_label`, and compares it against a
|
||||
fixed 30 deg/s velocity-threshold baseline. It prints per-class precision/
|
||||
recall, a confusion matrix, a saccade-recovery detection-latency comparison,
|
||||
and feature importances, then saves `models/filter_model.joblib` +
|
||||
`models/filter_model_meta.json`.
|
||||
|
||||
With only one subject/session recorded, the split holds out unseen trials
|
||||
within that session — it does not yet test cross-subject generalization.
|
||||
Once more subjects are recorded, re-run training; group the split by
|
||||
`subject_id` (leave-one-subject-out) instead of by trial for the real paper
|
||||
evaluation.
|
||||
|
||||
`adaptive_filter.py` defines the real-time filters built on that model:
|
||||
`BaselineFilter` (the existing fixed median+EMA filter), and
|
||||
`MLAdaptiveFilter` in `mode="hard"` (discrete fixation/saccade/pursuit
|
||||
switching that discards history on a detected saccade) or `mode="soft"`
|
||||
(continuous smoothing strength scaled by predicted saccade probability).
|
||||
|
||||
## Held-out evaluation: static fixation
|
||||
|
||||
`gaze_exercises.py` is what the model trains on, so it can't validate
|
||||
generalization by itself. `eval_static_fixation.py` runs a task shape the
|
||||
model has never seen — one unmoving target held for a long duration — and
|
||||
reports RMS error, mean error, and on-target accuracy % for raw gaze, the
|
||||
fixed baseline filter, and both ML-adaptive modes side by side:
|
||||
|
||||
```powershell
|
||||
python eval_static_fixation.py --subject-id you --duration 60 --viewing-distance 70 --screen-diagonal 31.5
|
||||
```
|
||||
|
||||
Press Space to start the 60-second hold. Results are saved to
|
||||
`results/eval_static_fixation_<timestamp>.csv` plus a `_meta.json` summary
|
||||
report. If `models/filter_model.joblib` doesn't exist yet, it records raw +
|
||||
baseline only and prints a warning — run `train_filter_model.py` first for
|
||||
the ML columns. A simplified eyes-as-aim game is a planned second held-out
|
||||
evaluation task, to test generalization to fast target-acquisition demands
|
||||
closer to real use.
|
||||
|
||||
Visualize the newest result file with:
|
||||
|
||||
```powershell
|
||||
|
||||
Reference in New Issue
Block a user