Ports scene extract, face ONNX preprocess, and net reference resize to Torch/CUDA with minimal CPU sync, while keeping the CPU parity path unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
163 lines
6.3 KiB
Markdown
163 lines
6.3 KiB
Markdown
# MAGICMATCH
|
||
|
||
ComfyUI custom nodes for **neural color match**: two images in, graded source out. Tune strength on a preview node before you wire the result to save/export.
|
||
|
||
## Install
|
||
|
||
1. Clone into ComfyUI `custom_nodes`:
|
||
|
||
```bash
|
||
cd ComfyUI/custom_nodes
|
||
git clone https://github.com/lookuters22/MAGICMATCH.git
|
||
```
|
||
|
||
2. Install Python deps (ComfyUI’s environment):
|
||
|
||
```bash
|
||
pip install -r MAGICMATCH/requirements.txt
|
||
```
|
||
|
||
3. Model files are included in the repo (pull gets everything):
|
||
|
||
```text
|
||
MAGICMATCH/models/color_match.onnx
|
||
MAGICMATCH/models/face/face_detect_landscape.onnx
|
||
MAGICMATCH/models/face/face_detect_portrait.onnx
|
||
MAGICMATCH/models/face/face_parse.onnx
|
||
```
|
||
|
||
To regenerate locally (optional), use Python 3.12 + `scripts/convert_face_models_to_onnx.py` and the color-match convert script under `polarrnext/color_match_extract/`.
|
||
|
||
4. Restart ComfyUI. Nodes appear under **MAGICMATCH**.
|
||
|
||
## Workflow (strength before export)
|
||
|
||
Use **Build** + **Preview** so changing the slider only re-applies the LUT (fast):
|
||
|
||
```text
|
||
[Source] ──┬──► MagicMatch Build LUT ◄── [Reference]
|
||
│ │
|
||
│ ▼ lut
|
||
└──────► MagicMatch Preview (strength) ──► Preview Image
|
||
│
|
||
└──► Save / export when ready
|
||
```
|
||
|
||
| Step | Node |
|
||
|------|------|
|
||
| 1 | **MagicMatch Build LUT** — run once per source/reference pair |
|
||
| 2 | **MagicMatch Preview (strength)** — run once, then use the **live preview inside the node** and drag **strength** (no re-queue) |
|
||
| 3 | When happy with the slider, **Queue** again and connect output to Save / export |
|
||
|
||
### In-node live preview
|
||
|
||
1. Run the workflow **once** (Build + Preview execute; LUT is cached).
|
||
2. Open the **MagicMatch Preview** node — you’ll see a **live image** under the widgets.
|
||
3. Drag **strength** — preview updates **instantly** in the node (WebGL, no workflow re-run).
|
||
4. When the look is right, **Queue Prompt** once more so the **image** output matches the slider, then save/export.
|
||
|
||
Live preview uses WebGL (merged 25³ LUT + strength mix). Mid-strength may differ slightly from the queued **image** output, which uses the full CPU path — queue once more before export.
|
||
|
||
**MagicMatch (one-shot)** combines build + apply in one node (simpler, slower when you change strength).
|
||
|
||
## Requirements
|
||
|
||
- ComfyUI with standard `IMAGE` tensors (batch size **1**)
|
||
- `onnxruntime`, `numpy` (see `requirements.txt`)
|
||
- Face auto-WB/light uses ONNX face models under `models/face/` (see install step 3)
|
||
- CPU inference by default (~5–15s for Build on first run per pair)
|
||
|
||
## CUDA inference (experimental)
|
||
|
||
A **separate** GPU path lives alongside the CPU parity stack — default nodes and
|
||
`scripts/parity_pair.py` golden checks are unchanged.
|
||
|
||
### Install (H100 / Linux)
|
||
|
||
```bash
|
||
# In ComfyUI's venv — onnxruntime and onnxruntime-gpu are mutually exclusive on many builds
|
||
pip uninstall -y onnxruntime
|
||
pip install -r MAGICMATCH/requirements-cuda.txt
|
||
```
|
||
|
||
Requires NVIDIA driver + CUDA libs compatible with your `onnxruntime-gpu` wheel.
|
||
ComfyUI already provides PyTorch with CUDA — the GPU pipeline uses Torch for develop,
|
||
detection buffers, and LUT apply (ONNX uses CUDA EP).
|
||
|
||
On machines without CUDA, CUDA nodes fall back to CPU EP + CPU Torch automatically.
|
||
|
||
### ComfyUI nodes
|
||
|
||
After restart, look under **MAGICMATCH/CUDA (experimental)**:
|
||
|
||
| Class | Display name |
|
||
|-------|----------------|
|
||
| `MagicMatchBuildCUDA` | MagicMatch Build LUT (CUDA) |
|
||
| `MagicMatchPreviewCUDA` | MagicMatch Preview (CUDA LUT) |
|
||
| `MagicMatchCUDA` | MagicMatch one-shot (CUDA) |
|
||
|
||
**GPU pipeline (CUDA nodes):** CUDA ONNX + GPU detection buffers + GPU develop@1600 + GPU full-res apply.
|
||
|
||
### GPU Full pipeline (experimental)
|
||
|
||
A **complete** hot-path port keeps detection buffers, luminance stats, face ONNX preprocess,
|
||
develop@1600, full-res LUT apply, and net reference resize on GPU/Torch. Minimal CPU sync:
|
||
JPEG q98 worker normalize, detection-sized downloads for face/color/WB parity helpers,
|
||
256×256 reference JPEG/WebP round-trips, and single `.cpu().numpy()` feeds for ONNX.
|
||
|
||
ComfyUI category: **MAGICMATCH/GPU Full (experimental)**
|
||
|
||
| Class | Display name |
|
||
|-------|----------------|
|
||
| `MagicMatchBuildGPUFull` | MagicMatch Build LUT (GPU Full) |
|
||
| `MagicMatchPreviewGPUFull` | MagicMatch Preview (GPU Full LUT) |
|
||
| `MagicMatchGPUFull` | MagicMatch one-shot (GPU Full) |
|
||
|
||
Set `MAGICMATCH_GPU_FULL_NODES=0` to hide GPU Full nodes.
|
||
|
||
**CPU default nodes** under **MAGICMATCH** are unchanged.
|
||
|
||
Set `MAGICMATCH_CUDA_NODES=0` before starting ComfyUI to hide CUDA nodes.
|
||
|
||
Use `python3.12` on RunPod if `python` is not on PATH.
|
||
|
||
### Benchmark / parity
|
||
|
||
```bash
|
||
# CPU golden (must stay parity_ok)
|
||
python scripts/parity_pair.py \
|
||
../polarrnext/standalone_probe/public/pair/source.png \
|
||
../polarrnext/standalone_probe/public/pair/reference.jpg
|
||
|
||
# CPU vs CUDA timings + lut_hash compare
|
||
python scripts/bench_cuda_vs_cpu.py \
|
||
../polarrnext/standalone_probe/public/pair/source.png \
|
||
../polarrnext/standalone_probe/public/pair/reference.jpg
|
||
|
||
# Full GPU pipeline phase breakdown + parity report
|
||
python scripts/bench_gpu_full.py \
|
||
../polarrnext/standalone_probe/public/pair/source.png \
|
||
../polarrnext/standalone_probe/public/pair/reference.jpg
|
||
|
||
# Per-phase GPU timings only (via bench_cuda_vs_cpu)
|
||
python scripts/bench_cuda_vs_cpu.py --profile-gpu \
|
||
../polarrnext/standalone_probe/public/pair/source.png \
|
||
../polarrnext/standalone_probe/public/pair/reference.jpg
|
||
```
|
||
|
||
Expected golden `lut_hash` on the polarrnext/pair test set: `a48758ca22a2e389`.
|
||
CUDA may differ slightly if GPU face-detect scores diverge from CPU f16 quirks; compare
|
||
`lut_max_abs_delta` in the bench report.
|
||
|
||
## Nodes (CPU default)
|
||
|
||
| Class | Display name |
|
||
|-------|----------------|
|
||
| `MagicMatchBuild` | MagicMatch Build LUT |
|
||
| `MagicMatchPreview` | MagicMatch Preview (strength) |
|
||
| `MagicMatch` | MagicMatch (one-shot) |
|
||
|
||
## License
|
||
|
||
See [LICENSE](LICENSE). The bundled `color_match.onnx` is part of this package; use responsibly and in compliance with applicable terms for any upstream model you obtained.
|