Detect Face Rotation for Inpainting 🧅
Fix a sideways head by rotating the problem
- image
- ROTATION_INV
- MASK
- ROTATION
Inpainting a face is easier when the face is upright. When someone's head is tilted - a person lying down, a photo shot at an angle - the standard "inpaint the face" trick fights the model: it doesn't know which way is up for that region, and you get mush. This node is the clever workaround: it detects the head's rotation from OpenPose keypoints and hands you the exact counter-rotation plus a circular face mask, so you can rotate the image straight, inpaint, and rotate it back.
How it works
It's the third node in the pack's keypoint pipeline, and it expects the output of OpenPoseToPointList with method set to all - that JSON list of named keypoints. The node averages the face landmarks (nose, eyes, ears) to find the face center, measures the distance from the face to the neck to size the region, and then estimates rotation from the nose-to-neck vector: if the neck is mostly below the nose, the head is roughly upright (0°); if the neck is off to one side, the head is tilted 90° or 270°.
It reports rotation in multiples of 90 degrees only - this is a coarse upright/landscape detector, not a fine angle. That matches how people actually use it: rotate the image 90° or 180°, inpaint the now-level face, rotate back.
The inputs and outputs that matter
parts- the JSON from OpenPoseToPointList (allmethod). This is the whole point of the chain.image- the image the mask will apply to.radius_scale(default 1.0) - how big the face mask is relative to the detected face size. Crank it up to include more context in the inpaint region.overwrite_rotation- force a rotation (None/0/90/180/270) if you don't trust the detection.- Outputs:
ROTATION(detected rotation, 0/90/180/270),ROTATION_INV(the counter-rotation to apply), andMASK(a circular blob sized and positioned for the rotated face).
The workflow is: rotate the image by ROTATION_INV, feed the MASK into the inpaint step on the rotated image, then rotate the result back by the inverse. The mask is already computed in the rotated frame, which is the subtle part that makes this node genuinely useful rather than annoying.
Where you'd use it
Portraits taken at odd angles, reference photos of people lying down, any inpaint job where a tilted face keeps coming out wrong. It's the kind of preprocessing that turns a frustrating failure into a routine fix. It pairs with classic masked inpainting - the exact technique the KB flags as still owning "only-masked detail" and "bit-identical unmasked pixels" - so this is a traditional-mask workflow, not an instruction-edit one.
Installing it
It's part of ComfyUI-NegiTools - ComfyUI Manager (search "ComfyUI-NegiTools") or:
cd ComfyUI/custom_nodes
git clone https://github.com/natto-maki/ComfyUI-NegiTools
pip install -r ComfyUI-NegiTools/requirements.txt
then restart. No API key. The upstream OpenPose node downloads pose weights on first use, which applies here since you need it to produce parts.
The honest caveats
This only detects 90° multiples, so a subtle 15° tilt won't be corrected - you'll get ROTATION 0 and a straight-ish mask. And the whole thing hinges on OpenPose detecting the face and neck reliably; on profile shots, heavy crops, or weird angles it can miss, in which case overwrite_rotation is your manual override. It's a specialized tool for a specific failure mode - but when that failure mode hits, it's exactly the node you wish you'd had. The three-node chain (OpenPose → this → inpaint) is a bit of setup for the payoff, so only reach for it when tilted faces are actually costing you.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| parts | STRING | — | |
| image | IMAGE | — | |
| radius_scale | FLOAT | 1.000.1–5 | — |
| overwrite_rotation | COMBO | 5 options: None, 0, 90, 180, 270 |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| ROTATION_INV | INT | — |
| MASK | MASK | — |
| ROTATION | INT | — |