Nodes/ComfyUI-H3-FaceRefine/H3 Face Track + Crop
ComfyUI Node

H3 Face Track + Crop

The node that fixes H3's tiny, smeared distant faces

By Carasibana·Created about a month ago·Updated 2 days ago· 384
H3 Face Track + Crop
  • images
  • identity_reference
  • identity_clip_vision
  • face_pick
  • crops
  • transform
  • preview
  • report
  • canvas_w
  • canvas_h
  • frame_count
detector
confidence0.35
crop_factor2.5
canvas_width768
canvas_height768
canvas_modemanual
smooth_window21
size_smooth_window51
smooth_methodgaussian
size_modeper_frame
identity_tracktrue
identity_threshold0.28
selectlargest_face
fallback_detectornone
fallback_head_frac0.50
select_index0
identity_modelinsightface
cut_detectionnone
cut_threshold3.00
absent_shotsoff
X0
Y0
frame_index0

H3 Face Track + Crop is the engine of the ComfyUI-H3-FaceRefine pack - the node that takes a video clip, finds the face on every frame, and hands MiniMax H3 a batch of crops where the face fills the canvas instead of being a few dozen pixels of smudge. Everything else in the pack hangs off what this node produces.

Why it exists: H3 renders faces poorly when the head occupies a small fraction of the frame. That's a property of head-size-in-frame, not of output resolution, so it persists at 720p and above. The fix is the same loop FaceDetailer made standard for stills - detect, crop, re-render at proper resolution, paste back - adapted to video. This node is the detect-and-crop half, and it's where all the temporal thinking happens.

How it works

Per frame, a YOLO face detector (face_yolov8m.pt by default, the same Bingsu/adetailer weights ADetailer and Impact Pack use) finds the face. Frames where detection fails get their gaps filled by interpolation, and the crop trajectory is then smoothed with a gaussian window - because a crop box that shivers frame-to-frame makes the refined face boil, even when the original subject sat still. Each crop is sized so the face holds a constant fraction, then everything is resized to one canvas size, since H3 generates a single fixed WxH for a whole sequence.

Two optional inputs make it smarter. Give it an identity_reference image and it'll pick the subject by face identity (via InsightFace buffalo_l embeddings) instead of by size - the difference between tracking your person through a crowd and latching onto whoever's briefly biggest. And a fallback_detector (a person/body model) supplies a real head position on frames where the face detector finds nothing, rather than blindly interpolating.

