diff --git a/gaze/README.md b/gaze/README.md index 8143f51..3346530 100644 --- a/gaze/README.md +++ b/gaze/README.md @@ -63,7 +63,7 @@ Ground rules, for anyone changing it: - **Clean room.** Nothing of Valve's goes in: we don't decompile, disassemble, or patch the `eyetracking` binary or its network weights, and we don't copy their code or weights. Its public output (eye-server.mmap, read-only) is fair game as a baseline and as labels, and so are published papers and openly licensed pupil detectors (check each one's license: PuRe, PuReST, ElSe, and ExCuSe are non-commercial only). - **Root only reads.** ft-eyegrab never writes to, stops, or signals the `eyetracking` process, vrserver, or vrcompositor, never opens `/dev/adsp`, `/dev/cdsp`, or `/dev/spidev0.1`, and never writes to `/dev/shm/eye-server.mmap` (it also carries calibration clicks into SteamVR's tracker), `/opt`, or `/persist`. - **Eye images are biometric data.** Recordings live outside the repo, in `~/.local/share/frametop/eyes/captures` (0700), and `.gitignore` catches stray frame dumps. They go nowhere but the machine that runs your offline jobs. -- **Mind the headset's budget.** Finding a pupil takes about 0.4 ms a frame while ft-eyes follows it, and 1.4-2.1 ms when it searches the whole frame. Replays, scoring, and training go to a PC. +- **Mind the headset's budget.** Finding a pupil takes about 0.4 ms a frame while ft-eyes follows it, and 1.4-2.1 ms when it searches the whole frame. ft-eyes keeps OpenCV and numpy to one thread: their pools of one per core spun idle workers at about a quarter of a core, for frames this small. Replays, scoring, and training go to a PC. ## Headset fit diff --git a/gaze/tracker/eyes_pupil.py b/gaze/tracker/eyes_pupil.py index 8884363..cf3672d 100644 --- a/gaze/tracker/eyes_pupil.py +++ b/gaze/tracker/eyes_pupil.py @@ -9,7 +9,12 @@ the search runs again with a smaller closing. import cv2 import numpy as np -DARK = 30 # pupil pixels are below this (the face around it is 40-180) +# One thread: OpenCV's pool of one per core costs more than it saves on a frame this small +# (a 140-240 px window while it follows the pupil). Its idle workers spun and yielded about +# 14,000 times a second each, a quarter of a core, beside SteamVR's compositor. +cv2.setNumThreads(1) + +DARK = 30 # pupil pixels are below this (the face around it is 40-180) MIN_AREA = 150 # pupil area range in pixels MAX_AREA = 20000 MIN_FILL = 0.75 # blob area / fitted-ellipse area diff --git a/gaze/tracker/ft-eyes b/gaze/tracker/ft-eyes index 5e25799..66bbff7 100755 --- a/gaze/tracker/ft-eyes +++ b/gaze/tracker/ft-eyes @@ -58,7 +58,12 @@ import time from collections import deque from pathlib import Path -import numpy as np +# One thread for numpy's BLAS and OpenMP, set before numpy loads: it would start one per core +# (8 here) for small arrays that never need them. eyes_pupil keeps OpenCV to one as well. +for _var in ("OPENBLAS_NUM_THREADS", "OMP_NUM_THREADS"): + os.environ.setdefault(_var, "1") + +import numpy as np # noqa: E402 sys.path.insert(0, str(Path(__file__).resolve().parent)) import eyes_model # noqa: E402