chore: establish authorship — Holden Salomon
- LICENSE: add copyright line for Holden Salomon (retain original) - pyproject.toml: update authors to Holden Salomon <holden@arch.fyi> - README: lead with what the software does rather than fork attribution; merge split env var tables into one unified reference; add lint/test badges; move attribution to footer Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Holden Salomon
|
||||||
Copyright (c) 2026 Sebastian
|
Copyright (c) 2026 Sebastian
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
|||||||
@@ -1,30 +1,20 @@
|
|||||||
[](https://github.com/sudolulo/if_curator_headless/actions/workflows/docker-publish.yml) [](https://github.com/sudolulo/if_curator_headless/actions/workflows/release.yml)
|
[](https://github.com/sudolulo/if_curator_headless/actions/workflows/docker-publish.yml) [](https://github.com/sudolulo/if_curator_headless/actions/workflows/release.yml) [](https://github.com/sudolulo/if_curator_headless/actions/workflows/lint.yml) [](https://github.com/sudolulo/if_curator_headless/actions/workflows/test.yml)
|
||||||
### if-curator-headless
|
|
||||||
|
|
||||||
Headless fork of [if-curator](https://github.com/ds-sebastian/if_curator) with automatic Frigate face training upload and Docker support.
|
### if-curator-headless
|
||||||
|
|
||||||
> *A specialized tool to extract **high-quality, diverse** training images from your Immich library for Frigate's Face Recognition (ArcFace) and Object/State Classification models.*
|
> *A specialized tool to extract **high-quality, diverse** training images from your Immich library for Frigate's Face Recognition (ArcFace) and Object/State Classification models.*
|
||||||
|
|
||||||
## What This Adds
|
Runs headless in Docker with full GPU acceleration, automatic Frigate upload, cron scheduling, and env-var-driven configuration — no interactive prompts required.
|
||||||
|
|
||||||
- **Headless mode** — runs without interactive prompts, suitable for Docker and cron
|
|
||||||
- **Auto-discover people** — processes all named people from Immich automatically instead of picking one at a time
|
|
||||||
- **Frigate upload** — sends curated face crops directly to Frigate's face training API after processing
|
|
||||||
- **People filtering** — skip specific people, whitelist only certain people, or set a minimum photo count
|
|
||||||
- **Docker** — pre-built image with NVIDIA GPU support, ready for TrueNAS
|
|
||||||
- **Scheduling** - Use cron notation to schedule runs
|
|
||||||
|
|
||||||
All of if-curator's original functionality is unchanged.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Why This Tool??
|
## Why This Tool?
|
||||||
|
|
||||||
> **"Diversity matters far more than volume."** — *Frigate Developer Tips*
|
> **"Diversity matters far more than volume."** — *Frigate Developer Tips*
|
||||||
|
|
||||||
Training AI models on "bulk" data is often harmful. If you feed the model 50 images from the same 10-second video clip, it learns to recognize the *lighting and background*, not the actual *face* or *object*.
|
Training AI models on bulk data is often harmful. Feed the model 50 images from the same 10-second video clip and it learns the *lighting and background*, not the actual *face* or *object*.
|
||||||
|
|
||||||
`if-curator` solves this using **AI-powered diversity selection** and **quality filtering**:
|
`if-curator-headless` solves this using **AI-powered diversity selection** and **quality filtering**:
|
||||||
|
|
||||||
| Mode | Embedding Model | Algorithm |
|
| Mode | Embedding Model | Algorithm |
|
||||||
| :--- | :--- | :--- |
|
| :--- | :--- | :--- |
|
||||||
@@ -39,20 +29,21 @@ Training AI models on "bulk" data is often harmful. If you feed the model 50 ima
|
|||||||
- **Auto Diversity [Recommended]**: Clusters images by visual similarity, selects representatives from each cluster, then fills with maximally-diverse picks until redundancy starts (capped at 80)
|
- **Auto Diversity [Recommended]**: Clusters images by visual similarity, selects representatives from each cluster, then fills with maximally-diverse picks until redundancy starts (capped at 80)
|
||||||
- **Standard (30 images)**: Balanced set using Smart Diversity
|
- **Standard (30 images)**: Balanced set using Smart Diversity
|
||||||
- **Broad (100 images)**: Extensive set using Smart Diversity
|
- **Broad (100 images)**: Extensive set using Smart Diversity
|
||||||
- **Custom Count**: You choose the limit
|
- **Custom Count**: Set `LIMIT=N` for any exact number
|
||||||
|
|
||||||
### Quality Filtering
|
### Quality Filtering
|
||||||
Bad training data hurts ArcFace models. Images are automatically rejected if they are:
|
Images are automatically rejected if they are:
|
||||||
- **Blurry** — Laplacian variance below threshold
|
- **Blurry** — Laplacian variance below threshold
|
||||||
- **Grayscale / IR** — ArcFace is trained on color images only
|
- **Grayscale / IR** — ArcFace is trained on color images only
|
||||||
- **Over/Underexposed** — Washed-out or too dark to use
|
- **Over/Underexposed** — Washed-out or too dark to use
|
||||||
- **Low confidence** — Partial or occluded face detections
|
- **Low confidence** — Partial or occluded face detections
|
||||||
- **Too small** — Faces under 100px (configurable) lack features
|
- **Too small** — Faces under the minimum pixel width lack features
|
||||||
|
|
||||||
### Face Recognition Prep
|
### Face Recognition Prep
|
||||||
- Uses InsightFace embeddings on **face crops** (not full images — avoids wrong-face in group photos)
|
- Uses InsightFace embeddings on **face crops** (not full images — avoids wrong-face in group photos)
|
||||||
- **Hard example prioritization** — unusual angles, sunglasses, and low-confidence detections are biased for selection
|
- **Hard example prioritization** — unusual angles, sunglasses, and low-confidence detections are biased for selection
|
||||||
- **Face alignment** via InsightFace landmarks (standard 112×112 ArcFace input)
|
- **Face alignment** via InsightFace landmarks (standard 112×112 ArcFace input)
|
||||||
|
- **EXIF orientation** applied before cropping so bounding boxes align correctly
|
||||||
- Downloads **full-resolution** originals for final crops (falls back to JPEG preview for HEIC/RAW)
|
- Downloads **full-resolution** originals for final crops (falls back to JPEG preview for HEIC/RAW)
|
||||||
|
|
||||||
### Object/State Classification Prep
|
### Object/State Classification Prep
|
||||||
@@ -60,19 +51,20 @@ Bad training data hurts ArcFace models. Images are automatically rejected if the
|
|||||||
- **YOLOv9c** to detect and crop specific objects (dogs, cars, etc.)
|
- **YOLOv9c** to detect and crop specific objects (dogs, cars, etc.)
|
||||||
- Captures variation in poses, lighting, and backgrounds
|
- Captures variation in poses, lighting, and backgrounds
|
||||||
|
|
||||||
> **Note:** Frigate does not support uploading custom images for object classification training via the UI or API. Object mode crops are saved to disk for manual YOLO model training.
|
> **Note:** Frigate does not support uploading custom images for object classification via the UI or API. Object mode crops are saved to disk for manual YOLO model training.
|
||||||
|
|
||||||
### Performance
|
### Performance
|
||||||
- Concurrent thumbnail downloads (8 parallel workers)
|
- Concurrent thumbnail downloads (8 parallel workers)
|
||||||
- Batch-capable SigLIP embeddings for GPU efficiency
|
- Batch-capable SigLIP embeddings for GPU efficiency
|
||||||
- Optional disk-based embedding cache for faster re-runs
|
- Optional disk-based embedding cache for faster re-runs
|
||||||
|
- Upload deduplication — already-uploaded assets are skipped on future runs
|
||||||
- Multi-person batch mode
|
- Multi-person batch mode
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- **NVIDIA GPU** (recommended) — auto-detects CUDA for faster embedding computation. CPU mode is available via `FORCE_CPU=true` but significantly slower.
|
- **NVIDIA GPU** (recommended) — auto-detects CUDA. CPU mode available via `FORCE_CPU=true` but significantly slower.
|
||||||
- **Python 3.12+**
|
- **Python 3.12+**
|
||||||
- **[uv](https://astral.sh/uv/)**
|
- **[uv](https://astral.sh/uv/)**
|
||||||
- **Immich Server** (v1.106+)
|
- **Immich Server** (v1.106+)
|
||||||
@@ -82,41 +74,78 @@ Bad training data hurts ArcFace models. Images are automatically rejected if the
|
|||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
### New in This Fork
|
### Mode & Strategy
|
||||||
|
|
||||||
| Variable | Default | What it does |
|
| Variable | Default | Description |
|
||||||
| :--- | :--- | :--- |
|
| :--- | :--- | :--- |
|
||||||
| `AUTO_MODE` | `false` | Run without prompts |
|
| `AUTO_MODE` | `false` | Run without interactive prompts |
|
||||||
| `FRIGATE_URL` | *(empty)* | Frigate server URL — auto-uploads faces when set |
|
|
||||||
| `TRAINING_MODE` | `face` | `face` or `object` |
|
| `TRAINING_MODE` | `face` | `face` or `object` |
|
||||||
| `STRATEGY` | `auto` | `auto`, `standard`, or `broad` |
|
| `STRATEGY` | `auto` | `auto`, `standard` (30), or `broad` (100) |
|
||||||
| `SKIP_PEOPLE` | *(empty)* | People to skip |
|
| `LIMIT` | *(unset)* | Custom image count — overrides `STRATEGY` |
|
||||||
| `ONLY_PEOPLE` | *(empty)* | People to process (whitelist) |
|
| `OBJECT_CLASS` | `dog` | Object label for object mode (e.g. `dog`, `cat`, `car`) |
|
||||||
| `MIN_FACE_COUNT` | `3` | Minimum photos required to process a person |
|
|
||||||
| `OBJECT_CLASS` | `dog` | Object type (only for object mode) |
|
|
||||||
|
|
||||||
### Original if-curator Variables
|
### People Filtering
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `ONLY_PEOPLE` | *(unset)* | Comma-separated whitelist of people to process |
|
||||||
|
| `SKIP_PEOPLE` | *(unset)* | Comma-separated list of people to skip |
|
||||||
|
| `MIN_FACE_COUNT` | `0` | Skip people with fewer than N assets in Immich |
|
||||||
|
| `YEARS_FILTER` | `10` | Only include images from the last N years |
|
||||||
|
|
||||||
|
### Connection
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `IMMICH_URL` | *(required)* | Full URL to Immich (e.g. `http://192.168.1.10:2283`) |
|
||||||
|
| `API_KEY` | *(required)* | Your Immich API Key |
|
||||||
|
| `FRIGATE_URL` | *(unset)* | Frigate server URL — enables automatic face upload when set |
|
||||||
|
|
||||||
|
### Image Quality
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `MIN_FACE_WIDTH` | `50` | Minimum face crop width in pixels |
|
||||||
|
| `FACE_MARGIN` | `0.15` | Padding around face crop as a fraction of face size |
|
||||||
|
| `ENABLE_FACE_ALIGNMENT` | `true` | Align face to ArcFace 112×112 format before cropping |
|
||||||
|
| `USE_FULL_RESOLUTION` | `true` | Download full-resolution originals for final crops |
|
||||||
|
| `MIN_CONFIDENCE` | `0.7` | Minimum Immich face detection confidence |
|
||||||
|
| `BLUR_THRESHOLD` | `100.0` | Laplacian variance threshold — lower accepts more blur |
|
||||||
|
| `MAX_AUTO_IMAGES` | `80` | Hard cap on auto-diversity selection |
|
||||||
|
|
||||||
|
### Caching & Models
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
| :--- | :--- | :--- |
|
| :--- | :--- | :--- |
|
||||||
| `IMMICH_URL` | *(prompted)* | Full URL to Immich (e.g. `http://192.168.1.10:2283`) |
|
|
||||||
| `API_KEY` | *(prompted)* | Your Immich API Key |
|
|
||||||
| `FORCE_CPU` | `false` | Disable GPU acceleration |
|
| `FORCE_CPU` | `false` | Disable GPU acceleration |
|
||||||
| `MIN_FACE_WIDTH` | `100` | Minimum face crop size (pixels) |
|
|
||||||
| `BLUR_THRESHOLD` | `100.0` | Laplacian variance threshold for blur detection |
|
|
||||||
| `MIN_CONFIDENCE` | `0.7` | Minimum Immich detection confidence |
|
|
||||||
| `MAX_AUTO_IMAGES` | `80` | Safety cap for auto-diversity mode |
|
|
||||||
| `FACE_MARGIN` | `0.15` | Crop margin around face (fraction) |
|
|
||||||
| `USE_FULL_RESOLUTION` | `true` | Download originals for final crops |
|
|
||||||
| `ENABLE_FACE_ALIGNMENT` | `true` | Align faces to ArcFace 112×112 format |
|
|
||||||
| `ENABLE_CACHE` | `false` | Cache embeddings to disk for faster re-runs |
|
| `ENABLE_CACHE` | `false` | Cache embeddings to disk for faster re-runs |
|
||||||
| `CACHE_DIR` | `.if_cache` | Directory for embedding cache |
|
| `CACHE_DIR` | `.if_cache` | Directory for embedding cache |
|
||||||
|
| `HF_HOME` | *(system)* | Override HuggingFace model cache location |
|
||||||
|
| `INSIGHTFACE_HOME` | *(system)* | Override InsightFace model cache location |
|
||||||
|
|
||||||
|
### Tracker Overrides *(one-shot — remove after use)*
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `DRY_RUN` | `false` | Preview selection without downloading or uploading |
|
||||||
|
| `RETRY_REJECTED` | `false` | Re-attempt previously rejected images |
|
||||||
|
| `RESET_PERSON` | *(unset)* | Clear uploaded + rejected history for one person by name |
|
||||||
|
|
||||||
|
### Scheduling
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `CRON_SCHEDULE` | *(unset)* | Cron expression — unset runs once and exits |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
[ghcr.io/sudolulo/if-curator-headless](ghcr.io/sudolulo/if-curator-headless)
|
```bash
|
||||||
|
docker pull ghcr.io/sudolulo/if-curator-headless:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
See [compose.yml](compose.yml) for a full example with volume mounts and GPU support.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -126,3 +155,11 @@ Bad training data hurts ArcFace models. Images are automatically rejected if the
|
|||||||
git clone https://github.com/sudolulo/if_curator_headless.git
|
git clone https://github.com/sudolulo/if_curator_headless.git
|
||||||
cd if_curator_headless
|
cd if_curator_headless
|
||||||
uv sync
|
uv sync
|
||||||
|
uv run if-curator
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
Based on [if-curator](https://github.com/ds-sebastian/if_curator) by Sebastian, licensed MIT.
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ version = "0.1.0"
|
|||||||
description = "Immich to Frigate training sets"
|
description = "Immich to Frigate training sets"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
authors = [{ name = "sudolulo" }]
|
authors = [{ name = "Holden Salomon", email = "holden@arch.fyi" }]
|
||||||
keywords = ["immich", "frigate", "face-recognition", "training-data", "arcface", "insightface"]
|
keywords = ["immich", "frigate", "face-recognition", "training-data", "arcface", "insightface"]
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Development Status :: 3 - Alpha",
|
"Development Status :: 3 - Alpha",
|
||||||
|
|||||||
Reference in New Issue
Block a user