The inputs that actually matter

  • images - your clip from the video loader.
  • detector - face_yolov8m.pt is the good default.
  • confidence (0.35) - lower catches more profiles, at the cost of false positives.
  • crop_factor (2.5) - crop side as a multiple of face height; 2.0–3.0 is the useful range. Bigger gives the seam more context to land in, but less magnification.
  • canvas_mode - auto_capped_768 is the sane default: sizes the canvas from the largest crop, clamped to 768 (H3's native short edge, and a sensible VRAM ceiling). manual uses the two values below; auto_no_downscale never shrinks a crop but can get expensive on clips with close-ups.
  • smooth_window (21) / size_smooth_window (51) - raise the first if the box shivers, and note the second is deliberately bigger: size jitter makes the crop breathe, which reads as shimmer.

Outputs - and one you must not skip

  • crops → H3 Inject Video Latent's images (and the SAM mask node).
  • transform → the spine of the whole pack: H3 Face Stitch Back, H3 Per-Frame Denoise and H3 Face Mask (SAM) all need it.
  • preview - a debug view of the tracked boxes.
  • report - detection stats; watch for magnification < 1.0x, which means a crop is being downscaled and real detail discarded. Raise the canvas, or skip clips that are close-ups throughout.
  • canvas_w / canvas_hmust be wired to the H3 node's width/height. In the auto modes the tracker chooses the size; if the H3 node disagrees, the latent shapes differ and injection refuses.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/Carasibana/ComfyUI-H3-FaceRefine.git

Restart, and the nodes appear under MiniMax H3/Face Refine (ComfyUI Manager finds the pack by title too). ultralytics, scipy and insightface auto-install. The one model you must supply yourself is the face detector, face_yolov8m.pt, dropped in models/ultralytics/bbox/. Everything else - the H3 diffusion model, text encoder, VAEs - you already have if you're generating H3 video.

One onnxruntime gotcha worth knowing before identity tracking: insightface needs it, and the pack deliberately pins no variant. Install onnxruntime-gpu alongside an existing CPU onnxruntime and the CPU package shadows it, CUDAExecutionProvider disappears, and identity matching silently runs on CPU. Check with python -c "import onnxruntime; print(onnxruntime.get_available_providers())".

For multiple people in one shot: run the pipeline once per subject, each with that person's identity_reference and their own refs on the H3 node, then chain them - feed run 1's stitched output in as run 2's base_images. The composites accumulate.

CategoryMiniMax H3/Face Refine

Inputs (27)

NameTypeDefaultDescription
imagesIMAGE
detectorCOMBO1 options: face_yolov8m.pt
confidenceFLOAT0.350.05–0.95
crop_factorFLOAT2.51.2–8Crop side as a multiple of detected face HEIGHT. 2.5 puts the face at ~40% of the crop, comfortably inside H3's good regime. Bigger = more context so the seam lands in hair/background, but less magnification. 2.0-3.0 is the useful range.
canvas_widthINT768128–1344Resolution H3 generates at. 768 is H3's native short edge and the default here; 512 is cheaper. In manual mode this is used exactly as typed, high or low. Ignored when canvas_mode is not 'manual', where the canvas comes from the crop instead and never falls below 512x512. Cost scales with area: 768 is 2.25x the latent tokens of 512.
canvas_heightINT768128–1344
canvas_modeCOMBOmanualmanual: use canvas_width/height as given. auto_no_downscale: size the canvas from the LARGEST crop in the video so no frame is ever downscaled (magnification never drops below 1.0x). Can get expensive on videos that include close-ups. auto_capped_768: same, but clamped to 768 - H3's native short edge and a sane VRAM ceiling. Both auto modes clamp UP to a minimum of 512x512, whatever the crop, so a small face in a low-resolution clip is still magnified. manual is not clamped - it uses canvas_width and canvas_height exactly as typed.
smooth_windowINT211–201Frames of smoothing on the crop CENTRE. 21 at 24fps is ~0.9s. Raise if the box still shivers; lower if it lags behind fast head movement.
size_smooth_windowINT511–201Frames of smoothing on the crop SIZE. Wants MORE than the centre: size jitter makes the crop breathe, which changes the resample factor every frame and reads as shimmer. Real zoom moves are slow, so heavy smoothing here costs nothing.
smooth_methodCOMBOgaussiangaussian: best jitter rejection. savgol: preserves the shape of a push-in better at large windows. moving_average: the old boxcar, leaves residual jitter.
size_modeCOMBOper_frameper_frame: constant face-fraction in every crop (correct for push-ins). max_of_clip: one size for the whole video, only useful when the shot is genuinely static.
identity_referenceoptIMAGEA clear face image of the person to track. When supplied, the subject is chosen by FACE IDENTITY rather than by size, so a crowd scene locks onto the right person even when someone else is briefly larger or nearer. OPTIONAL on this node. identity_track works without it: the anchor is then built FROM THE CLIP, off frames where one face clearly dominates, which is usually the better anchor since a stylised reference sits in a different domain. Supply one only to name a specific person. Read only while identity_track is ON. With it off this input is ignored, and the report says so. Without either, 'largest_face' has no notion of WHO it is following - it just takes the biggest box each frame, which switches subject whenever the framing changes. FOR MULTIPLE PEOPLE: run the pipeline once per subject, each with that person's reference here and their own refs on the H3 node, and chain them - feed run 1's stitched output in as run 2's base_images. The composites accumulate.
identity_trackoptBOOLEANtrueHold one subject through a crowd. Continuity (nearest box to the previous position) decides most frames; the face-identity embedding is consulted only when two candidates are similarly plausible or their boxes overlap - which is both the accurate and the cheap arrangement, since the embedding model then runs on a handful of frames instead of all of them. The anchor is taken FROM THE CLIP by default (frames where one face clearly dominates), because an external stylised reference sits in a different domain - measured similarity between an illustration and a render of the same character was only 0.305, where same-domain faces score 0.5-0.7. This switch also gates identity_reference: with it OFF a connected reference is not read at all, and the subject is chosen by select instead. The report says so when that happens.
identity_thresholdoptFLOAT0.280–1Minimum score to accept a face as the reference person. Below this the frame falls back to continuity (nearest to the previous position at a similar size), which is what carries tracking through profiles and partial occlusion where embeddings become unreliable. The scale depends on identity_model. 0.28 suits insightface cosine; clip_vision sits much higher (~0.80) because its similarities are compressed; ccip scores 0.5 at its own published operating point. SET 0 to use whichever default the chosen model recommends. The report prints the scores actually seen, so it can be tuned from evidence rather than guessed.
selectoptCOMBOlargest_faceHow the subject is chosen. It is chosen ONCE per shot, on the first frame that holds it, and continuity follows that same face from there - it is NOT re-ranked each frame. A subject who walks from the left of frame to the right while someone else crosses the other way is still tracked correctly. largest_face / smallest_face: biggest or smallest face by height. left_most / right_most / top_most / bottom_most: by the CENTRE of the face box. centre_most: nearest the centre of the frame. closest_to_xy: nearest the X, Y you give, measured on frame_index. detector_score: the detection the detector is most confident about. AT A HARD CUT a rank means nothing across the join - everyone is renumbered. With cut_detection ON, each shot chooses again by this rule, so a cut can land on a different person. With it OFF the video counts as one shot and continuity runs straight through a real cut onto whichever face is nearest the last position, which may be anyone. To hold one person across cuts, wire identity_reference, or choose the face in H3 Load Video + Face Select. Used only when no identity_reference is connected.
fallback_detectoroptCOMBOnoneUsed only on frames where the FACE detector finds nothing (subject turned away). A person/body model such as segm\person_yolov8m-seg.pt gives a real head position from the top of the body box, which beats interpolating blindly between the last and next face. Set 'none' to interpolate instead.
fallback_head_fracoptFLOAT0.500–1.5Head centre as a multiple of face height below the top of the person box. 0.5 puts it half a face-height down, which is about right for a head seen from behind.
select_indexoptINT00–63Which face in that ranking to track. 0 is the first, 1 the second, and so on. The subject is locked on the first frame that actually contains this index, so a video that opens on one face and only later shows a crowd still finds face 1. Frames before that lock-on are interpolated from it and faded out of the composite, the same as a detection dropout; the report counts them. Clamped, with a warning in the report, if the video never shows that many faces at once. Ignored entirely when identity_reference is connected. H3 Load Video + Face Select shows the faces numbered, if you need to see which number is who.
identity_modeloptCOMBOinsightfaceWhich model decides that two faces are the same person. insightface: ArcFace/buffalo_l. Photographed human faces. It reaches faces through its OWN detector, which does not fire on illustration - so on anime it finds no candidates at all and tracking quietly falls back to continuity. clip_vision: ComfyUI's CLIP vision, wired into identity_clip_vision from a CLIPVisionLoader. No extra install, works on any domain - anime, 3D, stylised - but it describes appearance rather than identity, so two characters with a similar palette can collide. ccip: the illustration counterpart of ArcFace, purpose-built for 'same anime character?'. Best on anime. Needs 'pip install dghs-imgutils', which this pack deliberately does not install for you - it pins numpy<2 and pulls opencv-contrib-python. The last two embed the boxes YOUR detector found, so pair them with an anime face model in the detector slot.
cut_detectionoptCOMBOnoneHard-cut detection, so the crop is not smoothed ACROSS a cut. none: off. Correct for single-shot videos, which is what H3 generates. auto: split at the cuts and treat each shot as its own window for the smoothing, interpolation and composite fade. The canvas is still sized once for the whole video.
cut_thresholdoptFLOAT3.000.5–20How far a frame has to stand out from its NEIGHBOURS to count as a cut. 3.0 is PySceneDetect's adaptive default. Lower catches more and risks splitting a continuous shot, which costs smoothing on both sides. Higher takes only unambiguous cuts. Only used when cut detection is on. The report says how many cuts were found and where, so tune it from that.
identity_clip_visionoptCLIP_VISIONA CLIP vision model from a CLIPVisionLoader, used only when identity_model is clip_vision. Any of the usual ComfyUI clip_vision checkpoints works; the bigger ViT-L/H models separate characters better than the small ones.
absent_shotsoptCOMBOoffFind shots the subject is not in, so they are not rendered at all. by_identity: a shot where no sampled face matches the identity anchor above identity_threshold is treated as not containing the subject. Its frames keep their original pixels and drop out of the batch. Needs identity matching to be working - it does nothing without an anchor. Sampled, not exhaustive, so a brief appearance can be missed. The report names every shot it drops and the score it saw.
XoptINT00–16384Only used by select=closest_to_xy. Horizontal position in PIXELS of the source video frame, measured from the TOP-LEFT corner, increasing to the right. On a 960x544 clip, 0 is the left edge, 960 the right, 480 the middle. The point does not have to sit on a face: the nearest face CENTRE wins, however far away it is.
YoptINT00–16384Only used by select=closest_to_xy. Vertical position in PIXELS of the source video frame, measured from the TOP-LEFT corner, increasing DOWNWARD. On a 960x544 clip, 0 is the top edge, 544 the bottom, 272 the middle.
frame_indexoptINT00–999999Only used by select=closest_to_xy. The frame the X, Y measurement is taken on, counting from 0 for the FIRST frame. It counts the frames this node loaded, so with skip_first_frames or select_every_nth set it counts from the first frame kept, not the first frame of the file. The face found there is followed forwards and backwards through its shot, so pick a frame where the subject is clearly visible rather than one the detector may miss them on.
face_pickoptH3FACEPICKThe subject chosen upstream by H3 Load Video + Face Select. Decides who to follow, per shot, and carries the boxes and shot boundaries with it so this node does not detect the video again. select, select_index, cut_detection and cut_threshold are then unused, and detector and confidence are too unless a fallback_detector or a crop-based identity_model still needs them - they are then unused - the report names the detector that actually produced the boxes.

Outputs (7)

NameTypeDescription
cropsIMAGE
transformH3FACEXFORM
previewIMAGE
reportSTRING
canvas_wINT
canvas_hINT
frame_countINT