BD MP Face Refine
Merge MediaPipe shapes with SAM3 edges for pixel-accurate skin
- candidates
- face_oval
- image
- silhouette_mask
- left_eye
- right_eye
- left_brow
- right_brow
- lips
- nose
- skin
- left_eye
- right_eye
- left_brow
- right_brow
- lips
- nose
- debug_overlay
- match_info
- masked_image
- masked_skin
- head_mask
MediaPipe face masks have crisp, well-placed hulls but chunky boundaries; SAM3 masks have pixel-perfect boundaries but need prompting to know what they're segmenting. BD MP Face Refine is the node that marries them: it matches each MediaPipe feature mask (eye, brow, lips, nose) to the best-overlapping SAM3 segment by IoU, intersects them - SAM3 supplies the pixel-accuracy, MediaPipe prevents bleed - and then computes skin as face_oval − refined features. The result is a set of face feature masks with MediaPipe's placement and SAM3's edges.
How it works
Each feature's MediaPipe hull is dilated by target_expand (4 px) to help find its SAM3 candidate, then matched by IoU against the candidate batch with a min_iou threshold (default 0.05 - deliberately permissive; raise to 0.15+ if the wrong segments keep matching). The matched segment is intersected with the hull, and clip_expand (4) controls how far outside the raw hull the SAM3 segment is allowed to extend. feature_expand (0) dilates the refined masks before they're subtracted from skin, which creates a useful edge buffer. exclusive (on) means each SAM3 candidate can only be matched to one feature - highest IoU wins, in a fixed matching order (lips → eyes → brows → nose).
The two required inputs are candidates (the SAM3 segment batch - each frame is one candidate) and face_oval (MediaPipe's inner face-plate mask, the skin boundary). Wire silhouette_mask (a head outline, e.g. from BD_SAM3MultiPrompt) to clip all outputs to the head boundary, and image to get composited debug/masked outputs with a chosen background (masked_image_bg: transparent/white/black/checker).
Outputs: skin, per-feature masks (left_eye, right_eye, left_brow, right_brow, lips, nose), debug_overlay, match_info, masked_image, masked_skin, and head_mask. That's a full face-segmentation kit in one run.
Installing
Ships in ComfyUI-BrainDead. ComfyUI Manager → search "BrainDead" → install, or:
cd ComfyUI/custom_nodes
git clone https://github.com/BizaNator/ComfyUI-BrainDead
cd ComfyUI-BrainDead
pip install -r requirements.txt
Restart. You'll also need a working SAM3 setup upstream (this pack's BD SAM3 Multi-Prompt can provide the candidate batch and auto-downloads the model).
Where people get burned
Two knobs do most of the damage. min_iou too low (default) can match a candidate that's mostly the background if your SAM3 batch is noisy - raise it and watch match_info. And face_oval is the inner face plate while silhouette_mask is the outer head boundary - they're different masks and wiring the wrong one in will either leave hair in your skin or clip the face away. The note on max_target_fill (0.95) matters too: it rejects the "SAM3 returned a full-white not-found result" case that would otherwise swallow your skin mask.
Inputs (18)
| Name | Type | Default | Description |
|---|---|---|---|
| candidates | MASK | SAM3 segment batch (B, H, W). Each frame is one candidate segment. | |
| face_oval | MASK | MediaPipe face oval — the INNER face plate (covers the face surface, not hair or the full head silhouette). Outer boundary for skin: refined skin = face_oval minus all refined feature masks. | |
| imageopt | IMAGE | Original character image. When wired: • Used as the debug overlay base (shows mask colours over the render) • Produces masked_image (skin region) and masked_face (full face plate) Leave unwired to composite the debug overlay on black. | |
| silhouette_maskopt | MASK | Head silhouette (white=head, black=background). When wired, all output masks are clipped to this boundary after refinement. Note: face_oval is the INNER face plate (no hair); silhouette_mask is the OUTER head boundary (full head shape including hair). They are different. Use head mask from BD_SAM3MultiPrompt here. | |
| masked_image_bgopt | COMBO | transparent | Background for masked_image and masked_face outputs when image is wired. transparent → RGBA PNG, background is fully transparent (alpha=0) white / black → RGB composite over solid colour checker → grey checkerboard (visually indicates transparency) |
| left_eyeopt | MASK | Left eye mask from BD_MediaPipeFaceMask (subject's left = image right). | |
| right_eyeopt | MASK | Right eye mask from BD_MediaPipeFaceMask. | |
| left_browopt | MASK | Left eyebrow mask from BD_MediaPipeFaceMask. | |
| right_browopt | MASK | Right eyebrow mask from BD_MediaPipeFaceMask. | |
| lipsopt | MASK | Lips mask from BD_MediaPipeFaceMask. | |
| noseopt | MASK | Nose mask from BD_MediaPipeFaceMask. | |
| min_iouopt | FLOAT | 0.050–1 | Minimum IoU for a SAM3 candidate to be accepted as a feature match. 0.05 is permissive. Raise to 0.15+ if wrong segments are being matched. |
| target_expandopt | INT | 40–60 | Pixels to dilate each feature mask BEFORE computing IoU. Used only for finding the right SAM3 candidate — does not affect the final clip boundary. 4–8 px is usually enough. |
| clip_expandopt | INT | 40–40 | How far outside the raw MediaPipe hull the SAM3 candidate is allowed to extend. SAM3 provides the pixel-accurate shape; this guards against wild bleed. Matches target_expand by default. Raise to let SAM3's edges show through more freely. Lower to stay closer to the MediaPipe shape. |
| feature_expandopt | INT | 00–20 | Pixels to dilate each REFINED feature mask BEFORE subtracting from skin. Creates an edge buffer — useful so the skin shader has a small gap between skin paint and the eye/lip regions. 0–4 px typical. |
| max_target_fillopt | FLOAT | 0.950–1 | Reject feature targets covering more than this fraction of the image. Catches SAM3 full-white 'not found' results from invert_negative. Set to 1.0 to disable. |
| exclusiveopt | BOOLEAN | true | Each SAM3 candidate can only be matched to ONE feature (highest-IoU wins). Matching order: lips → eyes → brows → nose. Recommended ON — face features don't overlap in SAM3's output. |
| overlay_alphaopt | FLOAT | 0.550–1 | Colour overlay opacity on the debug image. |
Outputs (12)
| Name | Type | Description |
|---|---|---|
| skin | MASK | Refined skin: face_oval minus all refined feature masks (with feature_expand buffer if set). Clipped to silhouette_mask if wired. |
| left_eye | MASK | SAM3-refined left eye, clipped to MediaPipe hull. Falls back to original MediaPipe mask if no match. |
| right_eye | MASK | SAM3-refined right eye. |
| left_brow | MASK | SAM3-refined left brow. |
| right_brow | MASK | SAM3-refined right brow. |
| lips | MASK | SAM3-refined lips. |
| nose | MASK | SAM3-refined nose. |
| debug_overlay | IMAGE | Colour-coded overlay: skin in warm tone, each feature in its own colour. Wire to PreviewImage to inspect the segmentation. |
| match_info | STRING | Per-feature match summary: candidate index, IoU, fallback notes. |
| masked_image | IMAGE | Original image with the head/body silhouette applied AND feature holes cut out (eyes, brows, lips, nose removed). Uses silhouette_mask as the outer boundary if wired, falls back to face_oval if not. Requires image to be wired. Background controlled by masked_image_bg. |
| masked_skin | IMAGE | Original image composited with the skin mask as alpha — shows only the skin region (face_oval minus all refined feature holes). Tighter cut than masked_image since it uses face_oval rather than the full silhouette. Requires image to be wired. Background controlled by masked_image_bg. |
| head_mask | MASK | Head/face boundary with feature holes cut out — same alpha as masked_image. Outer boundary is silhouette_mask if wired, else face_oval. Eye/brow/lip/nose regions are subtracted so this is a paintable 'skin shape' mask. Wire to SaveImage or BD_PackChannels to use as a standalone cutout. |