ComfyUI Node

MaskGrow

Grow it, shrink it, feather it — one node, two numbers

By 0xBeycan·Created 23 days ago·Updated 3 days ago· 2
MaskGrow
  • mask
  • mask
◄invert_maskfalse►
◄grow4►
◄blur4►

Nearly every mask complaint in ComfyUI is a padding complaint. The mask is one or two pixels too tight, so the seam shows; or it's too generous, so the re-render eats past the subject; or its edge is a cliff, so the two halves of the image don't meet.

What it is

One optional MASK input, three widgets, one MASK output. It does the three things you'd otherwise chain three nodes to do:

  • invert_mask (default off) - flip the mask first, so you can protect the subject instead of editing it.
  • grow (-999 to 999, default 4) - positive grows the mask, negative shrinks it.
  • blur (0 to 999, default 4) - Gaussian blur of the edge, in pixels.

How it works

The order is fixed and it's the right order: invert, then |grow| morphological iterations, then blur. Growing is grey dilation over a cross-shaped 3×3 kernel, one iteration per pixel; a negative grow runs erosion instead, so shrinking is the same machinery in reverse. The blur at the end is what turns a grown mask into a usable soft edge.

There's a detail in the implementation worth knowing because it explains behaviour you'll see: the frame is quantised to 8-bit before the morphology and again before the blur. Fine for a hard mask, less fine for a soft one - a mask with a long feathered gradient loses resolution each pass through.

A missing mask doesn't raise. You get a blank (1, 64, 64) mask back, which is friendly in an optional branch and confusing if you were expecting an error.

Why you'd reach for it

The inpaint rules cover this directly: mask blur of roughly 4–12 px is the normal range, too low gives hard seams, too high bleeds the change into surroundings. Grow-then-blur is how you tune that without a separate mask-blur node, and it's the standard fix for the grey-box-around-the-face class of artifact - mask padding before the second pass.

My own defaults, for what they're worth: grow 4–8, blur 4 for a tight detail pass; grow 8–16, blur 8 when I'm compositing something onto a new background and can't afford a hard cutout edge. And grow negative when a detector has been generous - SAM-style masks frequently include a halo of the background, and pulling them in a couple of pixels tightens the cutout more than any prompt will.

Pair it with a fill-holes pass when the mask comes from a segmentation model: fill first (so interior dropouts don't survive), then grow, then blur. Blurring first just makes the holes soft, and they're still holes.

Installing it

ComfyUI Manager → search ComfyUI-BCNodes → install → restart. Manually:

cd ComfyUI/custom_nodes
git clone https://github.com/0xBeycan/ComfyUI-BCNodes
pip install -r ComfyUI-BCNodes/requirements.txt

Reload the browser tab afterwards. The mask nodes sit under BCNodes/mask. No extra pip installs - the pack's requirements.txt covers its PostFx and Caption Audit nodes; scipy and Pillow, which do the actual work here, are already part of a normal ComfyUI environment.

Where people get burned

Both numbers are in pixels, and pixels are resolution-dependent. grow 4 and blur 4 on a 1024px image is a snug, well-behaved edge. The same numbers on a 4K upscale are almost nothing - double and quadruple them as you go up, or you'll conclude the node isn't doing anything.

The blur runs after the growth, so the mask you end up with is both larger and softer than either number suggests on its own. Tuning the two together is normal; tuning them one at a time and being surprised by the result is common.

Inverting last is not an option. invert_mask happens first, so grow and blur then apply to the inverted region. If you wanted the subject's mask blurred and then inverted, you want two nodes.

Empty input is silent. Nothing wired in returns a placeholder mask rather than an error, so a broken branch can look like a node that runs fine and does nothing.

CategoryBCNodes/mask

Inputs (4)

NameTypeDefaultDescription
invert_maskBOOLEANfalse—
growINT4-999–999—
blurINT40–999—
maskoptMASK—

Outputs (1)

NameTypeDescription
maskMASK—