Grow Mask
GrowMask, but it doesn't make you wait
- mask
- mask
ComfyUI's built-in GrowMask is one of those nodes everyone uses and nobody loves. Paint a rough inpaint mask, grow it a few pixels so the seam lands in the region you're actually re-rendering - fine. But on a big mask, or a batch of them, core GrowMask grinds through one mask at a time in a plain Python loop, and you can watch the progress bar crawl. GrowMask_lhy is the same idea reimplemented with tensor ops that run batched, and on GPU if you ask nicely. Same job, dramatically less waiting.
The description in the pack says it all: "Grew masks at an extremely fast speed." It's a from-scratch replacement, not a wrapper - which is why the inputs look slightly different from core GrowMask.
How it works
Growing a mask by N pixels is mathematically a dilation, and dilation is a max-pool. The node builds a kernel of size 2 * expand_by + 1 and runs F.max_pool2d over the mask. Shrink instead? It inverts the mask, pools, inverts back - erosion, same cost. The clever part is tapered_corners, which swaps the square pooling kernel for a diamond-shaped one built with torch.meshgrid, so corners come out rounded instead of blocky. Negative expand_by shrinks; 0 short-circuits and returns the mask untouched, so you can leave it in a workflow without paying anything.
It processes the batch in chunks (batch_size at a time) rather than all at once - that's the memory trick that lets it chew through a 100-mask batch without OOM on a mid-range card.
Inputs and outputs
The five inputs, and honestly only two matter most days:
mask(MASK) - your inpaint mask, or a whole batch of them.expand_by(INT, −255 to 255, default 0) - pixels to grow (positive) or shrink (negative).tapered_corners(BOOLEAN, default true) - rounded vs. square corners. Leave it on; square corners leave visible seams.batch_size(INT, 1–50, default 5) - masks per chunk. Raise it on a strong GPU, lower it if you're near VRAM limits.device-cpuorgpu. Defaults tocpu; on a 1080p batch the GPU path is where the speedup really shows.
One output: mask (MASK), same shape as the input, ready to feed a sampler, an inpaint node, or a mask-to-latent stage.
Installing it
From the ComfyUI-lhyNodes pack - install once, get all the nodes in this family:
- ComfyUI Manager → search
lhyNodes→ Install, restart. - Or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/lihaoyun6/ComfyUI-lhyNodes.git
python -m pip install -r ComfyUI-lhyNodes/requirements.txt
Then restart ComfyUI.
Where people get burned
The big difference from core GrowMask: expand_by here is integer pixels only. There's no float "expand then blur" - the result is hard-edged, full white or full black. If your inpainting needs a soft, feathered mask (and it usually does), run a Blur Mask after this. Also note this one is all-or-nothing on the corners toggle - there's no soft/round/square three-way like some packs offer. And device = gpu does nothing if you don't have CUDA available, so the safe default stays cpu. Minor complaints, honestly - for the one job it's built for, growing masks without the crawl, it just works.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | MASK | — | |
| expand_by | INT | 0-255–255 | — |
| tapered_corners | BOOLEAN | true | — |
| batch_size | INT | 51–50 | — |
| device | COMBO | cpu | 2 options: cpu, gpu |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| mask | MASK | — |