BD Mask Resolver
Separate skin, clothes, and accessories from one silhouette — the shader that became a node
- silhouette
- skin_mask
- clothes_mask
- original_image
- accessories_mask
- clean_skin
- clean_clothes
- clean_accessories
- residual
- debug_overlay
- status
BD Mask Resolver takes a character silhouette plus overlapping category masks - skin, clothes, accessories - and produces clean, mutually-exclusive masks. Every pixel ends up in exactly one category, so downstream steps (skin repaint, part isolation, channel packing) can trust the boundaries. It's a Python port of the GLSL Mask Resolver shader this pack used in its engine pipeline, and knowing that explains both why it exists and why it behaves the way it does.
The problem it solves is real: SAM3 gives you overlapping guesses. "Skin" mask claims a hand, "clothes" mask also claims it, and nobody decided who wins. This node decides - with a priority ranking and a color-voting step, plus a neighbor-aware gap fill so the seams don't look like a jigsaw puzzle.
The inputs that matter
The three required inputs are silhouette (the universe of pixels to assign - anything outside becomes background in every output), skin_mask and clothes_mask (your overlapping candidates), and original_image (sampled per-pixel for skin-tone detection). The optional accessories_mask defaults to empty but, when wired, gets the highest default priority.
skin_priority/clothes_priority/accessories_priority- the ranking that settles disputes. Default: accessories(3) > clothes(2) > skin(1), meaning a pixel claimed by both clothes and skin goes to clothes. Raiseskin_priorityabove 2.0 to flip it. Every pixel gets claimed by the highest-priority mask that covers it.skin_color_mode- how the color vote works.adaptive_lab(default) samples the actual skin tone from your confident skin pixels and measures LAB ΔE distance per pixel, so it self-tunes across pale to dark to reddish skin.fixed_hsvis the hard-coded HSV ranges from the original shader - it fails on very pale/dark skin.bothis strictest.adaptive_toleranceis the ΔE at which likelihood = 0.5 (25 is "clearly different but related");adaptive_min_samples(50) is how many confident skin pixels are needed before adaptive mode activates.color_weight- how much the color vote influences scoring (0 = ignore image color, 1 = strong). The default 0.6 is a reasonable middle.claim_threshold- a pixel is claimed only if the winning score exceeds this. Raise it (0.5+) to make more pixels "residual" (eligible for gap fill); lower it for aggressive claiming. This is the dial that trades sharpness for coverage.gap_fill_strength/gap_neighbor_radius- how residual pixels get assigned via neighbor voting. Default radius 8 covers small gaps; 16–32 for high-res character art.
overlap_mode switches between priority (winner takes all - each pixel in exactly one category) and soft_blend (fractional distribution where outputs can overlap). output_debug_viz gives you a color-coded overlap map (green skin, blue clothes, red accessories, gray residual) that makes tuning painfully obvious.
Outputs
clean_skin, clean_clothes, clean_accessories - the mutually exclusive result - plus residual (pixels that couldn't be confidently claimed) and debug_overlay. The status string reports what happened.
Installing
Standard BrainDead install - ComfyUI Manager search "BrainDead", or clone + pip install -r requirements.txt + restart.
One tuning tip from the pack's own docs: the skin_color_mode defaults are the part people skip and then complain about. If your character has non-standard skin tones and fixed_hsv style results look wrong, confirm adaptive_lab is on - it's the difference between masks that track the actual character and masks that track an average person.
Inputs (23)
| Name | Type | Default | Description |
|---|---|---|---|
| silhouette | MASK | Full character outline mask (white = character body, black = background). Defines the universe of pixels to assign to a category. Anything outside silhouette becomes background in all outputs. | |
| skin_mask | MASK | Mask of pixels you believe are skin (e.g. from BD_SAM3MultiPrompt with positive skin prompts). Will be clamped to silhouette. | |
| clothes_mask | MASK | Mask of pixels you believe are clothing. Will be clamped to silhouette. | |
| original_image | IMAGE | Original character image. Sampled per-pixel for HSV-based skin-tone detection (see color_weight). Resized to silhouette resolution if mismatched. | |
| accessories_maskopt | MASK | Optional mask for hard accessories (gloves, boots, belts, weapons). Defaults to all-zero if not provided. Highest default priority — wins overlaps with skin/clothes. | |
| silhouette_thresholdopt | FLOAT | 0.400–1 | Noise floor on the silhouette mask. Pixels in silhouette ABOVE this value count as character body, below count as background. Higher = stricter silhouette interpretation. NOT include/exclude — it's a noise filter. |
| skin_thresholdopt | FLOAT | 0.500–1 | Noise floor on the skin_mask input. Pixels above count as 'skin candidate', below are zeroed. Higher = only confidently-detected skin counts. Lower = pick up faint partial detections (and noise). |
| clothes_thresholdopt | FLOAT | 0.500–1 | Noise floor on the clothes_mask input. Same semantics as skin_threshold. |
| accessories_thresholdopt | FLOAT | 0.500–1 | Noise floor on the accessories_mask input. Same semantics as skin_threshold. |
| skin_priorityopt | FLOAT | 1.00.1–10 | Priority weight for skin when multiple masks claim a pixel. Default ranking: accessories(3) > clothes(2) > skin(1) — meaning a pixel claimed by both clothes and skin goes to clothes. Raise skin_priority above 2.0 to flip it. |
| clothes_priorityopt | FLOAT | 2.00.1–10 | Priority weight for clothes. See skin_priority for the ranking convention. |
| accessories_priorityopt | FLOAT | 3.00.1–10 | Priority weight for accessories. See skin_priority for the ranking convention. |
| edge_softnessopt | FLOAT | 0.300–1 | Smoothstep width around each input threshold. 0 = hard binary thresholds (sharp edges), higher = anti-aliased gradient at mask boundaries. |
| claim_thresholdopt | FLOAT | 0.150–2 | A pixel is 'claimed' by the winning category only if the winning score exceeds this. Pixels with weak/uncertain scores below claim_threshold become residual and are eligible for gap_fill. Raise this (e.g. 0.5+) to make residual generous (more gaps to fill); lower it to make claim aggressive (almost no residual). Default 0.15 = mild claim. |
| gap_fill_strengthopt | FLOAT | 0.800–1 | How aggressively to assign residual pixels via neighbor voting. 0 = leave residual untouched, 1 = fully assign residual to the strongest neighbor category. Only has an effect when residual is non-empty (controlled by claim_threshold). |
| gap_neighbor_radiusopt | INT | 81–64 | Radius (in pixels) of the neighborhood used to vote on residual pixels. Higher = looks further to find dominant category. Default 8 covers small gaps; raise to 16-32 for character art at high res. |
| color_weightopt | FLOAT | 0.600–1 | How much skin-tone detection influences scoring. 0 = ignore image color, only use input masks + priorities. 1 = strong color influence (skin pixels boosted toward skin, non-skin pixels boosted toward clothes). |
| skin_color_modeopt | COMBO | adaptive_lab | How to detect skin-toned pixels in the original image: adaptive_lab — sample reference skin color from confident skin_mask pixels, compute LAB ΔE distance per pixel. Self-tunes per character (works on pale white through dark African through reddish Navajo skin). fixed_hsv — hard-coded HSV ranges from the original GLSL shader. Fails on very pale/dark skin. Fallback for when adaptive can't sample enough pixels. both — multiply the two likelihoods. Strictest mode. |
| adaptive_toleranceopt | FLOAT | 252–100 | LAB ΔE distance at which adaptive likelihood = 0.5. Smaller = stricter (only pixels very close to sampled skin tone count). Larger = more permissive. ΔE 2.3 = just-noticeable difference, 25 = clearly different but related (typical skin variation), 50+ = very loose. |
| adaptive_sample_thresholdopt | FLOAT | 0.700–1 | Only skin_mask pixels above this value are used as reference samples for adaptive mode. Higher = use only the most confident skin pixels (better reference, fewer samples). Lower = use more pixels including soft edges (more samples, may include non-skin). |
| adaptive_min_samplesopt | INT | 5010–10000 | Minimum number of confident skin pixels needed for adaptive mode to activate. If fewer, adaptive returns zeros and falls back to fixed_hsv (in 'both' mode) or off. |
| overlap_modeopt | COMBO | priority | priority = winner takes all (each pixel goes to exactly ONE category). soft_blend = distribute proportionally by score (each pixel split fractionally; outputs may sum to >100% in overlap zones). |
| output_debug_vizopt | BOOLEAN | false | If True, debug_overlay shows color-coded overlap map: green=skin, blue=clothes, red=access, yellow=skin+clothes, magenta=skin+access, cyan=clothes+access, white=triple, gray=residual gap. Tinted by skin-tone confidence. If False, debug_overlay just shows the residual mask as RGB grayscale. |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| clean_skin | MASK | — |
| clean_clothes | MASK | — |
| clean_accessories | MASK | — |
| residual | MASK | — |
| debug_overlay | IMAGE | — |
| status | STRING | — |