Composite Rank (identity × proportion × sharpness)
Stop eyeballing 40 face-swap candidates — let Composite Rank pick
- face_reference
- proportion_reference
- images
- ranked_images
- best_image
- report
You generate a person from a face reference with InstantID, PhotoMaker, IP-Adapter, or PuLID, run forty seeds, and get the usual result: the face mostly looks like them, but the head-to-shoulder proportion wobbles, a few are straight-up soft, and one or two drifted into another person entirely. The old workflow is a contact sheet and a squint. Composite Rank replaces the squint.
It's the flagship of the QualityGate pack, and it does one job: take a batch, score every image on three axes, and hand you back the batch sorted by how close each image is to a reference - closest first, best_image on top. That's it. No training, no API, no model downloads beyond the small pose file it pulls on first run.
What it actually measures
Three axes, combined into one weighted score:
- Identity - ArcFace face embedding (via insightface, the same backbone under IP-Adapter FaceID and InstantID) compared against your
face_referenceby cosine similarity. Same person in normal variation scores roughly 0.5–0.95; a stranger is under 0.3. - Proportion - the head-size ratio
R = ear-to-ear width / shoulder width, measured with MediaPipe Pose and compared against yourproportion_reference. The clever bit: ear-to-ear is stable even with long or face-framing hair, and shoulder width normalizes for distance and crop, so it works on headshots or full bodies. - Sharpness - Laplacian variance, the classic blur detector. Catches the melt-y low-detail frames that identity and proportion both miss.
Each image's score is a weighted average of the three, and the weighted composite is the point. Face similarity and head ratio frequently fight each other - pull the face closer and the proportions drift - so a single combined score picks the best compromise instead of a winner in one axis. The pack's own numbers make the case: best image scores 0.93 identity / 0.93 proportion / 1.00 sharpness; worst sits at 0.64 / 0.24 / 0.81.
The proportion scoring is exponential decay, exp(-|ΔR|/tolerance). That's a deliberate design choice: a hard threshold would zero out every image if your reference sits far from the batch, and you'd get no ordering at all. Exponential decay never saturates, so you always get a ranked list.
Inputs and outputs that matter
You only really set a handful:
face_reference- the face you want to keep (the "correct head").proportion_reference- the target head-size ratio (the "correct proportions"). These can be different photos, even different people - one drives identity, the other geometry.images- the batch to rank, usually straight fromVAEDecode.w_identity,w_proportion,w_sharpness- weights; set a weight to 0 to disable that axis. Defaults are 1.0 / 1.0 / 0.5.tolerance- how picky the proportion scoring is. Smaller = more sensitive to ratio differences. 0.02 is a sane default; the author's data shows it resolves ΔR ≈ 0.01.
Outputs: ranked_images (sorted batch, closest first), best_image (the winner - wire this to SaveImage and you're done), and report, a plain-text table of per-image scores that's worth reading once so you trust the ordering.
Installing it
ComfyUI Manager, search "QualityGate," install, restart - or:
cd ComfyUI/custom_nodes
git clone https://github.com/nobu1990/ComfyUI-QualityGate
pip install -r ComfyUI-QualityGate/requirements.txt
Restart and the nodes land in a QualityGate category. The base requirements.txt is just opencv-python and numpy. The identity axis wants insightface + onnxruntime + the buffalo_l model pack; the proportion axis wants mediapipe (pose runs on CPU). Missing a dependency doesn't crash the node - the affected axis reports as skipped and its weight is treated as 0, so you can run sharpness-only out of the box. The pose model downloads itself to models/ on first use.
Where people get burned: the identity axis silently does nothing if buffalo_l isn't found - check the report string for identity=skip before you trust a run. The author ships an example_workflows/composite_rank_demo.json you can drag straight into ComfyUI to see it working.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| face_reference | IMAGE | — | |
| proportion_reference | IMAGE | — | |
| images | IMAGE | — | |
| w_identity | FLOAT | 1.00–3 | — |
| w_proportion | FLOAT | 1.00–3 | — |
| w_sharpness | FLOAT | 0.50–3 | — |
| tolerance | FLOAT | 0.0200.005–0.1 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| ranked_images | IMAGE | — |
| best_image | IMAGE | — |
| report | STRING | — |