BD Remove Background
SAM3 matting that actually handles hair
- image
- external_mask
- rgba
- mask
- rgb_white_bg
- rgb_black_bg
- crop_box
- sticker
Background removal is the most commoditized operation in this ecosystem - BiRefNet is in core ComfyUI now, rembg has been around since 2020 - so the question isn't "can it remove the background" anymore, it's "can it survive hair." BD Remove Background is the BrainDead answer: a self-contained, text-grounded cutter that chains SAM3 segmentation to pymatting edge refinement, and it's the one I'd reach for when the subject has flyaway hair or a complex edge and a plain matte just won't do.
What it is
One node that runs the whole pipeline internally: SAM3 text-grounded segmentation → hole fill → optional pymatting alpha matting → RGBA output. You don't wire a SAM3 model, a rmbg node, and a matting node together - it loads everything itself and gives you a clean cutout in one shot.
How it works
You give it an image and one or more positive prompts (prompts, one per line, union-combined - typically person, character, product, foreground object). It runs SAM3 for each and unions the masks. Negative prompts (negative_prompts, default background) get unioned and subtracted, which is the trick for punching the backdrop back out of a mask that bled into it.
Then the real work: matting_mode. The default closed_form runs pymatting's closed-form alpha matting around the mask boundary to produce soft, hair-accurate transparency instead of the hard chunky edge SAM3 gives you. none skips it if you want speed and hard edges. The trimap band is controlled by matting_erode / matting_dilate (8 px each by default - wider band = more matting area, slower). Around that you've got a whole toolbox: fill_holes_radius seals interior gaps, decontaminate removes background color spill at edges (that faint white fringe you see on black backgrounds), edge_refine runs a guided filter or VitMatte (auto-downloads hustvl/vitmatte on first use) on the boundary ROI, edge_shrink trims a stubborn halo, and key_gaps punches background-colored islands out of gaps between legs and fingers.
The inputs that matter for beginners
prompts- the subject, one per line. This decides what gets kept.matting_mode-closed_formfor soft edges,nonefor fast/hard.external_mask+mask_mode- hand it a mask from any source (ATR parser, another SAM3 node, manual) and it either constrains SAM3's result, subtracts, or skips SAM3 entirely and uses your mask as the alpha.crop_to_content- crops the output to the mask bounding box, killing excess transparent border.sticker_outline- a fun one: adds a die-cut colored trim around the subject, like a sticker.
Outputs: rgba (subject + alpha), mask, rgb_white_bg and rgb_black_bg composites (white is the one you want for 3D pipelines), crop_box, and sticker. The white-background composite is worth calling out - that's what you feed an image-to-3D node like Pixal3D or TRELLIS when you need a clean subject on a neutral field.
Gotchas
One that'll bite you: ComfyUI's LoadImage MASK output is the inverse of the subject (subject = black, background = white), so invert_external_mask defaults to ON to compensate. If you wire a mask straight out of SAM3 (which is already subject=white) you need to turn that off or everything inverts. Second: closed_form matting needs pymatting installed - it's not in the pack's requirements.txt, so pip install pymatting if the node complains. VitMatte downloads itself on first use.
Installing it
ComfyUI Manager: search "BrainDead" → install. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/BizaNator/ComfyUI-BrainDead
cd ComfyUI-BrainDead
pip install -r requirements.txt
pip install pymatting # if you want closed_form matting
Restart, find it under 🧠BrainDead/Segmentation. The SAM3 checkpoint (Comfy-Org/sam3.1) auto-downloads on first run, so the first cutout takes a while - subsequent ones are fast. If hair still looks like a mowed lawn after matting, raise matting_dilate a touch and let decontaminate eat the fringe; that combination fixes most complaints.
Inputs (29)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| prompts | STRING | subject person foreground | One SAM3 text prompt per line. Their masks are union-combined. Typical: 'person', 'character', 'product', 'foreground object'. |
| matting_mode | COMBO | closed_form | Edge refinement after SAM3: none — use SAM3 mask directly (fast, hard edges) closed_form — pymatting closed-form alpha matting around the mask boundary for soft, hair-accurate transparency. |
| negative_promptsopt | STRING | background | One prompt per line. SAM3 runs each → unioned → subtracted from positive mask. Useful to punch out backgrounds that bleed into the positive mask. Defaults to 'background' since that reliably helps SAM3 drop the backdrop. |
| external_maskopt | MASK | Optional mask from any source (ATR parser, SAM3, MediaPipe, manual, etc.). Behaviour is controlled by mask_mode. | |
| mask_modeopt | COMBO | constrain | How to use external_mask: constrain — intersect SAM3 result with external_mask (prevents bleed outside rough silhouette) subtract — subtract external_mask from SAM3 result (punch out an already-masked region) use_directly — skip SAM3 entirely, use external_mask as the alpha (prompts ignored). Useful for hole-fill + matting on a pre-made mask. |
| invert_external_maskopt | BOOLEAN | true | Invert external_mask before use. Default ON because ComfyUI's LoadImage MASK output is the INVERSE of the subject (subject=0, background=1) — so without inverting, constrain/subtract/use_directly act on the wrong region. Turn OFF if your mask already has subject=1 (e.g. straight from SAM3). |
| matting_erodeopt | INT | 80–64 | Pixels to erode inward to define the definite-foreground trimap band. Larger = wider unknown band = more matting area. |
| matting_dilateopt | INT | 80–64 | Pixels to dilate outward to define the definite-background trimap band. |
| fill_holes_radiusopt | INT | 40–64 | Morphological closing radius (pixels) applied before matting to seal interior gaps from SAM3. 0 = skip. |
| edge_bluropt | FLOAT | 0.00–16 | Gaussian blur radius applied to the final alpha for soft feathering. 0 = no blur. Use after 'none' matting for quick soft edges. |
| decontaminateopt | BOOLEAN | true | Estimate the true foreground colour (pymatting) to remove background colour spill at edges — fixes the faint white outline you see on the black-bg composite. Slight cost; runs on the cropped region. |
| edge_shrinkopt | INT | 00–32 | Erode the alpha inward by N px to cut a thin fringe halo. Use 1–2 if a hard edge ring remains after decontaminate. |
| edge_refineopt | COMBO | none | Edge-aware SOFT matte refine, run on the BOUNDARY ROI only (confident interior/exterior are locked, so it refines the edge — it won't fade the whole image): guided — cv2 guided filter (fast, RGB-guided) vitmatte — VitMatte deep matting (cleanest on hair/soft edges; GPU; auto-downloads hustvl/vitmatte on first use). |
| vitmatte_modelopt | COMBO | small | VitMatte variant for edge_refine='vitmatte'. Auto-downloaded from HF. |
| sharpenopt | FLOAT | 0.000–1 | Crisp the matte edge (smoothstep). 0 = leave soft, 1 = tight/clean cutout. Use to reduce a noisy/blurry boundary. |
| bg_cleanopt | FLOAT | 0.000–0.5 | Zero any alpha below this value to kill faint background ghosting / noise (e.g. 0.05). 0 = off. |
| key_gapsopt | BOOLEAN | false | Punch out background-coloured ISLANDS left inside the mask — the bits of original background showing through gaps (between legs, fingers, handles). Samples the bg colour from the removed area and removes only small matching islands, so large same-coloured SUBJECT areas (white clothing) are kept. |
| key_toleranceopt | FLOAT | 0.100.01–0.4 | key_gaps colour-match tolerance (LAB). Higher catches more (risks subject); lower is safer. ~0.08–0.15 for a clean white/solid background. |
| key_max_areaopt | FLOAT | 0.040–0.5 | key_gaps only removes bg-coloured islands smaller than this fraction of the frame (protects large subject areas). ~0.03–0.06 for small gaps. |
| key_enclosedopt | BOOLEAN | false | key_gaps: also remove ENCLOSED bg-coloured islands (e.g. between fingers in a fist) that aren't connected to the outer background. OFF by default so interior details NOT touching the background (white nametag, buttons) are kept. Open gaps (between legs, around an arm) are always removed. |
| sticker_outlineopt | INT | 00–128 | Die-cut STICKER mode: add a coloured trim border of N px around the subject (0 = off). The `sticker` output is RGBA with the subject + this outline, transparent outside. |
| sticker_coloropt | STRING | #ffffff | Trim colour for the sticker outline (hex, e.g. #ffffff white, #f00078 pink). |
| crop_to_contentopt | BOOLEAN | true | Crop the output to the bounding box of the mask (plus padding). Removes excess transparent border. |
| crop_paddingopt | INT | 160–512 | Extra pixels added around the crop bounding box. |
| output_sizeopt | INT | 00–8192 | 0 = native resolution. >0 = target size applied via output_size_mode. |
| output_size_modeopt | COMBO | none | How to apply output_size (the subject is cropped to the mask first when crop_to_content is on): none — ignore output_size pad_square — scale the crop so its LONGEST side = output_size (keeps aspect), then pad the shorter side → output_size × output_size. e.g. 1024 → fills 1024×1024 with bars top/bottom or left/right. resize_square — resize the crop straight to output_size × output_size (may distort aspect). |
| mask_thresholdopt | FLOAT | 0.500–1 | SAM3 confidence threshold. Lower = keep more area. Higher = tighter mask. |
| unload_modelopt | BOOLEAN | false | Unload SAM3 from VRAM after this node finishes. |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| rgba | IMAGE | RGBA image with alpha = subject mask. |
| mask | MASK | Subject alpha mask (H,W) [0,1]. |
| rgb_white_bg | IMAGE | Subject composited over pure white — good for 3D pipelines. |
| rgb_black_bg | IMAGE | Subject composited over pure black. |
| crop_box | STRING | 'x0,y0,x1,y1' bounding box of the cropped region in the original image. |
| sticker | IMAGE | RGBA die-cut sticker: subject + coloured trim outline (sticker_outline/sticker_color), transparent outside. When sticker_outline=0 this is the plain RGBA subject. |