Openpose Render Node
The 'ultimate' OpenPose renderer that detects nothing — and why that's the point
- POSE_KEYPOINT
- IMAGE
If you've ever run a DWPose or OpenPose preprocessor and wished you could do something with the stick figure besides take it as-is - draw only the body, drop the hands, make it bigger - this is the node for you. Openpose Render Node takes pose keypoints or classic OpenPose JSON and redraws them onto a clean black canvas, outputting an IMAGE ready to feed a ControlNet.
The name is doing some lifting. "Ultimate" suggests a detector, but it's a pure renderer: no pose models, no weights, no API, nothing to download. You hand it pose data, it draws the skeleton you already have. Detection happens upstream, in the ControlNet Auxiliary Preprocessors' DWPose/OpenPose nodes.
Honest take: if your whole pipeline is image → DWPose preprocessor → ControlNet, you don't strictly need this - the preprocessor already outputs a rendered pose map. This node earns its place when you want control over that render: body-only conditioning (hand keypoints are notorious for steering a model toward weird fingers), a specific output width to match your latent size, or pose data that never existed as an image - pasted OpenPose JSON, exported pose files, or output from the author's sibling project, the interactive ComfyUI-ultimate-openpose-editor. And because it loops over every frame in the pose data, a pose sequence becomes a batch of skeletons for per-frame ControlNet work in animation.
How it works
Two pose inputs, and only one matters at a time. POSE_KEYPOINT takes the wire type straight off a ControlNet Aux preprocessor (its second output); POSE_JSON is the same data as multiline text. Priority is explicit: POSE_KEYPOINT wins if both are connected - the README calls it out, and the code backs it up.
Both inputs end up parsed as the classic OpenPose JSON schema: a list of frames, each with people, canvas_width, and canvas_height, where each person carries pose_keypoints_2d, face_keypoints_2d, hand_left_keypoints_2d, and hand_right_keypoints_2d as x/y/confidence triplets. That's exactly what ControlNet Aux's modern DWPose emits - its UI even prints an openpose_json blob you can copy straight into POSE_JSON.
The drawing is the OpenPose look you already know: rainbow-colored limb sticks and joint dots for the body (18 keypoints), HSV-tinted lines with red joints for hands, white dots for the face, all on a black canvas via OpenCV. Coordinates auto-normalize - if keypoints peak above 2.0 they're treated as pixel coords and divided by width/height, otherwise assumed 0–1. A single dict gets auto-wrapped into a list.
The inputs that matter
- POSE_KEYPOINT - the wire from a ControlNet Aux DWPose/OpenPose preprocessor, or from a pose editor.
- POSE_JSON - same data as text, when you don't have the wire.
- show_body / show_face / show_hands - toggle what gets rendered, all
trueby default. - resolution_x - output width; height follows the source aspect ratio. Default
-1(anything under 64) means "keep the original canvas width." - pose_marker_size / face_marker_size / hand_marker_size - stick and dot thickness, defaults 4/3/2.
Output: a single IMAGE tensor (floats 0–1). Wire it into a ControlNet node with an openpose-family model (match dw_openpose to a DWPose source, openpose to an OpenPose source), then on to your KSampler. Or just drop a PreviewImage on it and look at what the ControlNet is actually being fed - usually the most instructive thing you can do.
Install
Easiest via ComfyUI Manager (search "ultimate-openpose"), or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/westNeighbor/ComfyUI-ultimate-openpose-render
cd ComfyUI-ultimate-openpose-render
pip install -r requirements.txt
Portable installs use the embedded interpreter, e.g. E:/ComfyUI_windows_portable/python_embeded/python.exe -m pip install -r requirements.txt. Then restart ComfyUI and find it under Right-click → ultimate-openpose → Openpose Render Node. No model downloads. One quirk: requirements.txt lists polygraphy, an NVIDIA tool the node never imports - harmless bloat, ignore it.
Common issues
- Feed it a photo and it errors. It renders, it doesn't detect. Detection is the preprocessor's job upstream. If neither input has usable data - no keypoint wire, empty JSON - you get
ValueError: Invalid input type. Expected an input to give an output.That's the node's actual error, and it's telling you the truth. - You edited POSE_JSON but nothing changed. Check whether a
POSE_KEYPOINTwire is still connected - it silently overrides the text field. - Empty or malformed JSON renders nothing. It must be the OpenPose
peopleschema withcanvas_width/canvas_height; arbitrary detector dumps without apeoplekey come back empty. - Hands/face toggles do nothing. The node can only render keypoints the preprocessor actually detected - DWPose's
detect_hand/detect_faceoptions gate what's in the data in the first place.
Small, dependency-light, one job done well. Not the flashiest node in the graph - just the one that turns pose data into exactly the control signal you meant to send.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| show_bodyopt | BOOLEAN | true | — |
| show_faceopt | BOOLEAN | true | — |
| show_handsopt | BOOLEAN | true | — |
| resolution_xopt | INT | -1-1–12800 | — |
| pose_marker_sizeopt | INT | 40–100 | — |
| face_marker_sizeopt | INT | 30–100 | — |
| hand_marker_sizeopt | INT | 20–100 | — |
| POSE_JSONopt | STRING | — | |
| POSE_KEYPOINTopt | POSE_KEYPOINT | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |