CropFaces
Upright face crops, ready-made masks, and the warp that puts it all back
- faces
- crops
- masks
- warps
CropFaces is the middle of the facetools pipeline, and it's the node that earns the pack its keep. DetectFaces hands it a list of FACE objects; it hands you three things: a batch of square, upright face crops; a mask for each crop; and the warp matrix that puts it all back. You run your inpaint or refine pass on the crops, then WarpFacesBack stitches them into the original image. The rest of your picture is never touched - no encode/decode drift, no grey-box color shifts, which is exactly the failure mode ADetailer-style pipelines are notorious for.
What it does
For each face it takes an ArcFace-style similarity transform to the face's five keypoints (eyes, nose, mouth corners), composes it with the rotation DetectFaces already figured out, and warps out a square crop. Because the alignment happens on face landmarks rather than the image axes, a head tilted 45 degrees comes out of the crop level. That's the rotation-aware core of the whole pack.
Three inputs matter:
- crop_size (512–1024, default 512): the edge length of the square crop. Bigger means the detail pass gets more pixels of the face; 512 is a solid default for SDXL-era detailing.
- crop_factor (1.0–3.0, default 1.5): how much context around the face you keep. 1.5 includes some hair and shoulders so the inpaint model knows where the face ends. Crank it up if the crop feels claustrophobic.
- mask_type: where the mask comes from.
simple_squareis just the bounding box;convex_hulluses MediaPipe face mesh landmarks to trace the actual head shape;BiSeNetandjonathandinurun a real face-parsing segmentation model (details in the BiSeNetMask and JonathandinuMask articles) for occlusion-aware masks. Both parsing options need their model files and more memory, so start withconvex_hullif you just want a head-shaped mask without the setup.
Outputs are crops (IMAGE), masks (MASK), and warps (WARP). Keep them bundled as a trio - they're positional. The warp is a 2x3 affine matrix recording exactly how each crop was pulled out of the original, which is what makes lossless paste-back possible later. If you feed it zero faces, it gracefully returns empty tensors instead of erroring, so it's safe to wire into a batch that might not always contain a face.
Wiring it in
The shape of the workflow is: Load Image → DetectFaces → CropFaces → your refine step on crops → WarpFacesBack → Save Image. The refine step is where you get to be opinionated. People pair this with a LoRA on the face region, an inpainting pass, or IPAdapter-style reference conditioning - anything that benefits from working on an upright, high-resolution face instead of a 60px blob in a 1024 frame.
Gotchas
crop_sizeandcrop_factorare the first dials to touch when a result looks off. A crop that's too tight gives the inpaint model no context; too loose and the face is small again.convex_hullneeds MediaPipe. The pack's README has a deprecated note about installingcomfyui_controlnet_auxfor it, but the current code imports mediapipe directly - just make sure it's in your environment.- The masks come out at crop resolution, matching the crops. Keep them in lockstep or the paste-back will misalign.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/dchatel/comfyui_facetools
or search facetools in ComfyUI Manager, then restart. The parsing mask types additionally want the BiSeNet weights in ComfyUI/models/bisenet/ (see the BiSeNetMask article). Everything else the pipeline needs - the YOLO detector, the landmark model, and the ultralytics/onnxruntime/mediapipe packages - is shared with DetectFaces.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| faces | FACE | — | |
| crop_size | INT | 512512–1024 | — |
| crop_factor | FLOAT | 1.51–3 | — |
| mask_type | COMBO | 4 options: simple_square, convex_hull, BiSeNet, jonathandinu |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| crops | IMAGE | — |
| masks | MASK | — |
| warps | WARP | — |