ComfyUI Node

Face Fixer

The Impact-Pack-style detailer that fixes every face, then blends it back cleanly

By Code2Collapse·Created 6 months ago·Updated a day ago· 52
Face Fixer
  • image
  • model
  • positive
  • negative
  • vae
  • mask
  • upscale_model
  • image
  • face_mask
  • info_json
face_modelnone
confidence0.50
max_faces8
crop_padding1.40
crop_resolution768
denoise0.40
steps20
cfg6.0
sampler_nameeuler
schedulernormal
seed0
blend_softness6.0
mask_dilate4
color_matchtrue
lightness_rescuetrue
differential_diffusiontrue
face_positive_prompt
face_negative_prompt

Small faces are the thing that breaks in every generation. A face occupying 70 pixels of a 1024px frame comes out as a smear, because the latent has no budget for it. Face Fixer (MEC) runs the whole automatic-detailing loop in one node: detect every face with YOLO11, crop and optionally upscale each one, re-render it with its own sampling pass, then blend the results back with color matching. It's a behavioural clone of Forbidden Vision's "Fixer" (a real pack by luxdelux7 that people use exactly for this) built on Impact Pack's wildcard syntax, and if you've read the KB's detailing essay you know the loop: detect → crop/upscale → re-render → paste back.

How it works

Pipeline: YOLO11 face detection → per-face crop with crop_padding → optional AI pre-upscale (upscale_model) for small faces → a KSampler on each crop → smart blend (color match + lightness rescue + differential diffusion) → wildcard prompt routing.

Key inputs:

  • face_model - a YOLO11 .pt/.onnx in ComfyUI/models/ultralytics/bbox/. This is your responsibility: the pack doesn't bundle weights (a deliberate choice - see below). Choose none to skip detection and use the mask input instead.
  • crop_resolution (default 768) - each face gets resized to this longer side before sampling.
  • denoise (default 0.4) - per-face strength; 0.3 subtle cleanup, 0.7 aggressive reshape. Start low.
  • steps, cfg, sampler_name, scheduler, seed - per-face sampling. Seed is base seed + face index, which quietly sidesteps the classic detailer clone problem.
  • blend_softness, mask_dilate, color_match, lightness_rescue, differential_diffusion - the blend stage, all defaulting on. This is where the seam dies.

The wildcard prompts are the fun part. face_positive_prompt/face_negative_prompt use Impact Pack tokens: [SEP] separates per-face prompts, [ASC]/[DSC] order by score, [ASC-SIZE]/[DSC-SIZE] by face size, [SKIP] leaves a face untouched. Outputs: image, face_mask (combined detection mask), and info_json (per-face bbox, score, prompt, denoise).

The honest caveats

From the KB's detailing essay, the failure modes are real: over-processing an already-good face (you can't see the difference but paid render time), and identity drift on crowds. The seed+i scheme helps the clone problem. The Ultralytics note matters too - the YOLO path is AGPL-3.0, and the Dec-2024 Ultralytics supply-chain incident is why some people prefer MediaPipe. This node uses the standard ultralytics/onnxruntime path, so be aware of the licensing if you're shipping a product.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/Code2Collapse/ComfyUI-CustomNodePacks.git
pip install opencv-python>=4.7.0 scipy>=1.10.0

Then get a face model: face_yolov8n.pt or face_yolov8s.pt (the standard community weights) into ComfyUI/models/ultralytics/bbox/. If neither ultralytics nor onnxruntime is installed, the node falls back to the mask input so your workflow doesn't hard-fail - that's by design. Restart and confirm [MEC] Loaded .... And the cardinal rule from the KB: detail at native resolution first, upscale after - upscaling before the detail pass bakes the mangled face into more pixels.

CategoryC2C/Paint

Inputs (25)

NameTypeDefaultDescription
imageIMAGESource image (single frame or batch; processed independently per frame).
modelMODELDiffusion model to sample with.
positiveCONDITIONINGBase positive conditioning. Wildcards in face_positive_prompt override per face.
negativeCONDITIONINGBase negative conditioning. Wildcards in face_negative_prompt override per face.
vaeVAEVAE used to encode/decode the per-face crops.
face_modelCOMBOnoneYOLO11 face-detection .pt/.onnx in ComfyUI/models/ultralytics/bbox/. Choose 'none' to use the optional mask input instead.
confidenceFLOAT0.500.05–0.95Minimum detection confidence.
max_facesINT80–32Maximum number of faces to process per frame (0 = all).
crop_paddingFLOAT1.401–3Bbox padding multiplier so the sampler sees context around each face.
crop_resolutionINT768256–2048Resize each face crop to this longer-side resolution before sampling.
denoiseFLOAT0.400–1Per-face denoise strength (0.3 = subtle, 0.7 = aggressive reshape).
stepsINT201–100Sampling steps per face.
cfgFLOAT6.00–30CFG scale for face sampling.
sampler_nameCOMBOeulerSampler algorithm.
schedulerCOMBOnormalSigma schedule.
seedINT00–18446744073709550000Base seed; each face gets seed+i.
blend_softnessFLOAT6.00–64Feather radius (px) on the per-face blend mask.
mask_dilateINT4-32–32Dilate (>0) / erode (<0) of the per-face blend mask.
color_matchBOOLEANtrueReinhard mean/std colour match per face.
lightness_rescueBOOLEANtrueLift the per-face L channel if the sample comes back darker than the original.
differential_diffusionBOOLEANtrueWeight the blend by |orig - sampled| so unchanged pixels stay sharp.
maskoptMASKOptional manual face mask. Used directly when face_model='none' or detection finds nothing.
upscale_modeloptUPSCALE_MODELOptional UPSCALE_MODEL applied to faces below crop_resolution before sampling.
face_positive_promptoptSTRINGPer-face positive prompt with wildcards: [SEP] separates faces; [ASC]/[DSC]/[ASC-SIZE]/[DSC-SIZE] order; [SKIP] leaves a face untouched.
face_negative_promptoptSTRINGSame syntax as face_positive_prompt for negatives.

Outputs (3)

NameTypeDescription
imageIMAGEImage with detected faces detailed and blended back over the original.
face_maskMASKCombined face-detection mask covering all processed faces.
info_jsonSTRINGJSON metadata: per-face bbox, score, prompt, denoise.