Face Body Aspect Bounds
The Crop That Keeps the Face
- body_x
- body_y
- body_width
- body_height
- face_x
- face_y
- face_width
- face_height
- face_x_body_rel
- face_y_body_rel
The classic failure in portrait generation isn't the model - it's the crop. You resize a body-region crop to a target aspect ratio, and the head gets sliced off, or the composition is awkward because the box recentered on something that isn't the face. Face Body Aspect Bounds is purpose-built for that: you give it a body bounding box and a face box inside it, and it resizes the body box to your aspect ratio while guaranteeing the face stays inside and preserving the face's original relative position. This is the node that makes "crop the person, keep the head" a solved problem.
How it works
You provide two boxes and one target:
- Body box:
body_x,body_y,body_width,body_height. - Face box:
face_x,face_y,face_width,face_height- given relative to the body box's top-left corner. aspect_ratio: the width/height you want the output body box to have (default 1.0).
The outputs hand back both boxes, recomputed: body_x, body_y, body_width, body_height and face_x, face_y, face_width, face_height - the latter re-expressed relative to the new body box, so downstream code that assumes face-coords-are-body-relative stays correct.
The core mechanism is the neat part. First it computes the face's position as a fraction of the body box - frac_x, frac_y - rather than assuming the face is dead-center. Then it works out the smallest aspect-correct body size that can still fully contain the face, and (by default) fits the body box down toward that snug size - never larger than the original body box. The body box is then repositioned so the face keeps the same relative spot it had before, with corrections to make sure the face is fully inside. The result: a tighter, aspect-correct body crop where the head lands where it should, headroom included.
A detail worth noting: the node picks the "body direction" from the body box's own shape - a box taller than wide means the body extends vertically, and the face-keeping logic orients accordingly. Near-square boxes default to upright, since that's the common case. So this node is less naive than it first appears about how a person is oriented.
Where you'd actually use it
- Face-detector → crop pipelines: feed boxes from a face detector (Florence2-style caption parsing or an object detector) into this, then use the resulting box to crop or inpaint the body region.
- Portrait reframing: normalize a person-crop to a consistent aspect for a batch.
- Composition control: keep natural headroom instead of hard-centering the face.
Installing it
Part of ComfyUI-TinyBee under 🐝TinyBee/Util:
- ComfyUI Manager → Install Custom Nodes → search "ComfyUI-TinyBee" → Install, then restart ComfyUI.
cd ComfyUI/custom_nodes
git clone https://github.com/TinyBeeman/ComfyUI-TinyBee
Restart. No models; it's pure coordinate math, so none of the pack's requirements.txt entries (pillow, jsonata) come into play.
Gotchas
The face box must be relative to the body box, which trips people up the first time - if your detector gives you absolute coordinates, subtract the body origin first. The default behavior also shrinks the body toward the face rather than growing outward, so if your face and body boxes are imprecise, you may get a crop that's snugger than you wanted. And remember the output face box is relative to the new body box - that's consistent with the input convention, but it means the absolute face position shifted along with the body. Feed it sane boxes and this node quietly turns a fiddly geometry problem into a single node.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| face_x | INT | 0-10000–10000 | — |
| face_y | INT | 0-10000–10000 | — |
| face_width | INT | 1281–10000 | — |
| face_height | INT | 1281–10000 | — |
| body_x | INT | 0-10000–10000 | — |
| body_y | INT | 0-10000–10000 | — |
| body_width | INT | 2561–10000 | — |
| body_height | INT | 5121–10000 | — |
| aspect_ratio | FLOAT | 1.000.01–100 | — |
| exceedBounds | BOOLEAN | false | — |
| ensureUpperBodyPct | FLOAT | 0.000–10 | — |
| image_width | INT | 5121–10000 | — |
| image_height | INT | 5121–10000 | — |
Outputs (10)
| Name | Type | Description |
|---|---|---|
| body_x | INT | — |
| body_y | INT | — |
| body_width | INT | — |
| body_height | INT | — |
| face_x | INT | — |
| face_y | INT | — |
| face_width | INT | — |
| face_height | INT | — |
| face_x_body_rel | INT | — |
| face_y_body_rel | INT | — |