Nodes/comfyui-fvmtools/Person Selector Multi
ComfyUI Node

Person Selector Multi

1, make every mask

By ping1979ping·Created 5 months ago·Updated about a month ago· 0
Person Selector Multi
  • current_image
  • sam_model
  • reference_1
  • outfit_palettes
  • person_mask
  • depth_map
  • sam3_model
  • reference_2
  • reference_3
  • reference_4
  • reference_5
  • reference_6
  • reference_7
  • reference_8
  • reference_9
  • reference_10
  • person_data
  • face_masks
  • head_masks
  • body_masks
  • combined_face
  • combined_head
  • combined_body
  • aux_masks
  • preview
  • similarities
  • matches
  • matched_count
  • face_count
  • report
auto_thresholdtrue
threshold0.40
guaranteed_refs0
aggregation
mask_fill_holestrue
mask_blur0
det_size
aux_mask_typenone
aux_model
aux_confidence0.35
aux_label
aux_fill_holesfalse
aux_expand_pixels0
aux_blend_pixels0
match_weights50/15/15/20
depth_edge_threshold0.05
depth_carve_strength0.80
depth_grow_pixels30
body_mask_modeauto
depth_sort_orderfront_last

This is the node the whole pack orbits. Person Selector Multi detects every face in your image, matches each one against up to ten reference slots with exclusive 1:1 assignment - a face can match at most one reference, so no duplicate assignments - and generates the full mask set for every matched person: face, head, body, plus optional hair, skin, eyes, mouth, neck, and accessories, all from a single BiSeNet run. The output is PERSON_DATA, which is exactly the structure Person Detailer eats.

Why exclusive assignment matters: in a scene with three people who resemble each other, naive max-similarity matching happily assigns the same face to two references. This does a proper 1:1 assignment, so each character gets their own mask and their own detailing slot. If you've ever watched a multi-person detail pass "fix" the same face twice, you know why this is the feature.

How it works

The differentiator is appearance-enhanced matching. Pure ArcFace struggles when faces look similar, so the node blends four signals - face identity, hair color (BiSeNet HSV), head appearance (histogram), and outfit color - weighted by match_weights, default 50/15/15/20. Faces too similar? Crank the outfit weight. Need pure face matching? Set 100/0/0/0. That tuning string is the single most important thing to learn on this node.

The quality-of-life wiring is deep. auto_threshold (default on) finds the optimal assignment and ignores the manual threshold; guaranteed_refs force-assigns the first N references so key characters always get detailed. A depth map (from Depth Anything V2 or similar) enables edge-carved masks, cross-reference deconfliction, and back-to-front render ordering - the preview even draws an isometric depth-layer diagram. A person_mask (BiRefNet, RMBG-2.0) hard-clips every mask to the foreground silhouette. YOLO models dropped into models/ultralytics/segm/ add body-part detection, stored as aux masks.

The inputs that matter

  • current_image - supports batch input, each image processed independently.
  • reference_1 through reference_10 - all optional; with none connected, every face goes to the generic slot.
  • match_weights - the four-signal blend.
  • guaranteed_refs - force-assign your key characters.

Outputs

person_data (→ Person Detailer), per-reference face/head/body masks, combined masks, aux_masks, an annotated preview, plus similarities, matches, matched_count, face_count, and a report string.

Install

Face deps as usual:

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

buffalo_l auto-downloads; parsing_bisenet.pth is manual; SAM/SAM3 and YOLO are optional.

Common issues

The wrong person gets the wrong slot → tune match_weights, or connect outfit_palettes from the color generator so the outfit signal has something to compare against. Everyone landing in the generic slot → no references connected, which is by design. Masks bleeding into the background → connect a person_mask or a segmentation detector. And if auto_threshold gives surprising results with strongly similar faces, the manual threshold path with guaranteed_refs gives you back control.

CategoryFVM Tools/Face

Inputs (36)

