Nodes/ComfyUI-PoseKeypointsToImage/Pose Keypoints → Image
ComfyUI Node

Pose Keypoints → Image

The node that shows you what DWPose actually saw

By smartvain·Created 8 months ago·Updated 8 months ago· 0
Pose Keypoints → Image
  • pose_kps
  • image
width512
height512
point_radius2
draw_bodytrue
draw_facetrue
draw_handstrue

Pose Keypoints → Image is a tiny utility that takes the POSE_KEYPOINT data DWPose (or OpenPose) produces and renders it back into an actual IMAGE tensor. You don't need it to use pose ControlNet - the preprocessor already gives you a rendered skeleton for that. You reach for this when you want to see what was actually detected, as data, instead of trusting the pretty render.

The author's own use case is the giveaway. The README pairs this node with FaceKeypointsFilter (same author, different pack): you filter some face keypoints out of the JSON, then render the filtered pose_kps to confirm the parts you wanted gone are gone. It's a debugging and inspection tool - and a genuinely useful one, because pose is where ControlNet's "where things go" signal comes from, and if that signal is wrong your whole composition is wrong. Being able to eyeball the raw keypoints before they hit the ControlNet is the difference between "why are the hands weird" and "oh, DWPose only found two hand points."

How it works

The node is refreshingly honest about its scope. It expects the DWPose/OpenPose JSON layout: a dict (or list of frame dicts) where each person carries pose_keypoints_2d, face_keypoints_2d, hand_left_keypoints_2d and hand_right_keypoints_2d - flat [x, y, score] triplets. For each point it checks that the score is above zero (skipping anything low-confidence or NaN), then draws a white circle on a black canvas. Multiple people? It walks the people list and draws them all. Multiple frames? They get stacked into a batch tensor, so video-style batches pass through fine.

Here's the catch nobody warns you about: it draws dots, not a stick figure. No lines connecting joints, no OpenPose colors. The output is a point cloud on black - great for checking keypoint positions, but it is not the classic pose render that pose ControlNets were trained on. If you feed this directly into a ControlNet expecting openpose conditioning, results will be hit or miss. Think of it as a scope, not a replacement for the preprocessor's rendered output.

Another quirk, straight from the source: if the first frame has canvas_width/canvas_height in its JSON, those override your width/height inputs. You can set 512×512 and still get whatever resolution the detector recorded.

The inputs that matter

  • pose_kps (required) - the POSE_KEYPOINT data. This is the only non-obvious one.
  • width / height - output canvas, 512 default, 8-step, 64–4096. Subject to the canvas override above.
  • point_radius - dot size, 2 default, 1–10. Bump it up if your dots vanish at high resolution.
  • draw_body / draw_face / draw_hands - all default to on; flip one off to render a part selectively.

Output: a single image (IMAGE), which you can feed to a Preview Image or Save Image node. That's it - no optional inputs, no model, no frills.

Installing it

Via ComfyUI Manager, search PoseKeypointsToImage and install. Manual route:

cd ComfyUI/custom_nodes
git clone https://github.com/smartvain/ComfyUI-PoseKeypointsToImage.git

Then restart ComfyUI. No requirements.txt, no pip install, no model downloads - it only uses numpy, Pillow and torch, all already in ComfyUI. MIT licensed, and at ~200 lines of actual code it's one of the easier packs to read if you want to trust your custom nodes.

Where people get burned

The big one is wiring it up. In the version of comfyui_controlnet_aux on disk here, the DWPose Preprocessor only returns an IMAGE - the JSON goes to its UI display, not out a port. So you can't just drag the preprocessor's image output into pose_kps; that's a type error. You need a node that actually emits POSE_KEYPOINT - the README's example is FaceKeypointsFilter, which outputs filtered pose_kps precisely for this node. If you don't have a filter step, check whether your preprocessor build exposes a POSE_KEYPOINT output; if not, this node sits awkwardly alone.

Second gotcha: a black, empty image out. That usually means no person was detected (every score came back at zero), or the input wasn't the expected dict/list format. The node returns a blank canvas rather than throwing - silent failure, easy to miss.

Third: don't treat the dot map as a ControlNet condition out of the box. It's for inspection and debugging. That's its job, and it's a good one.

CategoryPose/Face Utils

Inputs (7)

NameTypeDefaultDescription
pose_kpsPOSE_KEYPOINT
widthINT51264–4096
heightINT51264–4096
point_radiusINT21–10
draw_bodyBOOLEANtrue
draw_faceBOOLEANtrue
draw_handsBOOLEANtrue

Outputs (1)

NameTypeDescription
imageIMAGE