Extensions/YOLO-Pose Keypoints
ComfyUI Extension

YOLO-Pose Keypoints

Generic YOLO-Pose keypoint detector: IMAGE - keypoints JSON (also to /history).

By solanex·Created 2 months ago·Updated 2 months ago· 0
solanex/comfyui-yolo-pose
Nodes
On cloudLocal install
Stars0
Updated2 months ago
Readme

ComfyUI — YOLO-Pose Keypoints

A single, product-agnostic ComfyUI node that runs an ultralytics YOLO-Pose model on an image and returns the detected keypoints as JSON. It is an OUTPUT_NODE, so the JSON is also surfaced to ComfyUI's /history (outputs[<node_id>].text[0]) — letting an external orchestrator read the keypoints over the HTTP API with no file sidecar (the same pattern ComfyUI graphs already use for previewing arbitrary values).

It deliberately knows nothing about what the keypoints mean. Pose semantics (what each keypoint index means, any 3D model, solvePnP, UV baking) belong in your downstream code, not in a render node.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/solanex/comfyui-yolo-pose
pip install -r comfyui-yolo-pose/requirements.txt   # ultralytics

Put your trained pose weights in ComfyUI/models/yolo_pose/ (created on first load). The node lists every .pt there in a dropdown. Weights are yours — they are not shipped with this node.

The node — "YOLO-Pose Keypoints" (category keypoints)

| Input | Type | Notes | |-------|------|-------| | image | IMAGE | single still (batch frame 0 is used) | | model_name | dropdown | a .pt in models/yolo_pose/ | | confidence | FLOAT | detection threshold (default 0.25) |

Output: keypoints_json (STRING) — and the same string in /history.

{
  "image_size": [1920, 1080],
  "model": "pose_model.pt",
  "instances": [
    {
      "box": [812.0, 396.0, 1958.0, 1820.0],
      "box_conf": 0.974,
      "keypoints": [[840.0, 412.0, 0.99], [1102.0, 508.0, 0.98], "..."]
    }
  ]
}

Keypoints are [x, y, confidence] in the input image's pixel coordinates, one list per detected instance. Instances are sorted best-first by box_conf.

Reading it from an orchestrator

hist = requests.get(f"{COMFYUI_URL}/history/{prompt_id}").json()
text = hist[prompt_id]["outputs"][NODE_ID]["text"][0]
kp = json.loads(text)["instances"][0]["keypoints"]   # pick/validate the right one

Then feed those 2D keypoints + your canonical 3D model to solvePnP and bake the UV map. (Multiple instances? Pick the one that matches your object — e.g. best overlap with a segmentation mask — rather than blindly taking index 0.)

License

MIT.