H3 Face Stitch Back
The node that puts the refined face back where it belongs
- base_images
- refined_crops
- transform
- masks
- images
H3 Face Stitch Back is the final node in the ComfyUI-H3-FaceRefine pipeline: it takes the crops that MiniMax H3 re-generated, warps each one back onto the exact spot the face came from, colour-matches it, feathers the seam, and composites it into the original frame. If the tracker is the spine of this pack, the stitch is the part the eye actually judges - a perfect refine with a bad paste reads as a pasted-on face, and it's the stitch that decides.
The pack exists because H3 renders distant heads as smears. The fix is the classic detailer loop Impact Pack made famous: detect, crop so the face fills the canvas, let the model re-render, paste back. This node is the paste step, and it inherits two important ideas from FaceDetailer along the way.
How it works
The clever part is that it's one batched grid_sample - every refined crop is warped back onto its float-precision box in a single GPU tensor op. That matters because the tracker smoothed its trajectory to sub-pixel accuracy, and a naive paste would re-quantize it, re-introducing exactly the jitter the whole pipeline exists to remove. Then a per-channel mean/std match brings the crop's brightness and tint in line with the region it replaces, the paste mask is blurred by feather, and the composite happens.
The design principle to internalise: only the face region composites. The wide crop exists to give the sampler context, not to be pasted. Pasting the whole crop covers ~88% of the canvas versus ~16% for the face box, and anything H3 changed in the hair or background comes back as a rectangle.
Inputs that matter
base_images- the original frames, the same clip you fed to the tracker.refined_crops- theVAEDecodeoutput of your refined crops.transform- from H3 Face Track + Crop; it records where every crop came from.paste_region-face_only(default) orface_ellipsepaste just the detected face;full_croprisks a visible rectangle.feather(6) - blur radius on the paste mask in source pixels. This is the trap input: if it were canvas-relative, the blend would come out tightest exactly where the face is smallest - a hard edge appearing as a shot zooms out. Use ~24 with a rect mask, 4–8 with a SAM mask.colour_match(1.0) - without it the refined face comes back subtly brighter and reads as pasted on. Dial down if it over-corrects.blend(1.0) - global opacity of the refined face; below 1.0 mixes back toward the original, handy for dialing back over-sharpening.undetected_frames(fade_out) - what happens where no face was found. All frames still run through H3 either way (that's what keeps it temporally consistent); this only controls pasting.fade_outramps the composite to zero,skiphard-cuts,composite_anywayrisks H3 hallucinating a face onto the back of a head.masks(optional) - per-frame masks from H3 Face Mask (SAM), which overridepaste_region.
Output is a single images tensor - the finished frames, straight to your video save node.
Install and gotchas
The pack is one clone into custom_nodes/ (or search "ComfyUI-H3-FaceRefine" in ComfyUI Manager), then restart. For this node you need the transform wiring intact and, to run the actual pipeline, a face detector (face_yolov8m.pt in models/ultralytics/bbox/) plus the usual H3 model stack. The stitch itself needs nothing extra.
Where people get burned: frame count mismatch. If base_images, refined_crops and the transform disagree on length, the node truncates to the shortest and prints a warning - your clip's frame count must sit on H3's 17k+5 grid (5, 22, 39 …), which clips generated by H3 already do. And if the face looks pasted on, that's colour_match working or not working - check it's at 1.0 before you blame the geometry.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| base_images | IMAGE | — | |
| refined_crops | IMAGE | — | |
| transform | H3FACEXFORM | — | |
| paste_region | COMBO | face_only | WHAT gets composited back. face_only / face_ellipse paste just the detected face box (FaceDetailer's behaviour - the wider crop exists to give the sampler context, not to be pasted). full_crop pastes the whole crop including hair, shoulders and background, which risks a visible rectangle if H3 alters them. |
| mask_dilation | INT | 160–256 | Grow the face box before blurring, in canvas px. Impact Pack dilates the same way so the blur has room and the blend does not eat into the face itself. |
| feather | INT | 60–256 | Gaussian blur radius on the paste mask, in SOURCE pixels. Measured against the final frame, not the canvas, so the blend is the same physical width whatever this frame's magnification happens to be. Canvas-relative feather is a trap: a 75px crop blown up to 512 makes a 40px canvas feather only ~6 source px, while a 720px crop makes it ~56. The blend ends up TIGHTEST exactly where the face is smallest and the composite needs the most help - which reads as a hard edge appearing as a shot zooms out. |
| colour_match | FLOAT | 1.000–1 | Match the refined crop's per-channel mean/std to the region it replaces. The crop and the full frame went through independent passes, so without this the face can come back subtly brighter or differently tinted and read as pasted on. |
| blend | FLOAT | 1.000–1 | Global opacity of the refined face. Below 1.0 mixes back toward the original - useful to dial back over-sharpening. |
| undetected_frames | COMBO | fade_out | What to do on frames where no FACE was found (turned away / occluded). ALL frames are still sent through H3 either way - that is what keeps it temporally consistent - this only controls whether the result is pasted back. fade_out: ramp the composite to zero across the gap (smooth, no pop, recommended). skip: hard cut - those frames keep original pixels exactly. composite_anyway: paste regardless. Risks H3 hallucinating a face onto the back of a head. |
| feather_scales_with_cropopt | BOOLEAN | false | Old behaviour: treat feather as CANVAS pixels, so the blend narrows as the crop shrinks. Leave off. |
| masksopt | MASK | Optional per-frame paste masks in CANVAS space, e.g. from H3 Face Mask (SAM). Overrides paste_region. This is the FaceDetailer bbox+SAM path: the mask follows the actual face so the blend falls on the jaw and hairline instead of an arbitrary rectangle. With a SAM mask use a SMALL feather (4-8); a rectangle needs much more. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | — |