BD SAM3 Multi-Prompt
One node instead of twelve, and it votes on the mask
- image
- color_reference_mask
- silhouette_mask
- combined_mask
- masked_image
- per_prompt_masks
- status
- silhouette_composite
SAM3 is the model that made text-to-mask boring: type skin, get a skin mask, no GroundingDINO, no point-click dance. The ComfyUI way to do multi-region segmentation with it is to wire one SAM3Segment node per region - people built 12-node chains for the classic "skin / face / neck / arms / legs" character split. BD SAM3 Multi-Prompt collapses that whole chain into a single node and adds the part nobody had: majority voting across overlapping detections.
What it is
A standalone SAM3 node that runs once per prompt line and combines the masks. "Standalone" is doing real work there - it loads the SAM3 model and its text encoder in-house and auto-downloads the official Comfy-Org/sam3.1 checkpoint on first use. No comfyui-rmbg, no separate model loader, no wiring.
How it works
You list one positive prompt per line in prompts (default: skin\nface\nneck\narm\nleg\nhand\nfoot - the classic character split). Each runs through SAM3, and combine_mode decides how they merge:
union(default) - OR everything together.intersection- AND, keep only pixels every prompt agrees on.subtract_first/first_only- niche single-mask modes.vote- the interesting one. Each positive detection votes +1, each negative votes −1, and a pixel survives if net votes ≥vote_threshold. Great when you have one strong positive and six negatives and you want the agreement, not the loudest voice.weighted_vote- same idea but each detection contributes its continuous confidence instead of a binary vote.
Negatives (negative_prompts) are always unioned and subtracted - e.g. clothing\nglove\nshoe peels non-skin off a body mask. Then there's the color layer: color_filter with adaptive_lab samples the reference color from your positives and cleans the mask by LAB ΔE distance - it self-tunes per character, so "red jacket" learns red, "pale skin" learns pale. silhouette_mask + enforce_silhouette clamp every result inside a character outline so SAM3 can't detect skin in the background.
Inputs a beginner actually sets
prompts- the regions you want, one per line.combine_mode-unionto start,votewhen overlapping prompts disagree.negative_prompts- what to subtract.mask_threshold- SAM3 confidence; lower keeps more area.invert_combined- leave it OFF. The tooltip is emphatic about this: flip it on and any downstream BD_PartsBuilder gets an inverted silhouette that zeroes every real per-class mask, leaving one garbage full-image "part."
Outputs: combined_mask, masked_image (mask composited over a chosen bg for preview), per_prompt_masks (the batch of individual detections), status, and silhouette_composite (outline minus detected regions - handy for "head minus eyes" skin masks).
Gotchas
SAM3's license is worth knowing: SAM and SAM 2 are Apache 2.0, but SAM 3 is not - it ships under Meta's custom SAM Licence with its own acceptable-use terms. Fine for most internal and research work; read it before shipping something commercial. And the model is big - first run downloads it, so the first execution hangs for a while. Set unload_model when SAM3 won't be used again in the run to free the VRAM.
Installing it
ComfyUI Manager: search "BrainDead" → install. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/BizaNator/ComfyUI-BrainDead
cd ComfyUI-BrainDead
pip install -r requirements.txt
Restart, find it under 🧠BrainDead/Segmentation, and let the first run download the checkpoint. From there it feeds the whole BD parts pipeline - BD Parts Refine, BD Parts Builder, BD Parts Export - or just drives a mask-to-RGBA graph for character cutouts.
Inputs (28)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| prompts | STRING | skin face neck arm leg hand foot | One positive prompt per line. SAM3 runs once per non-empty line. |
| negative_promptsopt | STRING | One negative prompt per line. SAM3 runs each, then their union is SUBTRACTED from the combined positive mask. Use to explicitly remove regions, e.g. 'clothing\nglove\nshoe' to peel non-skin off a body mask. | |
| combine_modeopt | COMBO | union | How to combine positive prompts (and how negatives are applied): union — OR all positives, then SUBTRACT negatives cumulatively. Single strong positive overrides many weak negatives. intersection — AND all positives. Then subtract negatives. subtract_first — first positive MINUS all others (then subtract negatives too). first_only — return positive #1, ignore the rest. vote — MAJORITY VOTE. Each positive detection = +1, each negative = -1. Pixel kept if net votes >= vote_threshold. Use when you have many prompts and want agreement (e.g. 1 positive vs 6 negatives → removed even if positive was strong). weighted_vote — like vote but each detection contributes its CONTINUOUS value, not binary. Soft detections weigh proportionally. |
| vote_thresholdopt | FLOAT | 1.0-20–20 | Vote-mode threshold. Pixel kept if (positive_votes - negative_votes) >= this. Default 1 = need at least one MORE positive than negative. Lower (0, -1) = positives win ties / get a head start. Higher (2+) = need stronger positive consensus. |
| vote_pos_minopt | FLOAT | 0.500–1 | In 'vote' mode, a positive prompt's mask must have a pixel value >= this to count as a vote. Higher = only confident positives count. |
| vote_neg_minopt | FLOAT | 0.500–1 | In 'vote' mode, a negative prompt's mask must have a pixel value >= this to count as a vote. Higher = only confident negatives count. |
| color_filteropt | COMBO | off | Color-aware mask refinement. Works for ANY positive-prompt category — the reference color is sampled from your positives (or color_reference_mask if provided), so red jacket → red ref, pale skin → pale ref, dark skin → dark ref, etc. off — no filtering. exclude — KEEP pixels matching the reference, suppress non-matching (cleans bleed in mask). exclude_hard — same but binary threshold (use color_strength=1). include — ADD pixels matching reference into the mask (catches what SAM3 missed). exclude_and_include — combine: keep matching AND add matching pixels SAM3 missed. remove_matching — REMOVE pixels matching reference from the mask. Use case: pass color_reference_mask=ear_region to subtract ear-colored pixels from a skin detection. |
| color_strengthopt | FLOAT | 0.700–1 | How aggressive 'exclude' is. 0 = no effect, 1 = fully suppress non-matching pixels. Try 0.5 for stylized art that doesn't match the reference range strictly. |
| color_thresholdopt | FLOAT | 0.300–1 | Threshold for binary color modes (exclude_hard, include). Pixels with color-match likelihood above this count as 'matches reference'. Lower for stylized art (try 0.15-0.25). |
| color_modeopt | COMBO | adaptive_lab | How the color filter scores match likelihood: adaptive_lab — GENERIC, works for ANY positive-prompt category. Samples reference color from the current combined mask (or color_reference_mask if provided), then scores every image pixel by CIE LAB ΔE distance. Self-tunes per character/object. fixed_hsv — SKIN-SPECIFIC. Hard-coded HSV ranges from the legacy GLSL shader. Only use this for skin detection on photo-trained characters; fails on very pale/dark skin and on non-skin categories entirely. both — multiply the two likelihoods (strictest, skin-only). Falls back to fixed_hsv if not enough confident pixels for adaptive sampling. |
| color_reference_maskopt | MASK | Optional explicit color reference mask. When provided, adaptive_lab samples reference color from this region (useful when you want to lock the reference to a specific area, e.g. a face mask for skin, a swatch region for clothing). When NOT provided, samples from the current SAM3 combined mask — which is normally what you want, since the positives ALREADY found the category you're refining. | |
| adaptive_toleranceopt | FLOAT | 252–100 | LAB ΔE distance at which adaptive likelihood = 0.5. ΔE 2.3 = just-noticeable, 25 = clearly different but related (typical skin variation), 50+ = very loose. Tighten for strict skin matching, loosen for shadowed/rim-lit skin. |
| adaptive_sample_thresholdopt | FLOAT | 0.500–1 | Only mask pixels above this value are used as reference samples for adaptive sampling. Higher = use only the most confident pixels (better reference, fewer samples). |
| adaptive_min_samplesopt | INT | 5010–10000 | Minimum number of confident skin pixels needed for adaptive mode. If fewer, falls back to fixed_hsv. |
| silhouette_maskopt | MASK | Optional character outline mask. When provided AND enforce_silhouette=True, the final combined_mask is multiplied by this silhouette as the LAST step — any SAM3 false positives outside the character (e.g. detecting 'skin' in the background) are zeroed. Also constrains the color filter's 'include' zone to within the silhouette. | |
| enforce_silhouetteopt | BOOLEAN | true | When True (and silhouette_mask is non-blank): EVERY SAM3 result (positive and negative) AND the colour filter are clamped to the silhouette immediately after inference — combined_mask reflects 'what SAM3 found INSIDE the character only'. When False: the silhouette does NOT restrict SAM3 or any mask function (raw SAM3 output, including outside the outline). The silhouette is still available — wire silhouette_composite_enable to punch the detected regions OUT of the silhouette (silhouette − combined) via the silhouette_composite output. So: enforce ON = clamp; enforce OFF = don't clamp, optionally use the outline only for the composite. |
| include_dilate_radiusopt | INT | 640–512 | When 'include' has no silhouette_mask: how far (in pixels) to dilate the SAM3 mask to define the 'candidate zone' for adding skin pixels. Higher = pulls in more distant skin (good for filling chest/torso when SAM3 only got arms/legs). |
| masked_image_bgopt | COMBO | white | Background composited under the mask in masked_image. masked_image is literally combined_mask used as alpha to blend image over this color (transparent = RGBA output with mask as alpha channel). Continuous mask values produce continuous alpha blending — no threshold trickery. |
| invert_negatives_in_per_promptopt | BOOLEAN | true | When True, negative prompts in per_prompt_masks are inverted before batching: white = pixels KEPT after subtraction, black = pixels REMOVED. Makes it visually obvious which areas each negative is excluding when previewed as a batch. Set False to get raw 'white-where-detected' for both positives and negatives. |
| confidence_thresholdopt | FLOAT | 0.500–1 | — |
| deviceopt | COMBO | Auto | 3 options: Auto, CPU, GPU |
| mask_bluropt | INT | 00–64 | — |
| mask_offsetopt | INT | 0-64–64 | — |
| unload_modelopt | BOOLEAN | false | Unload SAM3 from VRAM after this node finishes. Useful when SAM3 won't be used again this Run. |
| invert_combinedopt | BOOLEAN | false | Invert the FINAL combined mask. Global flip — turns 'detected' into 'not detected'. WARNING: if you wire combined_mask into BD_PartsBuilder.combined_mask downstream, leaving this ON will INVERT the silhouette and zero every real per-class mask. Symptom: only one full-image leftover part survives. Keep this OFF for Parts pipeline workflows. |
| mask_thresholdopt | FLOAT | 0.000–1 | Binarize the combined mask at this value. 0.0 = off (continuous, current behaviour). Any value > 0 snaps every pixel to 0 or 1 at that cutoff — removes the grey semi-transparency that causes color bleed when the mask is used in color transfer or GLSL. Try 0.5 as a starting point. |
| silhouette_composite_enableopt | BOOLEAN | false | Enable silhouette_composite output. When True: computes silhouette_mask − combined_mask (clamped 0-1) so the detected regions are punched out of the outline. Example: head silhouette minus eyes/mouth/brows = clean skin-only mask for color transfer. Requires silhouette_mask to be wired. Off = output zeros. |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| combined_mask | MASK | — |
| masked_image | IMAGE | — |
| per_prompt_masks | MASK | — |
| status | STRING | — |
| silhouette_composite | MASK | silhouette_mask − combined_mask, clamped to [0,1]. When silhouette_composite_enable=True: gives you the outline region with the detected parts punched out — e.g. head silhouette minus eyes/mouth/brows = skin-only mask, ready for color transfer. When silhouette_composite_enable=False or no silhouette provided: outputs zeros. |