OpenPose - Get direction
Which way is your subject facing? Read it straight off the pose keypoints
- pose_kps
- direction
- direction_code
If you've ever needed to know whether the person in your image is facing the camera or showing a profile - for a batch of reference poses, or to flip a ControlNet condition - you'd normally eyeball it. This node does it automatically. Feed it the POSE_KEYPOINT data your pose preprocessor already produced, and it hands back a direction string ("forward", "left", "right") plus a direction_code integer (0, 1, 2).
It's the one trick of a tiny pack (ComfyUI-PoseDirection) by Alessandro Zonta. There's no model here, no API call, no heavy dependency - it's pure geometry over keypoints, so it runs in a blink and costs you nothing at queue time. That's the whole appeal: a cheap, deterministic answer to a question you'd otherwise answer by hand or with a prompt hack.
How it actually works (the README fibs a little)
The README says the node uses body keypoints - shoulders and nose. It doesn't. I read the source, and the body is ignored entirely; only face landmarks are touched. The DWPose keypoint dict carries face_keypoints_2d (68 points, each with x/y/confidence), and that's the entire input this node reads.
Mechanically it's a symmetry test. It averages the x-positions of the left and right eyes, mouth corners, jaw points, and eyebrow groups, then measures three things: how symmetric the face is around the nose, how aligned the feature midpoints are, and how far the nose tip sits from the face center (normalized by feature distance). If all three land under hand-tuned thresholds (0.15, 0.12, and 0.18), the face is roughly frontal → "forward". Otherwise the nose's offset decides: nose right of the face center in image space → "right", nose left → "left".
Those thresholds were tuned against the author's example images, so treat this as a heuristic, not a learned classifier. Clean frontal and three-quarter shots are its home turf; extreme angles, heavy occlusion, or a hand over the face will confuse it.
One quirk: IS_CHANGED returns NaN, so the node re-evaluates on every change. Since it's pure arithmetic that's harmless - it just means you'll always see it run in the queue.
The inputs and outputs that matter
The full input list is exactly one slot: pose_kps (type POSE_KEYPOINT), in the DWPose/OpenPose format - a list of people, each with a face_keypoints_2d array. If that's missing, or there are fewer than four face points, the node answers ("missing keypoints", -1) instead of a direction.
Outputs:
- direction (STRING):
"forward","left", or"right"(or"missing keypoints") - direction_code (INT):
0,1, or2(or-1)
The string is readable for branching; the int is easier for comparisons. Both wire nicely into a switch or condition node - say, a filter that only lets forward-facing frames through a character-consistency pass.
Installing and wiring it
Installation is trivial:
cd ComfyUI/custom_nodes
git clone https://github.com/alessandrozonta/ComfyUI-PoseDirection
Then restart ComfyUI - or just search "ComfyUI-PoseDirection" in ComfyUI Manager. There's no requirements.txt and no model to download. The hidden dependency is upstream: you need a node that emits POSE_KEYPOINT, which in practice means DWPreprocessor from ComfyUI_ControlNet_Aux (the pack's own sample workflow ships with one, running the dw-ll_ucoco_384 model).
That's where the first gotcha lives. On DWPreprocessor, detect_face must be set to "enable", or you'll get no face keypoints and this node will answer "missing keypoints" forever. Second gotcha: it only looks at the first person in the frame (pose_kps[0]) - no batch analysis. Third: left/right are decided in image coordinates, so if your notion of "showing their left side" is from the subject's perspective, sanity-check the output on your own images once before trusting it in an automated pipeline.
Verdict
For a utility node it's a clean little thing: zero deps, instant, deterministic. It won't replace a pose classifier for hard cases, but for "does my batch of references face the camera" it saves you from squinting at a thousand thumbnails. Pair it with DWPreprocessor and a switch node and you've got an automatic face-the-camera filter.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| pose_kps | POSE_KEYPOINT | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| direction | STRING | — |
| direction_code | INT | — |