Nodes/Castcut nodes/Castcut Pose Score
ComfyUI Node

Castcut Pose Score

How close is this take to your guide pose?

By doodersrage·Created 21 days ago·Updated 14 days ago· 2
Castcut Pose Score
  • pose_keypoint
  • scores_json
  • first_score
◄guide_json►
◄methodlimb-angle►

Pose control either works or it half-works, and the half is the annoying case: the figure is broadly right, one arm is 30 degrees off, and the whole still reads as wrong. Eyeballing fifty takes to find the two closest to your reference is a bad afternoon. Castcut Pose Score does that comparison mechanically - DWPose keypoints in, a score per image out.

DWPose over OpenPose is the right call here: it's the improved detector the community reaches for precisely because hands and occlusion are where the older one falls apart, and hands are usually where pose fidelity is visible.

What it's comparing against, and how

The node takes two things: a POSE_KEYPOINT batch from DWPose, and a guide_json string. The guide is Castcut's own format - a JSON object with a guide list (one entry per person, 18 keypoints each as {"x": ..., "y": ...} or null for a joint you don't know, normalised 0–1) plus the aspect (width ÷ height) the guide was authored at. Nulls are legal and meaningful: an unknown joint stays unknown rather than being invented.

Then it does a surprising amount of work for one node:

  • It classifies each body's posture (standing, sitting, kneeling, crouching, all-fours, bending, lying on back/side/front) from the keypoints and the frame aspect, and compares guide posture against detected posture.
  • It scores limb angles - 12 scored segments, each weighted by how defining that limb is for the guide pose.
  • It tries the candidate both mirrored and left/right swapped, keeping the best result but charging a penalty for mirroring proportional to how asymmetric the guide pose is.
  • With up to three guide people and the three most prominent detected people, it brute-forces the assignment - every permutation, highest total wins - so it doesn't just match person 1 to person 1.
  • Posture mismatches beat everything else: they cap the score at 0.4. Agree on posture and the score lives in the 0.5–1.0 band, scaled by limb accuracy.

The alternative method value, joint-distance, drops limb angles and returns a plain joint-position similarity instead - each shared joint's distance from the guide measured in torso lengths and averaged. No posture cap, no floor; it just reports how close the joints landed. Limb-angle is the default, and the one Castcut scores with.

Inputs and outputs

Required: pose_keypoint (wire it from a DWPose node in comfyui_controlnet_aux) and guide_json. Optional: method.

Outputs are scores_json - {"version": ..., "results": [...]} where each entry is a per-image result (or null for an image where no pose was detected) and each result carries camelCase fields the app reads: score, jointScore, limbScore, gestureMiss, expectedPeople, detectedPeople, extraPeople, perPerson, assignment, posture (with mismatch/unsure), postureMiss, postureUnsure, offLimbs and limbDeltas - plus first_score, the first non-null score as a FLOAT, or 0.0 if nothing was detected at all.

The obvious wiring is straight into Castcut Pick Best's scores_json, which is the "best of two for hard poses" pipeline the pack exists for. first_score is useful on its own as a threshold input for a switch or a note.

Two caveats. It scores pose, not likeness - a well-posed wrong person scores well. And the guide has to exist: without the Castcut app to export it, you're authoring that JSON by hand, and a malformed one errors with Castcut guide must be a JSON object with guide and aspect.

Installing it

One pack, one file. Manager → search Castcut nodes, or comfy node install castcut-nodes, or the manual route and a restart:

git clone https://github.com/doodersrage/castcut-nodes
cp castcut-nodes/castcut_nodes.py /path/to/ComfyUI/custom_nodes/

The pack needs only numpy and pillow on top of ComfyUI. Best-of-two needs one more thing: DWPose, which lives in comfyui_controlnet_aux. Verifying the install is quick - http://127.0.0.1:8188/object_info/CastcutPoseScore should return the node, and its description ends with [castcut-nodes 1.1.0], which is how the app reads the installed version. Install one way only: a castcut_nodes.py file next to a castcut folder both load.

Where people get burned

  • DWPose is the flaky part, not this node. The default controlnet_aux DWPose breaks on updates often enough to have a standing thread about it, and the usual symptom is the ONNX "will run slow" warning because onnxruntime is the CPU build. Uninstalling it for onnxruntime-gpu silences the warning and, for plenty of people, breaks DWPose entirely. If you go looking for the faster TensorRT replacement, know it exports images only - no keypoints, so it can't feed this node.
  • Nulls in results are normal. It's a batch; images with nobody in frame come back null and are skipped by first_score.
  • Mirroring is allowed, so it won't catch a flipped pose. That's deliberate, but it means a left-arm/right-arm swap can still score well if the guide is roughly symmetric.
CategoryCastcut

Inputs (3)

NameTypeDefaultDescription
pose_keypointPOSE_KEYPOINT—
guide_jsonSTRING—
methodoptCOMBOlimb-angle2 options: limb-angle, joint-distance

Outputs (2)

NameTypeDescription
scores_jsonSTRING—
first_scoreFLOAT—