Sapiens2 Seg Contours (line art)
Semantic line art straight from segmentation
- class_id_mask
- contours
- contour_mask
If you've ever fed canny edges of a talking face into a video control pass, you know the pain: the lines pick up every wrinkle and hair, and they flicker frame to frame because the raster edges wobble. This node takes a different route. Instead of edge-detecting the image, it draws the boundaries between semantic classes from a Sapiens2 body-part segmentation - clean, stable line art of exactly the mouth parts you care about, built to feed a control/scribble signal to an LTX union-control guide or a Wan VACE stream.
Why semantic beats raster here
The trick is that Sapiens2's segmentation knows things a gradient can't see. Its 29-class body-part segmentation labels not just Upper_Lip and Lower_Lip but also Upper_Teeth, Lower_Teeth, and Tongue as distinct classes - unusual, and exactly why this pack leans on it. Raster edge detectors only find boundaries where the image changes. Sapiens2 Seg Contours finds boundaries where the class changes, which means the border between lip and tongue shows up even where there's no visible gradient - the author's own description names lip-tongue and tongue-teeth explicitly. And because it's driven by segmentation rather than pixel texture, the temporal stability is exactly the segmentation's stability. No threshold flicker.
How it works
Feed it the class_id_mask from the Sapiens2 Body-Part Segmentation node (upstream, from the ComfyUI-Sapiens2 pack - that mask is float-encoded, class_id divided by num_classes-1, so pixel values live in [0,1]). Pick up to six classes from the dropdowns - the defaults are Upper_Lip, Lower_Lip, Tongue, Upper_Teeth, Lower_Teeth, with the sixth set to none to skip. For each selected class it takes the class's own mask, runs a morphological gradient (a 3×3 ellipse kernel) to extract that class's boundary, ORs the boundaries together so shared borders between classes appear, and dilates to line_thickness. That last one defaults to 2, and the tooltip is the practical advice: 2–3 pixels survives control-guide downscaling.
Two outputs: contours (the white-on-black line art as an IMAGE) and contour_mask (the same thing as a MASK, handy if a downstream node prefers one over the other). Feed the image into your union-control or VACE guide input.
The one setting that bites
num_classes defaults to 29 and must match whatever the upstream segmentation was built with - Sapiens2's standard is 29, but if you or your workflow rescale that, the class IDs decode wrong and your "Upper_Lip" lines end up somewhere weird. Leave it at 29 unless you know otherwise.
Install
It's in Jalen-Brunson/lip_mask_from_pose - ComfyUI Manager (search the pack name) or:
cd ComfyUI/custom_nodes
git clone https://github.com/Jalen-Brunson/lip_mask_from_pose
Restart, find it under mask/pose. The pack itself adds no dependencies beyond cv2/numpy/torch, but this node is useless without the upstream ComfyUI-Sapiens2 pack and its segmentation models installed - that's the thing producing class_id_mask. Sapiens2 itself is Meta's high-resolution human-centric transformer family, released in spring 2026 and trained on a billion human images, and it's the reason a tool this specific can even exist: until lip, teeth, and tongue were separate segmentation classes, "draw the semantic contour of the mouth" wasn't a well-defined request.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| class_id_mask | MASK | class_id_mask from Sapiens2 Body-Part Segmentation. | |
| class_1 | COMBO | Upper_Lip | 30 options: none, Upper_Lip, Lower_Lip, Upper_Teeth, Lower_Teeth, Tongue, +24 |
| class_2 | COMBO | Lower_Lip | 30 options: none, Upper_Lip, Lower_Lip, Upper_Teeth, Lower_Teeth, Tongue, +24 |
| class_3 | COMBO | Tongue | 30 options: none, Upper_Lip, Lower_Lip, Upper_Teeth, Lower_Teeth, Tongue, +24 |
| class_4 | COMBO | Upper_Teeth | 30 options: none, Upper_Lip, Lower_Lip, Upper_Teeth, Lower_Teeth, Tongue, +24 |
| class_5 | COMBO | Lower_Teeth | 30 options: none, Upper_Lip, Lower_Lip, Upper_Teeth, Lower_Teeth, Tongue, +24 |
| class_6 | COMBO | none | 30 options: none, Upper_Lip, Lower_Lip, Upper_Teeth, Lower_Teeth, Tongue, +24 |
| line_thickness | INT | 21–12 | Line thickness in pixels. 2-3 survives control-guide downscaling. |
| num_classes | INT | 292–256 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| contours | IMAGE | — |
| contour_mask | MASK | — |