Nodes/comfyui-fvmtools/Person Detailer
ComfyUI Node

Person Detailer

Detail each face in a crowd with its own LoRA — without burning out your workflow

By ping1979ping·Created 7 months ago·Updated a day ago· 2
Person Detailer
  • images
  • person_data
  • model
  • clip
  • vae
  • positive_base
  • negative
  • dd_options
  • inpaint_options
  • images
  • refined
  • refined_references
  • refined_generic
◄seed0►
◄steps4►
◄denoise0.52►
◄sampler_name▾►
◄scheduler▾►
◄detail_daemon_enabledtrue►
◄detail_amount0.20►
◄dd_smoothtrue►
◄mask_blend_pixels32►
◄mask_expand_pixels0►
◄target_width800►
◄target_height1200►
◄reference_1_enabledtrue►
◄reference_1_lora▾►
◄reference_1_lora_strength1.00►
◄reference_1_prompt►
◄reference_2_enabledfalse►
◄reference_2_lora▾►
◄reference_2_lora_strength1.00►
◄reference_2_prompt►
◄reference_3_enabledfalse►
◄reference_3_lora▾►
◄reference_3_lora_strength1.00►
◄reference_3_prompt►
◄reference_4_enabledfalse►
◄reference_4_lora▾►
◄reference_4_lora_strength1.00►
◄reference_4_prompt►
◄reference_5_enabledfalse►
◄reference_5_lora▾►
◄reference_5_lora_strength1.00►
◄reference_5_prompt►
◄generic_enabledfalse►
◄generic_catch_unprocessedtrue►
◄generic_lora▾►
◄generic_lora_strength1.00►
◄generic_prompt►

If you've ever tried to put two or three different characters in one image and watched the model blend them into one mush-faced average, you know the pain this node exists for. Person Detailer is the workhorse of the FVMtools pack: it takes an image, a set of detected faces, and - here's the part FaceDetailer from Impact Pack can't do - applies a different LoRA and prompt to each person. Person one gets your character LoRA and a "short brown hair" prompt; person two gets the other LoRA and "long black hair"; everyone else can be swept up by a generic slot. It's the multi-character problem from character-consistency land, solved with a bunch of per-slot inpaint passes instead of hoping regional prompting cooperates.

What it actually does

The mechanism is the old detect-crop-refine loop - the same idea Impact Pack's FaceDetailer popularized in ComfyUI - but re-engineered for multiple identities. Feed it images plus person_data from Person Selector Multi (the node that matched each face to a reference and generated its masks), and it iterates over your reference slots one at a time. For each enabled slot it crops the matched region, applies that slot's LoRA as a temporary clone on your base model, encodes the slot's prompt, and runs a masked inpaint pass at target_width × target_height - 800×1200 by default, which is the whole point: a face that's 80×80 in the full frame gets a proper resolution budget. Then it feathers the edges (mask_blend_pixels, default 32) and stitches it back. Slots process sequentially, each inpainting into the result of the previous one, so the image builds up progressively.

There's real engineering under the hood. LoRA files live in a 6-slot LRU cache so the same LoRA isn't re-read from disk for every face. And before the batch loop it pre-computes every unique (LoRA, strength, prompt) combination once - five people sharing one LoRA means one load and one conditioning encode, not five. If you're running Z-Image Turbo (Lumina2), it auto-detects it and converts diffusers-style LoRAs to the fused QKV format on the fly. That last bit is why the defaults look weird: steps defaults to 4 and denoise to 0.52, tuned for distilled turbo models. On a regular SDXL or Flux checkpoint, raise steps before you conclude it's broken.

The inputs that matter

  • reference_1_enabled / reference_1_lora / reference_1_prompt - slot 1 is on by default; slots 2–5 start disabled. Each slot's prompt, if empty, falls back to the positive_base conditioning. This is where you wire per-character identity.
  • denoise - 0.52 default. Lower keeps more original detail; too high and you're re-drawing the face, not refining it.
  • generic_enabled + generic_prompt - the catch-all. It starts off; flip it on and, with generic_catch_unprocessed (on by default) doing the sweeping, it details any face no reference slot claimed, so nobody gets left looking mushy.

Outputs: images (the final stitched result), plus refined, refined_references, and refined_generic - grids of the inpainted crops, handy for checking what each slot actually did. Wire images straight to a SaveImage or into an upscaler.

Installing it

Grab the whole pack once - every node in this family ships together. Via ComfyUI Manager, search comfyui-fvmtools, or:

cd ComfyUI/custom_nodes
git clone https://github.com/ping1979ping/comfyui-FVMtools
pip install insightface>=0.7.3 onnxruntime-gpu>=1.17.0 opencv-python>=4.8.0 numpy>=1.24.0

Restart ComfyUI. InsightFace's buffalo_l models auto-download on first use, but the BiSeNet segmentation model does not - drop parsing_bisenet.pth (53 MB, from xinntao/facexlib releases) into ComfyUI/models/gfpgan/ or face/head masks silently won't exist.

Where people get burned

