diff --git a/FAQ.md b/FAQ.md index 0e1cc88..00bcd1f 100644 --- a/FAQ.md +++ b/FAQ.md @@ -8,9 +8,14 @@ No. winnow only reads from Immich (assets, people, face bounding boxes). It neve ## How many images should I upload to Frigate? -The `auto` strategy decides this for you — it keeps selecting until adding more images would be redundant. In practice this is usually 20–60 per person. You can cap it with `MAX_AUTO_IMAGES` (default 80). +The `auto` strategy decides this for you — it keeps selecting until adding more images would be redundant. In practice this is usually 20–60 per person. You can cap it with `MAX_AUTO_IMAGES` (default `80`). -When winnow reaches the cap on subsequent runs, `QUALITY_REPLACEMENT=true` (default) lets it swap out the lowest-scoring existing image if a better candidate is found — so the training set improves over time rather than stalling. Only images winnow uploaded are ever replaced; anything added manually through Frigate's UI is never touched. +When winnow reaches the cap on subsequent runs, `QUALITY_REPLACEMENT=true` (default) lets it improve the training set rather than stalling: + +- **With Frigate scores** (default, after the first run): targets the most *redundant* existing file — the one Frigate already recognizes most confidently — and replaces it only if the new candidate is more *novel* (scores lower). This keeps the set maximally diverse. +- **Without Frigate scores** (first run, or `ENABLE_FRIGATE_SCORES=false`): falls back to blur scores — replaces the blurriest existing file if the candidate is sharper. + +Only files winnow uploaded are ever replaced. Anything added manually through Frigate's UI is never touched. Quality and diversity matter far more than volume. 30 well-spread images outperform 200 from the same week. diff --git a/Home.md b/Home.md index 295ceca..2e2380e 100644 --- a/Home.md +++ b/Home.md @@ -4,6 +4,8 @@ winnow pulls photos from [Immich](https://immich.app), selects diverse high-qual It runs fully headless in Docker, is configured entirely through environment variables, and can run on a schedule. +> **winnow only touches files it uploaded.** Faces added to Frigate manually through its UI are never deleted, replaced, or modified — not by quality replacement, not by `RESET_PERSON`, not by stale cleanup. If you have a curated training set, it is safe. + ## Pages - [[Setup]] — installation, Docker Compose configuration, GPU passthrough, environment variables diff --git a/Setup.md b/Setup.md index eff973d..b7197b5 100644 --- a/Setup.md +++ b/Setup.md @@ -163,3 +163,81 @@ Set `VERBOSE=true` in your `.env` to enable DEBUG-level output on the console. T # log file is written to the output volume (frigate_train mount) docker exec winnow cat /app/frigate_train/winnow.log ``` + +--- + +## Environment Variables + +### Connection + +| Variable | Default | Description | +| :--- | :--- | :--- | +| `IMMICH_URL` | *(required)* | Full URL to your Immich instance | +| `API_KEY` | *(required)* | Immich API key | +| `FRIGATE_URL` | *(unset)* | Frigate base URL — required for face upload; omit for object mode only | + +### Mode & Strategy + +| Variable | Default | Description | +| :--- | :--- | :--- | +| `TRAINING_MODE` | `face` | `face` — upload crops to Frigate; `object` — save crops to disk | +| `STRATEGY` | `auto` | `auto` (embedding-based adaptive), `standard` (30 images), `broad` (100 images) | +| `LIMIT` | *(unset)* | Exact image count — overrides `STRATEGY` | +| `OBJECT_CLASS` | `dog` | Target class for object mode (any YOLO class: `dog`, `cat`, `car`, etc.) | +| `AUTO_MODE` | *(auto)* | Force non-interactive mode in a terminal; auto-detected otherwise | +| `VERBOSE` | `false` | Enable DEBUG-level console output (log file is always DEBUG) | + +### People Filtering + +| Variable | Default | Description | +| :--- | :--- | :--- | +| `ONLY_PEOPLE` | *(unset)* | Comma-separated whitelist — process only these people | +| `SKIP_PEOPLE` | *(unset)* | Comma-separated list — skip these people | +| `MIN_FACE_COUNT` | `0` | Skip people with fewer than N tagged assets in Immich | +| `YEARS_FILTER` | `10` | Ignore images older than N years | + +### Image Quality + +| Variable | Default | Description | +| :--- | :--- | :--- | +| `MIN_FACE_WIDTH` | `90` | Minimum face crop width in pixels | +| `FACE_MARGIN` | `0.15` | Padding around bounding box crop (fraction of face size) | +| `ENABLE_FACE_ALIGNMENT` | `true` | Align to ArcFace 112×112 format using facial landmarks | +| `USE_FULL_RESOLUTION` | `true` | Download full-resolution originals rather than preview thumbnails | +| `MIN_CONFIDENCE` | `0.7` | Minimum Immich face detection confidence | +| `BLUR_THRESHOLD` | `120.0` | Laplacian variance threshold — higher rejects more blur | +| `MAX_AUTO_IMAGES` | `80` | Maximum training images per person in Frigate | +| `QUALITY_REPLACEMENT` | `true` | When at cap, swap a weaker tracked image for a better candidate. With Frigate scoring active, targets the most redundant image (highest recognize score); otherwise uses blur score. Never touches manually added Frigate files. Set `false` to skip people at cap | +| `FRIGATE_SCORE_CEILING` | `0.0` | Skip uploads whose pre-upload Frigate recognize score exceeds this value — they are already well-covered. `0` disables; requires at least one prior run to have scores | +| `ENABLE_FRIGATE_SCORES` | `true` | Call Frigate's recognize endpoint pre-upload to store diversity scores used for quality replacement. Adds ~200 ms per upload. Disable to use blur-score replacement only | + +### GPU & Models + +| Variable | Default | Description | +| :--- | :--- | :--- | +| `FORCE_CPU` | `false` | Disable GPU — fall back to CPU for all inference | +| `OPENVINO_DEVICE` | `CPU` | Intel variant only: set `GPU` to use Arc or iGPU | +| `ENABLE_CACHE` | `true` | Cache computed embeddings to disk (speeds up re-runs on the same library) | +| `CACHE_DIR` | `.if_cache` | Path for embedding cache and upload tracker files | +| `HF_HOME` | *(system)* | HuggingFace model cache path (SigLIP) | +| `INSIGHTFACE_HOME` | *(system)* | InsightFace model cache path (Buffalo_L) | + +### Output + +| Variable | Default | Description | +| :--- | :--- | :--- | +| `OUTPUT_DIR` | `./frigate_train` | Directory for object-mode crops and the `winnow.log` file. In Docker, set this via the volume mount instead | + +### Tracker Overrides *(one-shot — remove after use)* + +| Variable | Default | Description | +| :--- | :--- | :--- | +| `DRY_RUN` | `false` | Preview selection without downloading or uploading | +| `RETRY_REJECTED` | `false` | Re-attempt assets previously rejected by Frigate | +| `RESET_PERSON` | *(unset)* | Clear upload history for one person and delete their winnow-managed Frigate training files so the next run starts fresh. Manually added Frigate files are never touched | + +### Scheduling + +| Variable | Default | Description | +| :--- | :--- | :--- | +| `CRON_SCHEDULE` | *(unset)* | Unset = run once and exit; empty string = stay alive; cron expression = scheduled | diff --git a/Troubleshooting.md b/Troubleshooting.md index e5e1002..62cab54 100644 --- a/Troubleshooting.md +++ b/Troubleshooting.md @@ -155,13 +155,14 @@ To clear the upload history for one person and start fresh: RESET_PERSON=John ``` -Remove this after one run — it clears the history and then processes normally. +Remove this after one run. It deletes winnow-managed Frigate training files for that person, wipes their upload history, then processes normally. Manually-added Frigate files are never touched. --- ## Image quality issues -- **Too blurry**: Lower `BLUR_THRESHOLD` (default 100) — e.g. `50` accepts more blur -- **Face too small**: Lower `MIN_FACE_WIDTH` (default 50px) -- **Low confidence detections included**: Raise `MIN_CONFIDENCE` (default 0.7) +- **Too many blurry images selected**: Raise `BLUR_THRESHOLD` (default `120.0`) — higher values require sharper images; e.g. `200` is stricter +- **Too many images rejected as blurry**: Lower `BLUR_THRESHOLD` — e.g. `80` accepts more blur +- **Face too small**: Lower `MIN_FACE_WIDTH` (default `90px`) +- **Low confidence detections included**: Raise `MIN_CONFIDENCE` (default `0.7`) - **Rejected images being re-tried**: Set `RETRY_REJECTED=true` for one run