SAX Mask Adjust
One SAM3 mask, fanned out to five different jobs
- mask
- MASK
Every workflow that uses a segmentation mask eventually hits the same problem: the mask you have isn't quite the mask the next node wants. Your detailer needs the face region plus a bit of margin; your noise injector needs the face region minus a bit; your finisher needs everything except the face. Running SAM 3 three times with three different grow settings is expensive and fiddly. SAX Mask Adjust is the cheap answer: run the segmentation once, then fan the result out through a couple of these nodes, each tuned to its own downstream job. It's a single-purpose node - grow/shrink, blur, threshold - and it does that one job well.
How it works
One MASK in, one MASK out, with four operations applied in a fixed order: invert → grow → blur → threshold.
invert- flips "white = target" to "white = protected". The killer feature. Detect the face with SAM 3, invert, and the mask now says "everything except the face" - refine the background while leaving the face alone, no re-segmentation.grow(px, −256 to +256) - hard-edged dilation (positive) or erosion (negative). Fast, jaggy, exactly what a hard mask operation should be.blur(sigma px) - gaussian softening.threshold(0–1) - binarize after the blur. 0 keeps a soft mask.
The combinations are where it gets useful, straight from the pack docs: grow=+8 for a fast hard dilation; blur=3, threshold=0.1 for a smooth, jaggy-free dilation; blur=3, threshold=0.9 for a smooth erosion; and blur=3, threshold=0 for a soft feathered mask - which is exactly what a sampler's noise_mask wants.
The usage pattern the node was built for
The README's example is the canonical one:
SAM3 (mask_grow=0) ──┬─→ Mask Adjust (grow=+8) → Detailer (larger region)
└─→ Mask Adjust (grow=-2) → Noise Injector (smaller region)
Set the SAM3 segmenter's own mask_grow to 0 and do all the per-branch tuning here - the two grow values are additive, so mixing them confuses the picture. Fan out with clean intent: one segmentation, one Mask Adjust per branch, each with its own grow/blur/threshold.
The invert use-cases are worth spelling out because they're the thing people don't expect: SAM3 returns background instead of the subject you wanted → flip invert and it's corrected instantly. Want to protect a region and expand protection slightly outward → invert + grow=+8. Face detected but you want everything-but-face detailed → SAM3(face) → Mask Adjust(invert) → Detailer.
What you don't need to worry about
There's no re-running of the model, no prompt, no seed - this is pure pixel math on the mask, instant on any machine. The grow uses the same separable max-pool as the SAM3 segmenter itself, so the semantics match what you already expect from the segmenter's grow field. It's the rare node that's hard to misuse: connect a mask, tweak two or three values, and the output is predictable.
Installing
Part of the pack:
cd ComfyUI/custom_nodes
git clone https://github.com/so16tm/SAX_Bridge
SAX/Bridge/Mask → SAX Mask Adjust. Pair it with a SAM3 Loader + Multi Segmenter upstream and a Detailer downstream and you've got the pack's whole text-mask-to-refine loop in four nodes.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | MASK | — | |
| invert | BOOLEAN | false | Invert mask (1 - mask) before grow/blur/threshold. |
| grow | INT | 0-256–256 | Positive: dilate. Negative: erode. Unit: px. |
| blur | FLOAT | 0.00–64 | Gaussian blur sigma in px. 0 disables. |
| threshold | FLOAT | 0.000–1 | Binarize after blur. 0 keeps soft mask. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| MASK | MASK | — |