mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 01:00:06 +02:00
frame-eyes, a separate project until now, becomes gaze/tracker:
- ft-eyegrab (was fe-bufprobe) copies the eye-camera frames, read-only, out of
SteamVR's eyetracking process. It runs as the system service
frametop-eyegrab.service, which gaze/tracker/install.sh installs to
/etc/frametop with sudo. It keeps only CAP_SYS_PTRACE, CAP_DAC_READ_SEARCH, and
CAP_CHOWN, and copies frames only while /dev/shm/frametop-eyes-want is fresh,
holding none of the tracker's buffers otherwise.
- ft-eyes (was fe-trackd) runs under ft-gazed in the dev container, with
build/venv's pinned numpy and OpenCV: while Eye tracker is Own tracker, or on
the probe's lease ("eyes SECONDS"). No sudo password or fe-live script at
run time any more.
- lab/ holds the research tools (ft-eyes-score, -e2e, -record, -replay,
-session) and findings.md. Recordings live outside the repo, in
~/.local/share/frametop/eyes/captures; .gitignore catches stray frame dumps.
Its socket is now @ft_eyes, its output /dev/shm/frametop-eyes-gaze, and its state
~/.local/state/frametop/gaze/eyes. On practice1 -> practice2 the whole live path
(ft-eyes-e2e) gives 1.30 deg median and 3.18 for the worst tenth, as before the
move (1.30, 3.21).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
32 lines
1.1 KiB
Python
32 lines
1.1 KiB
Python
"""What the lab tools share: where recordings are kept, and the tracker's modules.
|
|
|
|
Recordings of the eye cameras are biometric data. They're kept outside the repo, in
|
|
~/.local/share/frametop/eyes/captures (FT_EYES_CAPTURES overrides), one folder each, 0700,
|
|
and never leave the Frame except for the 7i's copies frame-job makes for offline jobs.
|
|
"""
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
TRACKER = Path(__file__).resolve().parents[1] # gaze/tracker: ft-eyes, eyes_model, eyes_pupil
|
|
LAB = Path(__file__).resolve().parent
|
|
CAPTURES = Path(os.environ.get("FT_EYES_CAPTURES", Path.home() / ".local/share/frametop/eyes/captures"))
|
|
sys.path.insert(0, str(TRACKER))
|
|
|
|
|
|
def capture(arg):
|
|
"""A recording's folder: a path as given, or a bare name in CAPTURES."""
|
|
p = Path(arg).expanduser()
|
|
return p if p.exists() or os.sep in arg else CAPTURES / arg
|
|
|
|
|
|
def new_capture(name):
|
|
"""A new, private recording folder in CAPTURES; exits if it's already there."""
|
|
out = CAPTURES / name
|
|
if out.exists():
|
|
sys.exit(f"{out} exists")
|
|
out.mkdir(parents=True)
|
|
for d in (CAPTURES, out):
|
|
d.chmod(0o700)
|
|
return out
|