The classic gotcha: an empty output. If you see a 64×64 black placeholder image come out, that's not a crash - it means no face matched any enabled slot, so nothing got detailed. Check your reference images, the threshold on Person Selector Multi, and whether the right slots are enabled. Also worth knowing: this node is LOUD - it loads a face detector, a face parser, potentially SAM, and runs a full inpaint per person. First run on a big batch can feel like it hung while models initialize. It's not hung, it's downloading buffalo_l.

CategoryFVM Tools/Face

Inputs (46)

NameTypeDefaultDescription
imagesIMAGEInput image batch [B, H, W, C]
person_dataPERSON_DATAPerson data from Person Selector Multi node
modelMODELBase model (LoRAs are applied as temporary clones per slot)
clipCLIPCLIP model for prompt encoding
vaeVAEVAE for encode/decode in the inpaint pipeline
seedINT00–18446744073709550000Global seed, fixed across all slots and batch items
stepsINT41–100Number of sampling steps per inpaint
denoiseFLOAT0.520–1Denoise strength for inpainting (lower = more original detail preserved)
sampler_nameCOMBOSampler algorithm
schedulerCOMBONoise schedule
detail_daemon_enabledBOOLEANtrueEnable Detail Daemon sigma manipulation for enhanced detail preservation
detail_amountFLOAT0.20-5–5Detail Daemon strength. Positive = more detail, negative = smoother. 0 = off.
dd_smoothBOOLEANtrueSmooth the Detail Daemon sigma curve to avoid artifacts
mask_blend_pixelsINT320–128Feather radius at the mask edge, measured in SAMPLING pixels (relative to target_width/target_height, the one fixed frame in the pipeline). The same radius is converted back to image pixels for the blend, so both ramps cover the same strip of the picture. The console prints the conversion, e.g. '32px @ 800px sampling = 15px in the image (crop 380px)'. Which side of the edge the ramp lies on is set by feather_direction in Inpaint Options. On 'both' (the default) the ramp eats into the mask as much as out of it - raise this only as far as the thinnest part of your mask tolerates.
mask_expand_pixelsINT00–64Dilate the mask by this many IMAGE pixels before anything else happens - before the crop region is computed, before feathering. Grows the mask outward in every direction, so on a hair or accessory mask it also grows toward the face. Unaffected by feather_direction. Leave at 0 unless the segmentation is clipping the subject.
target_widthINT80064–4096Width to resize face crops to before sampling
target_heightINT120064–4096Height to resize face crops to before sampling
reference_1_enabledBOOLEANtrueEnable reference slot 1 for detailing
reference_1_loraCOMBOLoRA to apply when detailing reference 1
reference_1_lora_strengthFLOAT1.000–2LoRA strength for reference 1
reference_1_promptSTRINGPositive prompt for reference 1. If empty, uses base conditioning.
reference_2_enabledBOOLEANfalseEnable reference slot 2 for detailing
reference_2_loraCOMBOLoRA to apply when detailing reference 2
reference_2_lora_strengthFLOAT1.000–2LoRA strength for reference 2
reference_2_promptSTRINGPositive prompt for reference 2. If empty, uses base conditioning.
reference_3_enabledBOOLEANfalseEnable reference slot 3 for detailing
reference_3_loraCOMBOLoRA to apply when detailing reference 3
reference_3_lora_strengthFLOAT1.000–2LoRA strength for reference 3
reference_3_promptSTRINGPositive prompt for reference 3. If empty, uses base conditioning.
reference_4_enabledBOOLEANfalseEnable reference slot 4 for detailing
reference_4_loraCOMBOLoRA to apply when detailing reference 4
reference_4_lora_strengthFLOAT1.000–2LoRA strength for reference 4
reference_4_promptSTRINGPositive prompt for reference 4. If empty, uses base conditioning.
reference_5_enabledBOOLEANfalseEnable reference slot 5 for detailing
reference_5_loraCOMBOLoRA to apply when detailing reference 5
reference_5_lora_strengthFLOAT1.000–2LoRA strength for reference 5
reference_5_promptSTRINGPositive prompt for reference 5. If empty, uses base conditioning.
generic_enabledBOOLEANfalseEnable detailing for unmatched faces (not assigned to any reference)
generic_catch_unprocessedBOOLEANtrueON: detail everything the active slots leave unprocessed - unmatched faces, faces of disabled slots, and with generic mask_type 'aux' also aux hits assigned to a reference whose slot does not use 'aux' (e.g. a phone in the hand of a person whose slot only details the head). OFF: only truly unmatched faces / unassigned aux hits.
generic_loraCOMBOLoRA to apply for unmatched faces
generic_lora_strengthFLOAT1.000–2LoRA strength for unmatched faces
generic_promptSTRINGPositive prompt for unmatched faces. If empty, uses base conditioning.
positive_baseoptCONDITIONINGBase positive conditioning, used as fallback when a slot's prompt is empty
negativeoptCONDITIONINGNegative conditioning. If not connected, an empty negative is used.
dd_optionsoptDD_OPTIONSAdvanced Detail Daemon parameters from Detail Daemon Options node
inpaint_optionsoptINPAINT_OPTIONSAdvanced inpaint settings and per-slot overrides from Inpaint Options node

Outputs (4)

NameTypeDescription
imagesIMAGE—
refinedIMAGE—
refined_referencesIMAGE—
refined_genericIMAGE—