Nodes/lip_mask_from_pose/Mouth Mesh Extractor (MediaPipe)
ComfyUI Node

Mouth Mesh Extractor (MediaPipe)

The MediaPipe node that hands you a lip contour render and a fill mask from one pass

By Jalen-Brunson·Created 5 months ago·Updated 21 days ago· 2
Mouth Mesh Extractor (MediaPipe)
  • images
  • mouth_render
  • mouth_mask
  • centroid_x_list
  • centroid_y_list
  • fallback_active_list
render_modecontour_only
line_colorgreen
line_thickness2
max_faces1
min_confidence0.30
mask_blur5
mask_grow0
person_index0
include_innertrue
include_outertrue
auto_fallbacktrue
fallback_area_threshold0.15
fallback_pad_h1.20
fallback_pad_v1.30

This is the node that does two jobs at once, and it's the one from this pack you'd reach for when you want a control image and a mask out of the same MediaPipe pass. MouthMeshExtractor runs Google's FaceLandmarker on your frames and returns, from one run, a rendered lip-contour image - colored lip lines on a black canvas, ready to drive a Wan VACE control - plus a filled mouth mask for the inpainting side of the same workflow. No running MediaPipe, dumping landmarks, and hand-drawing the render yourself.

The pitch is the same as the pack's MediaPipe tracked node, aimed at video: it runs FaceLandmarker in VIDEO mode for temporal tracking, then interpolates landmarks across any dropped frames so the mouth doesn't blink out mid-clip. Where it goes beyond the other nodes is output flexibility.

How it works

MediaPipe's 478-point face mesh includes a dedicated lips connection set (FACE_LANDMARKS_LIPS). The node pulls the inner and outer lip loops from that, then does three things per frame: draws the lip contours as lines, fills the region for the mask, and computes a centroid. The include_inner/include_outer booleans (both default on) control which loops contribute to the render - turn off the inner loop if you only want the vermilion border line.

render_mode picks what the render output contains:

  • contour_only - just the lip lines on black (cleanest VACE control signal)
  • contour_and_fill - lines plus a filled convex hull
  • fill_only - filled region, no lines

line_color (green/white/red/cyan/magenta) and line_thickness (1–10) set the look. Then the shared pack machinery: auto_fallback swaps in an elliptical mask when the inner/outer lip area ratio drops below fallback_area_threshold (pucker, kiss, occlusion), padded by fallback_pad_h/fallback_pad_v; mask_blur feathers the mask and mask_grow dilates it; person_index picks which face (-1 merges all); max_faces and min_confidence control detection.

Outputs: mouth_render (the IMAGE you feed a VACE control input), mouth_mask (the filled MASK for inpainting), and the by-now-familiar centroid_x_list/centroid_y_list (SAM-2 point prompting) and fallback_active_list (which frames ran on the fallback ellipse).

Installing it

Manager (search "lip_mask_from_pose") or:

cd ComfyUI/custom_nodes
git clone https://github.com/Jalen-Brunson/lip_mask_from_pose

restart. Here's the caveat the README won't tell you: it claims no extra dependencies, but that only covers the pose-based nodes. This one imports mediapipe at module load and there's no requirements.txt for Manager to auto-install, so add it yourself:

pip install mediapipe

First run downloads face_landmarker.task (~7 MB) from Google and saves it to ComfyUI/models/mediapipe/face_landmarker.task - the proper models-dir path, which is a relief compared to its tracked sibling in the same pack, which insists on a container-style /workspace path for the same file.

Troubleshooting

  • Mouth render is empty but the mask has content: you picked fill_only and are looking at the render - or include_outer got switched off. Check render_mode first.
  • The mouth blinks despite interpolation: interpolation only covers gaps between detected frames; if FaceLandmarker drops long runs of frames, lower min_confidence (its tooltip literally says lower = fewer dropped frames but more false positives).
  • Mask too fat or too skinny: mask_blur and mask_grow are your feather/dilate knobs - bump both a little before blaming the mesh.
  • Centroid jumps around: that's the fallback ellipse firing on puckers; fallback_active_list will confirm.
Categorymask/pose

Inputs (15)

NameTypeDefaultDescription
imagesIMAGE
render_modeCOMBOcontour_only3 options: contour_only, contour_and_fill, fill_only
line_colorCOMBOgreen5 options: green, white, red, cyan, magenta
line_thicknessINT21–10Thickness of lip contour lines in pixels.
max_facesINT11–10
min_confidenceFLOAT0.300.05–1Lower = fewer dropped frames but more false positives.
mask_blurINT50–100Gaussian blur for mask edges. 0 = hard edge.
mask_growINT00–200Dilate mask outward by this many pixels.
person_indexINT0-1–9Which face (0=first). -1=all faces merged.
include_innerBOOLEANtrueInclude inner lip contour (mouth opening edge).
include_outerBOOLEANtrueInclude outer lip contour (vermilion border).
auto_fallbackBOOLEANtrueFallback to elliptical mask when lips collapse (pucker/kiss).
fallback_area_thresholdFLOAT0.150.01–1Inner/outer area ratio below which fallback activates.
fallback_pad_hFLOAT1.200.5–3Horizontal scale for fallback ellipse.
fallback_pad_vFLOAT1.300.5–3Vertical scale for fallback ellipse.

Outputs (5)

NameTypeDescription
mouth_renderIMAGE
mouth_maskMASK
centroid_x_listFLOAT
centroid_y_listFLOAT
fallback_active_listBOOLEAN