Skip to content

Pose Detector

Finds a person's body and returns 33 landmarks, from the face down to the feet.

Body landmarks drawn on a person running

Basic use

import cv2 as cv
from detectors_world import create_detector

cap = cv.VideoCapture(0)

with create_detector("pose") as pose:
    while True:
        ok, frame = cap.read()
        if not ok:
            break

        bodies = pose.detect(frame)
        if bodies:
            print("Left shoulder:", bodies[0][11])

        cv.imshow("Pose Detection", frame)
        if cv.waitKey(1) & 0xFF == ord("q"):
            break

cap.release()
cv.destroyAllWindows()

Options

Option Default Meaning
model "full" Which model to use, see below
max_poses 1 Largest number of people to look for
detection_confidence 0.5 Minimum confidence to report a new body
tracking_confidence 0.5 Minimum confidence to keep following a body between frames
static_image False Set to True for unrelated photos
model_path None Use your own copy of the model file

Choosing a model

Model Download Use it when
"lite" 5.8 MB Speed matters most, such as on small devices
"full" 9.4 MB You want a balance of speed and accuracy
"heavy" 30.7 MB Accuracy matters most
pose = create_detector("pose", model="lite")

Landmark map

Each body has 33 landmarks. "Left" and "right" are the person's own sides, so in a photo of someone facing you, their left side is on your right. Odd numbers are on the left side of the body, and even numbers on the right.

Map of the 33 pose landmarks

Id Name Description
0 NOSE Nose
1 LEFT_EYE_INNER Left eye inner
2 LEFT_EYE Left eye
3 LEFT_EYE_OUTER Left eye outer
4 RIGHT_EYE_INNER Right eye inner
5 RIGHT_EYE Right eye
6 RIGHT_EYE_OUTER Right eye outer
7 LEFT_EAR Left ear
8 RIGHT_EAR Right ear
9 MOUTH_LEFT Mouth left
10 MOUTH_RIGHT Mouth right
11 LEFT_SHOULDER Left shoulder
12 RIGHT_SHOULDER Right shoulder
13 LEFT_ELBOW Left elbow
14 RIGHT_ELBOW Right elbow
15 LEFT_WRIST Left wrist
16 RIGHT_WRIST Right wrist
17 LEFT_PINKY Left pinky
18 RIGHT_PINKY Right pinky
19 LEFT_INDEX Left index
20 RIGHT_INDEX Right index
21 LEFT_THUMB Left thumb
22 RIGHT_THUMB Right thumb
23 LEFT_HIP Left hip
24 RIGHT_HIP Right hip
25 LEFT_KNEE Left knee
26 RIGHT_KNEE Right knee
27 LEFT_ANKLE Left ankle
28 RIGHT_ANKLE Right ankle
29 LEFT_HEEL Left heel
30 RIGHT_HEEL Right heel
31 LEFT_FOOT_INDEX Left foot index
32 RIGHT_FOOT_INDEX Right foot index

Results

pose.detect(frame) returns a list of Landmarks, one per body:

bodies = pose.detect(frame)

if bodies:
    body = bodies[0]
    body.points       # 33 (x, y) pixel positions
    body.normalized   # 33 (x, y, z) values
    body[0]           # the nose, as (x, y)

label and score are None for bodies.

Landmarks are estimated even for parts out of view, so a position can be off-screen or approximate when a person is only partly visible.

Finding landmarks with locate()

pose.locate() returns one body as [[id, x, y], ...], and draws a dot on each landmark:

pose.detect(frame)
landmarks = pose.locate(frame, pose=0)
Argument Default Meaning
pose 0 Which body to return, counting from 0
draw True Draw a dot on each landmark
color (0, 255, 0) Dot color as (blue, green, red)
radius 6 Dot radius in pixels

It returns [] if that body isn't visible.

Recipes

Measure a joint angle

An angle comes from three landmarks, such as shoulder, elbow and wrist:

import math

def angle(a, b, c):
    first = math.atan2(a[1] - b[1], a[0] - b[0])
    second = math.atan2(c[1] - b[1], c[0] - b[0])
    degrees = abs(math.degrees(first - second))
    return 360 - degrees if degrees > 180 else degrees

left_elbow = angle(body[11], body[13], body[15])

The Exercise Counter uses this to count repetitions.

Are the hands above the head?

A smaller y is higher in the image:

hands_up = body[15][1] < body[0][1] and body[16][1] < body[0][1]