cli: Add guided `calibrate-liveness` command
The guided live-vs-spoof profiling workflow that turns the liveness
checks' guessed thresholds into data-derived ones. Incremental and
GUI-shaped — each invocation does one thing, accumulating into a
persisted profile:
- `capture <class> [--label .. --append --conditions ..]` — capture a
labeled batch (live / printed-photo / screen / other). Opens the IR
camera, runs the same detect → liveness-policy pipeline auth uses,
harvests each check's sub-score `detail` into a feature vector, and
folds the batch into the profile (replacing the class, or appending).
- `status` — per-class sample counts.
- `report` — per-feature live-vs-spoof separation (means ± std, d-prime).
- `suggest-threshold` — per-feature threshold separating live from each
spoof, with the false-reject / false-accept it would incur.
- `reset [<class>]` — clear all, or one class.
Each verb is one core operation, so a future GUI can drive the same
flow — and because core ingests caller-supplied frames/features, a GUI
that owns the camera for preview can feed its own frames rather than
contend for the device.
Features are namespaced by check (e.g. `nir_reflectance.brightness`) so
multiple checks' sub-scores don't collide. A no-face capture (e.g. a
screen that's dark in IR) is skipped and counted — and an all-skipped
batch errors with a note that no-face is itself the dual-modality
defense. Gated on v4l2+inference with an arg-compatible fallback;
verified the --no-default-features build still compiles.
cli: Add guided `calibrate-liveness` command
The guided live-vs-spoof profiling workflow that turns the liveness
checks' guessed thresholds into data-derived ones. Incremental and
GUI-shaped — each invocation does one thing, accumulating into a
persisted profile:
- `capture <class> [--label .. --append --conditions ..]` — capture a
labeled batch (live / printed-photo / screen / other). Opens the IR
camera, runs the same detect → liveness-policy pipeline auth uses,
harvests each check's sub-score `detail` into a feature vector, and
folds the batch into the profile (replacing the class, or appending).
- `status` — per-class sample counts.
- `report` — per-feature live-vs-spoof separation (means ± std, d-prime).
- `suggest-threshold` — per-feature threshold separating live from each
spoof, with the false-reject / false-accept it would incur.
- `reset [<class>]` — clear all, or one class.
Each verb is one core operation, so a future GUI can drive the same
flow — and because core ingests caller-supplied frames/features, a GUI
that owns the camera for preview can feed its own frames rather than
contend for the device.
Features are namespaced by check (e.g. `nir_reflectance.brightness`) so
multiple checks' sub-scores don't collide. A no-face capture (e.g. a
screen that's dark in IR) is skipped and counted — and an all-skipped
batch errors with a note that no-face is itself the dual-modality
defense. Gated on v4l2+inference with an arg-compatible fallback;
verified the --no-default-features build still compiles.