Mask Pinch/Widen
Slim the donut hole — Mask Pinch/Widen without moving the silhouette
- mask
- MASK
Mask Pinch/Widen answers a question the standard mask tools don't: what do you do when the inside of a mask is wrong but the outside is perfect? A mask from SAM, BiRefNet, or a face parser often looks like a donut - a solid outline with a gap in the middle you don't want. Grow or shrink it and you move the outer edge too. This node only works on the hole.
That's the pitch, and it's a genuinely different tool. For inpainting, the practical version is: you have a ring-shaped mask (an arm looped behind the head, a collar, an O-shaped artifact) and you want the model to regenerate inside the ring, not through it - pinch the gap closed and the inpaint stays where you meant it. Or you want to widen a hole so the model gets more room to work inside a region without touching anything around it.
How it works
The trick is to operate on the inverted mask, inside the bounding box. The code finds the mask's bbox, flips the region (gaps become white), then runs a flat-kernel morphology along one axis on that inverted patch, flips it back, and writes the result only back into the bbox. Because the "pinch" and "widen" happen entirely on the interior inverse, the outer silhouette never moves - that's the whole point of the pack.
- pinch = erosion of the gap: short gaps vanish, longer ones get trimmed from both ends. The hole gets smaller.
- widen = dilation of the gap: it grows by
taper_amountpixels from both sides. The hole gets bigger.
Kernel size is 2 × taper_amount + 1, so the number on the dial is the pixel amount per side.
The naming is the trap
This is where people stumble, and the README calls it out explicitly. Despite the names:
vertical_pinch/vertical_widenoperate on the gap between the left and right sides (a vertically running gap).horizontal_pinch/horizontal_widenoperate on the gap between the top and bottom (a horizontal gap).
So if you want to slim a hole that runs top-to-bottom, that's vertical_pinch. It's backwards from what you'd guess, which is exactly why the README spells it out. You can flip on several toggles at once and they apply in sequence, so you can pinch one axis and widen the other in a single pass.
The inputs that matter
mask- your input MASK.taper_amount- int, 0–2048, default 0. The pixel amount for the operation. 0 disables everything.- The four booleans above (
vertical_pinch,horizontal_pinch,vertical_widen,horizontal_widen).
Output is a single MASK. Wire it into SetLatentNoiseMask for inpainting, ImageCompositeMasked for compositing, or just a preview node while you dial it in.
Installing it
Same drill as the rest of the pack. ComfyUI Manager → search "ComfyUI-MaskMorph", or:
cd ComfyUI/custom_nodes
git clone https://github.com/TheArtOfficial/ComfyUI-MaskMorph
Restart, done. No models, no pip dependencies - requirements.txt just points at ComfyUI's torch.
Gotchas worth knowing
The default state is a full no-op: taper_amount starts at 0, so the mask passes through untouched until you turn the dial. Don't assume it's broken.
Two more honest caveats. This is a brand-new, single-commit repo with essentially no community signal - useful and clearly written, but not hardened by thousands of workflows, so preview before you trust it. And it produces hard edges, clamped to 0–1, no feathering. If the reshaped hole is headed for an inpaint, a 4–12px mask blur after this node is what saves you from visible seams. One nice touch: it implements IS_CHANGED, so it skips recomputation when the inputs haven't changed.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | MASK | — | |
| taper_amount | INT | 00–2048 | — |
| vertical_pinch | BOOLEAN | false | — |
| horizontal_pinch | BOOLEAN | false | — |
| vertical_widen | BOOLEAN | false | — |
| horizontal_widen | BOOLEAN | false | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| MASK | MASK | — |