CMU-Perceptual-Computing-Lab/openpose

How to draw Skeleton Frame from JSON using python?

saisriteja opened this issue · 2 comments

I have a JSON output from openpose output, but I wanted to tweak a few things inside the JSON and redraw the skeleton from the modified JSON. The skeleton has to look the same as from the coco25 format given by the openpose. I don't have knowledge of CPP so I go stuck. Is there any python script to draw the skeleton(body+face+hands) just from JSON?

I am not sure if there is a ready-made python script available right now. However, you can use OpenCV in Python to draw over an image. Please check the following link for more info.

https://docs.opencv.org/4.x/dc/da5/tutorial_py_drawing_functions.html

How about something like this? The code below expects the pose keypoints to be input as a numpy array shaped like (num_people, 25, 3), which is how the pyopenpose Python API outputs detections directly. You'll have to modify things slightly to get your JSON pose files into numpy format, but that should be easy to do.

def show_image(img: np.ndarray):
    fig, ax = plt.subplots(figsize=(12, 8))
    ax.imshow(img)
    ax.grid('off')
    ax.axis('off')
    plt.savefig('poses_0001.png')
    plt.show()
    plt.close()


JOINT_PAIRS_MAP_ALL = {(0, 15): {'joint_names': ('Nose', 'REye')},
                       (0, 16): {'joint_names': ('Nose', 'LEye')},
                       (1, 0): {'joint_names': ('Neck', 'Nose')},
                       (1, 2): {'joint_names': ('Neck', 'RShoulder')},
                       (1, 5): {'joint_names': ('Neck', 'LShoulder')},
                       (1, 8): {'joint_names': ('Neck', 'MidHip')},
                       (2, 3): {'joint_names': ('RShoulder', 'RElbow')},
                       (2, 17): {'joint_names': ('RShoulder', 'REar')},
                       (3, 4): {'joint_names': ('RElbow', 'RWrist')},
                       (5, 6): {'joint_names': ('LShoulder', 'LElbow')},
                       (5, 18): {'joint_names': ('LShoulder', 'LEar')},
                       (6, 7): {'joint_names': ('LElbow', 'LWrist')},
                       (8, 9): {'joint_names': ('MidHip', 'RHip')},
                       (8, 12): {'joint_names': ('MidHip', 'LHip')},
                       (9, 10): {'joint_names': ('RHip', 'RKnee')},
                       (10, 11): {'joint_names': ('RKnee', 'RAnkle')},
                       (11, 22): {'joint_names': ('RAnkle', 'RBigToe')},
                       (11, 24): {'joint_names': ('RAnkle', 'RHeel')},
                       (12, 13): {'joint_names': ('LHip', 'LKnee')},
                       (13, 14): {'joint_names': ('LKnee', 'LAnkle')},
                       (14, 19): {'joint_names': ('LAnkle', 'LBigToe')},
                       (14, 21): {'joint_names': ('LAnkle', 'LHeel')},
                       (15, 17): {'joint_names': ('REye', 'REar')},
                       (16, 18): {'joint_names': ('LEye', 'LEar')},
                       (19, 20): {'joint_names': ('LBigToe', 'LSmallToe')},
                       (22, 23): {'joint_names': ('RBigToe', 'RSmallToe')}}


def draw_pose(img: np.ndarray, person_keypoints: np.ndarray):
    """ Draw pose skeleton on input image.

    Image should be an RGB image represented as a ndarray shaped like (H, W, 3)

    person_keypoints should be ndarray shaped like (25, 3).
    The row index is the joint number per the BODY_25 OpenPose format.
    The first and second column indices are the (x, y) coordinates of the joint, respectively
    The third column is the detection confidence for that joint.
    """
    pose_coords = person_keypoints[:, 0:2]
    confidences = person_keypoints[:, 2]
    for j1, j2 in JOINT_PAIRS_MAP_ALL.keys():
        x1, y1 = list(map(lambda v: int(round(v)), pose_coords[j1]))
        x2, y2 = list(map(lambda v: int(round(v)), pose_coords[j2]))
        c1, c2 = confidences[j1], confidences[j2]
        if c1 > 0.0:
            cv2.circle(img, (x1, y1), radius=4, color=(255, 128, 0), thickness=-1)
        if c2 > 0.0:
            cv2.circle(img, (x2, y2), radius=4, color=(255, 128, 0), thickness=-1)
        if c1 > 0.0 and c2 > 0.0:
            cv2.line(img, (x1, y1), (x2, y2), color=(0, 255, 128), thickness=2)
    return img


def draw_poses(img: np.ndarray, people_keypoints: np.ndarray):
    """ Wrapper around draw_pose to draw poses for multiple people.

    people_keypoints should be ndarray shaped like (num_people, 25, 3).

    """
    for i in range(people_keypoints.shape[0]):
        img = draw_pose(img, people_keypoints[i])
    return img


frame_clone = frame.copy()
draw_poses(frame_clone, pose_keypoints)
show_image(frame_clone)

poses_0001