Nodes/ComfyUI_zura_nodes/Zura · Choose Performer
ComfyUI Node

Zura · Choose Performer

When SAM finds four people and you only wanted one

By ZURAVFX·Created about a month ago·Updated a day ago· 2
Zura · Choose Performer
  • masks
  • initial_performer_mask
  • selection
◄performer-1►
◄positionauto►

Segmentation models are generous. Ask SAM for "person" on a street shot and you'll get the walker, the cyclist, the poster on the wall, and a stranger's shoulder in the foreground - all as separate masks in one batch. GenjChoosePerformer ("Zura · Choose Performer") is the one-job node that picks one of those masks and hands it downstream, with a human-readable note about which one it picked.

Why a node for this at all

Because "the biggest mask" is wrong often enough to matter. A subject standing closer to the camera isn't necessarily the one you're replacing, and in a wide shot the largest detection is frequently the guy at the edge of frame. The node's rule, when you leave it on its default, is largest central detection: it computes each mask's area and its centroid, then scores them as area divided by 1 + 4 × d², where d² is the squared normalised distance of the centroid from the centre of the frame. Area wins, but a big off-centre blob gets taxed for being off-centre.

In the pack's own Wan route, this is exactly how the reference character gets isolated: SAM 3 segments the reference image into individual masks, GenjChoosePerformer picks one, and the result is resized, cropped and pasted onto a neutral grey canvas to become the character reference the sampler sees. If it picks the wrong person there, your "character replacement" replaces the wrong face and you'll blame the model instead of the picker.

Inputs and outputs

masks takes a batch of masks (MASK) - typically straight off a segmentation node running with individual masks enabled, so each detection is its own 2D mask in the batch.

performer is an INT from -1 to 63. The tooltip is the whole story: -1 selects the largest central detection. Otherwise use a zero-based detection index. So when you want a specific person, you need to know their index in the batch - node 9 in the pack's shipped prepare graph sets it to -1 with the title "Performer: -1 = largest central", which tells you how often that's good enough.

Outputs:

  • initial_performer_mask - a single 2D MASK containing the chosen detection, which is what you wire into a crop, a resize-to-match, or a compositing node.
  • selection - a string like Tracking detection 2 of 5. Cheap to wire to a text display, and it's the fastest way to find out that your index guess was off by one.

The three errors you'll actually see

All of these are the node refusing to guess, which is the right behaviour:

  • No performer detected. Try 'person', lower the detection threshold, or select a clearer opening frame. - you passed a batch where every mask is essentially empty. The threshold suggestion is the real one; SAM 3 with a threshold of 0.5 on a soft, motion-blurred frame will simply return nothing.
  • Detected 3 objects. Select an index from 0 to 2. - you typed an index past the end of the batch. Note that the count comes from the batch, not from a frame, so a batch built from several frames gives you odd indices.
  • The selected detection is empty. Select a visible performer. - you picked an index that exists but is blank. The usual cause is that the detector wasn't asked for individual masks, so what arrived isn't one-mask-per-detection and the indexing doesn't mean what you think it does.

Install notes

GenjChoosePerformer ships in Zura Nodes: ComfyUI Manager → search Zura Nodes → install → restart ComfyUI. Manual clone:

cd ComfyUI/custom_nodes
git clone https://github.com/ZURAVFX/ComfyUI_zura_nodes
python -m pip install -r ComfyUI/custom_nodes/ComfyUI_zura_nodes/requirements.txt

The node itself is pure tensor arithmetic - no model, no ffmpeg, nothing to download. But the thing feeding it is usually SAM 3.1 (checkpoints/sam3.1_multiplex_fp16.safetensors, linked in INSTALL_STUDIO.md), and the pack's person-mask route also wants ultralytics/segm/person_yolov8m-seg.pt plus the ViTPose and YOLOv10 ONNX detectors for pose. Those are separate downloads and they're the multi-gigabyte part of the install.

Practical notes

Two things worth knowing. First, mask batches from different frames are not comparable by index - if you're picking by hand, split per frame, or trust -1. Second, the mask this returns is at the detector's raster, not your video's. The pack resizes it before cropping (ResizeImageMaskNode with nearest-exact); do the same, because a nearest-neighbour resize of a slightly wrong raster is how you get a half-missing jaw in a face replacement.

CategoryZura/Artist Studio

Inputs (3)

NameTypeDefaultDescription
masksMASK—
performerINT-1-1–63-1 selects the largest central detection. Otherwise use a zero-based detection index.
positionoptCOMBOauto4 options: auto, centre, left, right

Outputs (2)

NameTypeDescription
initial_performer_maskMASK—
selectionSTRING—