Sub-Pixel Mask Refiner
Turn Jagged SAM Masks Into Clean Alphas
- mask
- refined_mask
JHPixelProSubPixelMaskRefiner is the node you reach for right after SAM, YOLO, or rembg hands you a chunky binary mask. Those masks are hard-edged, aliased, and off by a pixel or two - fine for inpainting, terrible for compositing. This node turns them into a sub-pixel alpha mask: a guaranteed-1.0 interior, a guaranteed-0.0 exterior, and a Gaussian-feathered band in between. That's the difference between a cutout that looks glued on and one that survives contact with a different background.
How it works: it binarizes your mask at threshold (0.5), erodes by erosion_radius to define the "definitely inside" core, dilates by dilation_radius for the "definitely outside" core, then Gaussian-feathers the uncertain band by feather_sigma. The output is float32 in [0,1] - exact 1.0 inside, exact 0.0 outside, a smooth ramp in the middle. It's the classic cutout workflow in one node.
The knobs that matter:
erosion_radius(default 2) - how much of the interior to protect as solid.dilation_radius(default 4) - how far out to guarantee background. Keep it ≥erosion_radiusfor a stable feather band.feather_sigma(default 2.0) - the softness of the transition, 0.1..32.threshold(default 0.5) - binarization level applied before morphology.
Output: refined_mask, a single MASK. Feed it into a composite, an alpha matte chain, or use it as an inpaint mask with a bit of blur.
One honest limitation: erosion and dilation use a square kernel (Chebyshev metric), so with radius > 16 edges get slightly boxy rather than rounded. For normal portrait work at radius 2–8 you'll never notice.
Install is the shared pack install:
cd ComfyUI/custom_nodes
git clone https://github.com/jetthuangai/ComfyUI-JH-PixelPro.git
cd ComfyUI-JH-PixelPro
pip install -r requirements.txt
Restart and it's under ComfyUI-JH-PixelPro/mask, or use ComfyUI Manager → search "ComfyUI-JH-PixelPro".
Troubleshooting: it's float32-only - there's no precision pin, so don't expect float16 speedups, and large feather_sigma values need the float precision to stay clean. If you set both radii to 0 you get a bare Gaussian feather of the raw mask, which is a decent quick edge-softener in its own right. And midtone masks are fine as input - they get thresholded before morphology, so only the 0/1 decision matters; the geometry comes from the threshold, not from your mask's softness.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | MASK | — | |
| erosion_radius | INT | 20–64 | Pixel radius eroded into the protected 'definitely inside' core. 0 = no inside protection (output = clamped gaussian feather). |
| dilation_radius | INT | 40–64 | Pixel radius dilated into the protected 'definitely outside' core. Set ≥ erosion_radius for a stable feather band. 0 = no outside protection. |
| feather_sigma | FLOAT | 2.00.1–32 | Gaussian sigma (pixel) used to feather the uncertain band between inside and outside cores. |
| threshold | FLOAT | 0.500–1 | Strict binarization threshold (`mask > threshold`) applied before morphology. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| refined_mask | MASK | — |