Skip to content

Enable face/eye analysis

The closed-eye and blink, facing and expression cull signals come from the face/eye provider. Like every heavy provider it's off by default; cull still judges blur, exposure and near-duplicates without it. Turn it on to add the face signals.

Turn it on

Set face.enabled in your config, either in the config file:

face:
  enabled: true

or via an environment variable:

export KRITES_FACE_ENABLED=true

On the next cull, krites fetches and verifies the models and the ONNX Runtime library (once each), then runs them on your machine; no frame leaves it. There's no runtime to install or path to set. The macOS app carries the library inside it, every other build fetches it from the signed artefact channel, and onnxruntime.library_path is an optional override; see the config reference.

The first cull after turning this on re-analyses every frame, because the cached measurements were taken without it. On a full wedding that's minutes.

Apple Silicon

Run the models on the CoreML execution provider (falls back to CPU if unavailable):

face:
  execution_provider: coreml

What you get: the mediapipe strategy

Turning face analysis on uses the mediapipe strategy unless you choose otherwise. A detector (YuNet by default) finds the faces, then two MediaPipe models, FaceMesh and blendshapes, run on each face. From them krites reads the eyes, which way the face is turned, and a trained read of smile, frown and a grumpy-to-happy valence.

The studio's Expression axis shows that valence, averaged across the frame's faces. A single unsmiling guest doesn't drag a whole group shot to "grumpy", and a genuinely frowning face reads negative rather than merely "not smiling". The tunable Duchenne and brow weights are in the config reference.

The other strategy, ear, reads eyes and a geometric smile from InsightFace's 2d106det landmarks instead. It's an opt-in fallback, and not the default because 2d106det is licensed for non-commercial use only:

face:
  enabled: true
  strategy: ear

Re-cull after switching strategy. The first cull afterwards re-analyses every frame, because the cached measurements came from the other strategy.

Unlike the other models (fetched from third-party hosts and pinned by checksum), these two come from the estate's approved artefact channel at artifacts.phpboyscout.uk, the same channel and the same trust anchor krites uses for the ONNX Runtime. On first use krites reads the channel's signed index and the model's signed manifest, accepts the signature only when the release key embedded in the binary and the key published over WKD agree, fetches the file, and checks its digest against both the manifest and the digest compiled into this release. A failure at any step refuses the model rather than using it. Once a model is in the cache and matches the compiled-in digest it is used without any network access, so culling offline works after the first fetch. The channel's index carries each model's licence (Apache-2.0, cleared for commercial use) and conversion record.

Tune the thresholds

The eye, smile and facing cutoffs are starting points. For example, to treat eyes as closed more readily, raise face.ear.closed. All keys and their defaults are in the configuration reference; the reasoning is in Why the heavy providers are opt-in.

Then re-cull to apply:

krites cull --shoot ~/Pictures/smith-wedding

These face.* values are applied while measuring, not while judging, so the first cull after changing one re-analyses every frame. The cull profile's own thresholds (cull.profile.*) are applied while judging, so changing one of those re-culls in seconds from the cached measurements.