Nodes/BrainDead Nodes/BD MP Face Refine
ComfyUI Node

BD MP Face Refine

Merge MediaPipe shapes with SAM3 edges for pixel-accurate skin

By BizaNator·Created 8 months ago·Updated 3 days ago· 15
BD MP Face Refine
  • 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
masked_image_bgtransparent
min_iou0.05
target_expand4
clip_expand4
feature_expand0
max_target_fill0.95
exclusivetrue
overlay_alpha0.55

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.

Category🧠BrainDead/Segmentation

Inputs (18)

NameTypeDefaultDescription
candidatesMASKSAM3 segment batch (B, H, W). Each frame is one candidate segment.
face_ovalMASKMediaPipe 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.
imageoptIMAGEOriginal 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_maskoptMASKHead 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_bgoptCOMBOtransparentBackground 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_eyeoptMASKLeft eye mask from BD_MediaPipeFaceMask (subject's left = image right).
right_eyeoptMASKRight eye mask from BD_MediaPipeFaceMask.
left_browoptMASKLeft eyebrow mask from BD_MediaPipeFaceMask.
right_browoptMASKRight eyebrow mask from BD_MediaPipeFaceMask.
lipsoptMASKLips mask from BD_MediaPipeFaceMask.
noseoptMASKNose mask from BD_MediaPipeFaceMask.
min_iouoptFLOAT0.050–1Minimum 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_expandoptINT40–60Pixels 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_expandoptINT40–40How 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_expandoptINT00–20Pixels 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_filloptFLOAT0.950–1Reject 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.
exclusiveoptBOOLEANtrueEach 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_alphaoptFLOAT0.550–1Colour overlay opacity on the debug image.

Outputs (12)

NameTypeDescription
skinMASKRefined skin: face_oval minus all refined feature masks (with feature_expand buffer if set). Clipped to silhouette_mask if wired.
left_eyeMASKSAM3-refined left eye, clipped to MediaPipe hull. Falls back to original MediaPipe mask if no match.
right_eyeMASKSAM3-refined right eye.
left_browMASKSAM3-refined left brow.
right_browMASKSAM3-refined right brow.
lipsMASKSAM3-refined lips.
noseMASKSAM3-refined nose.
debug_overlayIMAGEColour-coded overlay: skin in warm tone, each feature in its own colour. Wire to PreviewImage to inspect the segmentation.
match_infoSTRINGPer-feature match summary: candidate index, IoU, fallback notes.
masked_imageIMAGEOriginal 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_skinIMAGEOriginal 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_maskMASKHead/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.