MAGICMATCH
ComfyUI custom nodes for neural color match: two images in, graded source out.
Nodes (12)
The color-match node that learns the look, not just the stats
Build the expensive LUT once, tune it forever
Faster LUT builds when the GPU is the bottleneck
The LUT builder that optimizes for speed and owns it
GPU speed without giving up the parity
The one-shot with the GPU accelerator bolted on
One-shot color match when the loop needs to be fast
The full GPU pipeline, fused into one node
Drag the strength slider without re-running the neural net
Preview a CUDA-built LUT without moving the apply
Fast preview for a fast LUT
The parity-friendly GPU preview
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
-
Clone into ComfyUI
custom_nodes:cd ComfyUI/custom_nodes git clone https://github.com/lookuters22/MAGICMATCH.git -
Install Python deps (ComfyUI’s environment):
pip install -r MAGICMATCH/requirements.txt -
Model files are included in the repo (pull gets everything):
MAGICMATCH/models/color_match.onnx MAGICMATCH/models/face/face_detect_landscape.onnx MAGICMATCH/models/face/face_detect_portrait.onnx MAGICMATCH/models/face/face_parse.onnxTo regenerate locally (optional), use Python 3.12 +
scripts/convert_face_models_to_onnx.pyand the color-match convert script underpolarrnext/color_match_extract/. -
Restart ComfyUI. Nodes appear under MAGICMATCH.
Workflow (strength before export)
Use Build + Preview so changing the slider only re-applies the LUT (fast):
[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
- Run the workflow once (Build + Preview execute; LUT is cached).
- Open the MagicMatch Preview node — you’ll see a live image under the widgets.
- Drag strength — preview updates instantly in the node (WebGL, no workflow re-run).
- 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
IMAGEtensors (batch size 1) onnxruntime,numpy(seerequirements.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)
# 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
# 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. The bundled color_match.onnx is part of this package; use responsibly and in compliance with applicable terms for any upstream model you obtained.