SAM3 Detect (Signed)
SAM3 Detect grows a minus sign
- model
- clip
- image
- masks
- bboxes
SAM3 changed masking in ComfyUI by making it conceptual: type "person" and Meta's model returns a mask for every person in the frame at once, no GroundingDINO-plus-SAM two-step. The stock SAM3 Detect node in recent ComfyUI handles that well. But it has a blind spot the moment you want a subtraction - "the two people, but not their heads", or a crowd cleared of a specific person's sunglasses. Stock SAM3 Detect can only find things; it can't remove them from what it found. SAM3 Detect (Signed) is a drop-in superset that adds one character: a leading -.
Write person:2, -head:2 and you get two people with their heads knocked out of the mask. Plain terms behave exactly as they do in the core node.
Why it has to be a new node
The clever part is that this can't just be a flag on stock's node, because of where SAM3 parses its syntax. Core tokenizes category:N inside the text encoder and hands the detector anonymous (embedding, max_detections) pairs - by the time the node reads a prompt, the term names are gone. A sign written into a CLIPTextEncode upstream would be lost before the detector ever saw it. So this node encodes each term itself, straight from the CLIP, keeping the sign attached, then runs the identical detector calls and core's own mask refinement. That's also why it takes a CLIP input where stock takes a CONDITIONING - one less node in your graph.
One deliberate divergence worth knowing: stock defaults an unqualified term to one detection, which is right for a positive ("person" = one person, so write person:2 for two). A negative is a removal, so a bare -head subtracts every match above threshold - removing one of two heads and leaving the other would look like a broken node. -head:2 caps it if you need to.
Inputs that matter
model,clip- the SAM3 model and CLIP, loaded the same way stock takes them: SAM3 is first-class in current ComfyUI, so drop the safetensors checkpoint inmodels/checkpointsand load it with the regular Load Checkpoint.prompt- comma-separated terms in SAM3'scategory:Nsyntax. This is where the action is.threshold(0.5) - the confidence floor for every term.refine_iterations(2) - SAM decoder refinement passes per detection; 0 uses the raw detector masks.individual_masks(off) - one mask per surviving positive instead of their union. Turn it on to feed this pack's Regions from Masks, so each region becomes a separate mask.negative_grow(4) - pixels to dilate the negatives before removal. A negative traces its own silhouette, so subtracting it exactly leaves a ring of edge behind - a collar of neck where a head was. Raise it if the hole has a halo, drop it to 0 if the removal eats too much.drop_empty(off) - drop positives the negatives consumed entirely. Leave it off: dropping renumbers the masks after it, and region numbers are what Region LoRAs bind to.
The masks output is the union of surviving positives (or one per positive with individual_masks on), and bboxes gives one box per mask, measured after subtraction so the two always describe the same pixels.
Install and what it needs
This node ships in ComfyUI-NynxzNodes - search "NynxzNodes" in ComfyUI Manager, or:
cd ComfyUI/custom_nodes
git clone https://github.com/Nynxz/ComfyUI-NynxzNodes
then restart. No Python dependencies. The pack targets ComfyUI's newer comfy_api node API and this node imports comfy_extras.nodes_sam3 (core's private helpers), so keep ComfyUI current - if it errors at load, update first. Text prompts only: stock's bounding-box and point-prompt inputs route through SAM3's decoder rather than its detector, and nothing there carries a sign, so keep using plain SAM3 Detect for those. And a licensing footnote from the wider SAM3 story: it's ~473M params and small, but it ships under Meta's custom SAM License, not the Apache 2.0 that SAM and SAM 2 enjoy - fine for tinkering, read it before shipping a product.
When it bites you
An empty prompt or an all-negative prompt raises an error (there's nothing to subtract from - you need at least one unprefixed term). The classic tuning loop is negative_grow: too low and you get the halo, too high and you eat the positive. And remember the positive default is one detection, so "two people minus their heads" needs person:2 written explicitly - the example in the tooltip is there for a reason.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | The SAM3 model, same as SAM3 Detect takes. | |
| clip | CLIP | The SAM3 CLIP. This node encodes each term itself — a sign written into a CLIPTextEncode would be lost before the detector saw it. | |
| image | IMAGE | — | |
| prompt | STRING | Comma-separated terms, SAM3's own 'category:N' syntax. A leading '-' subtracts that term from the rest. N caps how many of a term to keep, best-scoring first; it defaults to 1 on a positive (SAM3's own default — write 'person:2' for two people) and to all matches on a negative, since removing one of two heads leaves the other one in the mask. | |
| threshold | FLOAT | 0.500–1 | Detection confidence floor, applied to every term. |
| refine_iterations | INT | 20–5 | SAM decoder refinement passes per detection, positives and negatives alike. 0 uses the raw detector masks. |
| individual_masks | BOOLEAN | false | One mask per surviving positive instead of their union. Turn this on to feed Regions from Masks. |
| negative_grow | INT | 40–256 | Dilate the negatives, in pixels, before removing them. A negative traces its own silhouette, so subtracting it exactly tends to leave a ring of its edge behind — a collar of neck where a head was. Raise this if the hole has a halo; lower it to 0 if the removal eats too much. |
| drop_empty | BOOLEAN | false | Drop positives the negatives consumed entirely, rather than emitting a blank mask for them. Off by default because dropping renumbers everything after it, and region numbers are what Region LoRAs bind to. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| masks | MASK | — |
| bboxes | BOUNDING_BOX | One box per output mask, measured from the mask after subtraction so the two always describe the same pixels. |