NameTypeDefaultDescription
current_imageIMAGEImage(s) to search for faces. Supports batch input — each image is processed independently.
auto_thresholdBOOLEANtrueAuto: finds optimal 1:1 face-reference assignment (ignores threshold). Off: uses manual threshold.
thresholdFLOAT0.400–1Minimum cosine similarity to count as match. Ignored when auto_threshold is on.
guaranteed_refsINT00–10Force-assign the first N references to their best matching face, ignoring threshold. 0 = off (default). 2 = Ref1 and Ref2 always get assigned. Useful when key characters must always be detailed.
aggregationCOMBOHow to combine similarity scores across multiple reference images of the same person
mask_fill_holesBOOLEANtrueFill holes inside the mask (closes gaps in segmentation)
mask_blurINT00–100Gaussian blur radius for mask edges
det_sizeCOMBOFace detection resolution — higher finds smaller faces but uses more VRAM
aux_mask_typeCOMBOnoneAdditional mask type for aux_masks output (derived from BiSeNet, no extra cost)
aux_modelCOMBOYOLO model for body-part detection. Runs per batch image internally. Select a model from models/ultralytics/ to detect body parts (hands, persons, etc.). Detections are assigned to references via body mask overlap and stored as aux_masks in PERSON_DATA. none = no body-part detection (default) Drop .pt files into models/ultralytics/segm/ to add more models.
aux_confidenceFLOAT0.350.05–1YOLO detection confidence threshold. Lower = more detections (may include false positives) Higher = fewer, more confident detections 0.25-0.35 recommended for most models.
aux_labelSTRINGFilter YOLO detections by class label (substring match). Empty = keep all detected classes (default) Comma-separated: 'person' or 'leg,foot' Substring match: 'leg' hits 'Left-leg', 'right_leg', etc. The class list for the selected model is displayed above the Matching section after model selection.
aux_fill_holesBOOLEANfalseFill holes inside YOLO aux masks (closes interior gaps). Off by default — segm models usually produce solid masks.
aux_expand_pixelsINT00–100Dilate YOLO aux masks by N pixels (elliptical kernel). Useful when segm masks hug the silhouette too tightly for inpainting. 0 = no growth.
aux_blend_pixelsINT00–100Gaussian blur radius for YOLO aux mask edges (symmetric). Blurs ~N pixels inward AND outward from the current edge. If you want the grown shape to stay fully opaque, set aux_expand_pixels at least as large as aux_blend_pixels.
match_weightsSTRING50/15/15/20Matching weight blend: face/hair/head/outfit. Controls how much each signal contributes to the final similarity score. 50/15/15/20 — balanced with outfit (default) 60/20/20/0 — no outfit matching 100/0/0/0 — pure face matching 40/15/15/30 — heavy outfit weight 3 values also work (outfit=0): 60/20/20 equals 60/20/20/0. Hair = BiSeNet hair color (HSV). Head = head crop histogram. Outfit = clothing region vs. palette color distribution. Values are auto-normalized, so 3/1/1/1 equals 50/17/17/17.
sam_modeloptSAM_MODELSAM2 model from Impact Pack SAMLoader for body masks. Optional when sam3_model is connected.
reference_1optIMAGEReference image(s) for person 1. Pass a batch of images of the same person for better matching accuracy. Optional — if no references connected, all detected faces go to the generic slot in PersonDetailer.
outfit_palettesoptIMAGEPalette preview image batch for outfit color matching. Image[0] = palette for reference 1, image[1] = for reference 2, etc. If batch is smaller than number of references, remaining refs skip outfit matching. Connect palette_preview outputs from Color Palette Generator. Use match_weights with 4 values to control outfit weight (e.g. 50/15/15/20).
person_maskoptMASKForeground person mask (BiRefNet, RMBG-2.0, or similar). When connected, acts as a hard clip for ALL mask types — face, head, body, aux, and BiSeNet label seeds are zeroed outside this silhouette. Body masks are replaced entirely by the BiRefNet envelope (SAM/seed_grow skipped). Single mask [1,H,W] or per-image batch [B,H,W]. If batch size is 1 but current_image has a larger batch, the mask is broadcast to all images. Multi-person split: the foreground is divided per reference using depth (closest depth wins) when depth_map is also connected, or by face-center distance otherwise. When no references are connected, the split falls back to detected face count — each detected face becomes a pseudo-reference.
depth_mapoptIMAGEDepth map batch from Depth Anything V2 or similar. Improves masks via edge carving and cross-reference deconfliction.
depth_edge_thresholdoptFLOAT0.050.01–0.3Depth gradient threshold for edge detection. Lower = more edges detected.
depth_carve_strengthoptFLOAT0.800–1How strongly depth edges cut masks. 0=off, 1=full cut.
depth_grow_pixelsoptINT300–200Gap filling between depth edges. 0 = no growing.
body_mask_modeoptCOMBOautoBody mask strategy: - auto: seed_grow (recommended) - seed_grow: BiSeNet + SAM seed, carved by image/depth edges - sam: legacy SAM-only body segmentation
depth_sort_orderoptCOMBOfront_lastRendering order for PersonDetailer: - front_last: closest person rendered last (correct for depth_map with bright=near) - front_first: closest person rendered first (for inverted depth maps) - off: no sorting, uses slot order
sam3_modeloptSAM3_MODEL_CONFIGSAM3 model config (alternative to SAM2). Connect LoadSAM3Model output here to use SAM3 for body masks. When connected, SAM3 is used instead of SAM2 (sam_model). SAM3 supports text+point prompts and may produce tighter masks.
reference_2optIMAGE
reference_3optIMAGE
reference_4optIMAGE
reference_5optIMAGE
reference_6optIMAGE
reference_7optIMAGE
reference_8optIMAGE
reference_9optIMAGE
reference_10optIMAGE

Outputs (14)

NameTypeDescription
person_dataPERSON_DATA
face_masksMASK
head_masksMASK
body_masksMASK
combined_faceMASK
combined_headMASK
combined_bodyMASK
aux_masksMASK
previewIMAGE
similaritiesSTRING
matchesSTRING
matched_countINT
face_countINT
reportSTRING