Nodes/ComfyUI-UtilsCollection/AnimalPose Estimator (AP10K)
ComfyUI Node

AnimalPose Estimator (AP10K)

Pose Control for Your Dog, Cat, or Horse (Yes, Really)

By silveroxides·Created 3 months ago·Updated about 12 hours ago· 35
AnimalPose Estimator (AP10K)
  • image
  • image
  • pose_keypoint
resolution0
batch_size5
detection_threshold0.30
keypoint_threshold0.30
nms_threshold0.45
temporal_filterfalse
temporal_radius2
temporal_min_support2
temporal_max_distance0.10
temporal_match_iou0.30

Human pose estimation has an embarrassment of riches; animals get scraps. If you want a horse mid-gallop or a dog shaking off water to keep its actual posture, the usual answer is "crop it, describe it, and hope." UC_AnimalPoseEstimator is one of the few ComfyUI-friendly ways to pull a real 17-joint skeleton off an animal and hand it to a pose ControlNet.

The name is the display name - "AnimalPose Estimator (AP10K)" - and the class is UC_AnimalPoseEstimator, from silveroxides' ComfyUI-UtilsCollection.

What it detects

The detector is the same YOLOX-L detector used by the pack's DWPose node, but filtered to COCO animal classes 14–23: bird, cat, dog, horse, sheep, cow, elephant, bear, zebra, giraffe. Each detected box gets cropped and run through the RTMPose AP10K model at 256 square, which returns 17 joints per animal. That's the Animal-Pose-10K layout - a four-legged animal skeleton, not a human one.

That last point is the whole game. pose_keypoint here is not OpenPose human keypoints, and the pack's own overlay node will refuse it outright (it raises an error on animal documents, because the joint indices mean something completely different). Feed the map into a ControlNet trained on animal pose, or paint a prompt around it - don't hand it to a human-pose model and wonder why the dog has a person's shoulders.

The inputs you'll actually set

image is the batch. For a video, frames in order - and the temporal filtering options assume exactly that.

resolution is 0 by default, meaning keep the input as-is; a positive number sets the output's shortest edge while preserving aspect ratio. Note the model's own input stays fixed at 256, so upscaling the input gives you a bigger canvas and smaller relative animals, not more detail - useful when you want the map at the resolution your ControlNet expects.

batch_size (5) covers both frames and animal crops per network call. Lower it if VRAM complains; it doesn't affect the temporal window.

detection_threshold (0.3) keeps or rejects animal detections, keypoint_threshold (0.3) decides which joints survive - lower than the human nodes' 0.45, which tells you something about how confident the AP10K model tends to be. nms_threshold (0.45) cleans duplicate boxes; drop it and you lose the second dog in the frame, raise it and you'll get one dog twice.

Then temporal_filter plus temporal_radius (2), temporal_min_support (2), temporal_max_distance (0.1 - 10% of the animal's box diagonal) and temporal_match_iou (0.3). It prunes joints that nearby frames can't confirm from both the drawing and the keypoint records, keeps the animal entries, and never interpolates. For a running dog, 0.1 of the box diagonal is tight - raise it before you conclude the filter is broken. Off by default, and it should stay off for a folder of unrelated photos.

Outputs

Two, and only two: image (the drawn animal skeletons in frame order) and pose_keypoint (per-frame AP10K joints with pixel coordinates and confidence, after thresholding and filtering). There's no overlay mask on this node, unlike the pack's human estimators - if you want the mask, run the map through ImageToMask or use UC_OverlayPoseKeypoints, which handles human keypoints only.

Install

Manager → search "ComfyUI-UtilsCollection", or:

cd ComfyUI/custom_nodes
git clone https://github.com/silveroxides/ComfyUI-UtilsCollection
# restart ComfyUI

It needs two checkpoints, downloaded on first execution into ComfyUI/models/controlnet/preprocessors: dwpose_yolox_l.safetensors (shared with the DWPose node) and animalpose_ap10k_256.safetensors, both from silveroxides/ComfyUI-UtilsCollection-Models (HF paths detectors/ and preprocessors/animalpose/). No model weights ship with the repo. If you're offline, pre-place both files in that folder - the loader reuses local copies and only reaches out when one is missing.

Worth repeating the author's own caveat: the ports are verified for conversion correctness - keys, shapes, dtypes, values - while numerical parity and speed are not. A hand-ported AP10K model can be structurally perfect and still put a joint an inch off where the reference implementation put it. Check the first frame before you queue 300.

Troubleshooting

kornia is imported at pack load and isn't declared in requirements.txt. If it isn't already in your environment from another pack, the entire collection fails to import - a one-line pip install kornia fixes it.

Zoo footage with multiple overlapping animals is the case this struggles with, and it's structural: one box per animal, NMS at 0.45, and a temporal filter that matches boxes at IoU 0.3. Two giraffes crossing will swap identities no matter what you set. If identity stability matters, raise temporal_match_iou.

Categoryimage/pose

Inputs (11)

NameTypeDefaultDescription
imageIMAGEImage or image batch containing animals. Detector categories: bird, cat, dog, horse, sheep, cow, elephant, bear, zebra and giraffe. For temporal filtering, supply consecutive video frames in order.
resolutionINT00–40960 preserves the input dimensions. A positive value sets the output's shortest edge in pixels, preserving aspect ratio. Larger maps do not increase the model's fixed input size.
batch_sizeINT51–64Maximum images or animal crops processed together. Higher values may improve throughput but use more memory; lower if VRAM runs out. Does not change temporal-filter range.
detection_thresholdFLOAT0.300–1Minimum confidence for keeping an animal detection. Raise to reject false animals; lower to recover weak detections at the risk of false positives.
keypoint_thresholdFLOAT0.300–1Minimum confidence for each animal joint. Raise to remove uncertain joints from the drawing and keypoint output; lower to retain more of the skeleton.
nms_thresholdFLOAT0.450–1Overlap limit for removing duplicate animal boxes. Lower removes more overlapping detections but can lose nearby animals; higher keeps more and may leave duplicates.
temporal_filterBOOLEANfalseVideo frames only: remove joints unsupported by nearby frames from both pose maps and keypoints. Keeps animal entries; does not smooth or fill missing joints. Leave off for unrelated images.
temporal_radiusINT21–30Temporal filter only: frames to inspect before and after each frame. 2 checks up to four neighbors, across batch_size chunks. Larger windows cost more and may reject fast motion.
temporal_min_supportINT21–60Temporal filter only: neighboring frames that must confirm a joint. Raise to remove more flicker; lower to retain brief poses. Limited to available neighbors, including at clip edges.
temporal_max_distanceFLOAT0.100.001–1Temporal filter only: allowed joint displacement relative to the animal's box diagonal; 0.1 means 10%. Raise for faster motion; lower to reject sudden jumps.
temporal_match_iouFLOAT0.300–1Temporal filter only: required overlap between detection boxes to match an animal across frames. Raise to avoid mixing animals; lower for faster movement or changing boxes.

Outputs (2)

NameTypeDescription
imageIMAGEAnimal skeleton maps in input-frame order.
pose_keypointPOSE_KEYPOINTPer-frame AP10K animal keypoints: 17 joints with pixel coordinates and confidence, after thresholding and optional temporal filtering. Not the human OpenPose joint layout.