mirror of
https://github.com/Wan-Video/Wan2.2.git
synced 2026-01-27 10:22:46 +03:00
* Add Wan-Animate Codes and examples * Update Wan-Animate Release date * clean codes and add copyright
1358 lines
43 KiB
Python
1358 lines
43 KiB
Python
# Copyright 2024-2025 The Alibaba Wan Team Authors. All rights reserved.
|
|
import os
|
|
import cv2
|
|
import time
|
|
import math
|
|
import matplotlib
|
|
import matplotlib.pyplot as plt
|
|
import numpy as np
|
|
from typing import Dict, List
|
|
import random
|
|
from pose2d_utils import AAPoseMeta
|
|
|
|
|
|
def draw_handpose(canvas, keypoints, hand_score_th=0.6):
|
|
"""
|
|
Draw keypoints and connections representing hand pose on a given canvas.
|
|
|
|
Args:
|
|
canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
|
|
keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
|
|
or None if no keypoints are present.
|
|
|
|
Returns:
|
|
np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
|
|
|
|
Note:
|
|
The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
|
|
"""
|
|
eps = 0.01
|
|
|
|
H, W, C = canvas.shape
|
|
stickwidth = max(int(min(H, W) / 200), 1)
|
|
|
|
edges = [
|
|
[0, 1],
|
|
[1, 2],
|
|
[2, 3],
|
|
[3, 4],
|
|
[0, 5],
|
|
[5, 6],
|
|
[6, 7],
|
|
[7, 8],
|
|
[0, 9],
|
|
[9, 10],
|
|
[10, 11],
|
|
[11, 12],
|
|
[0, 13],
|
|
[13, 14],
|
|
[14, 15],
|
|
[15, 16],
|
|
[0, 17],
|
|
[17, 18],
|
|
[18, 19],
|
|
[19, 20],
|
|
]
|
|
|
|
for ie, (e1, e2) in enumerate(edges):
|
|
k1 = keypoints[e1]
|
|
k2 = keypoints[e2]
|
|
if k1 is None or k2 is None:
|
|
continue
|
|
if k1[2] < hand_score_th or k2[2] < hand_score_th:
|
|
continue
|
|
|
|
x1 = int(k1[0])
|
|
y1 = int(k1[1])
|
|
x2 = int(k2[0])
|
|
y2 = int(k2[1])
|
|
if x1 > eps and y1 > eps and x2 > eps and y2 > eps:
|
|
cv2.line(
|
|
canvas,
|
|
(x1, y1),
|
|
(x2, y2),
|
|
matplotlib.colors.hsv_to_rgb([ie / float(len(edges)), 1.0, 1.0]) * 255,
|
|
thickness=stickwidth,
|
|
)
|
|
|
|
for keypoint in keypoints:
|
|
|
|
if keypoint is None:
|
|
continue
|
|
if keypoint[2] < hand_score_th:
|
|
continue
|
|
|
|
x, y = keypoint[0], keypoint[1]
|
|
x = int(x)
|
|
y = int(y)
|
|
if x > eps and y > eps:
|
|
cv2.circle(canvas, (x, y), stickwidth, (0, 0, 255), thickness=-1)
|
|
return canvas
|
|
|
|
|
|
def draw_handpose_new(canvas, keypoints, stickwidth_type='v2', hand_score_th=0.6):
|
|
"""
|
|
Draw keypoints and connections representing hand pose on a given canvas.
|
|
|
|
Args:
|
|
canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
|
|
keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
|
|
or None if no keypoints are present.
|
|
|
|
Returns:
|
|
np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
|
|
|
|
Note:
|
|
The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
|
|
"""
|
|
eps = 0.01
|
|
|
|
H, W, C = canvas.shape
|
|
if stickwidth_type == 'v1':
|
|
stickwidth = max(int(min(H, W) / 200), 1)
|
|
elif stickwidth_type == 'v2':
|
|
stickwidth = max(max(int(min(H, W) / 200) - 1, 1) // 2, 1)
|
|
|
|
edges = [
|
|
[0, 1],
|
|
[1, 2],
|
|
[2, 3],
|
|
[3, 4],
|
|
[0, 5],
|
|
[5, 6],
|
|
[6, 7],
|
|
[7, 8],
|
|
[0, 9],
|
|
[9, 10],
|
|
[10, 11],
|
|
[11, 12],
|
|
[0, 13],
|
|
[13, 14],
|
|
[14, 15],
|
|
[15, 16],
|
|
[0, 17],
|
|
[17, 18],
|
|
[18, 19],
|
|
[19, 20],
|
|
]
|
|
|
|
for ie, (e1, e2) in enumerate(edges):
|
|
k1 = keypoints[e1]
|
|
k2 = keypoints[e2]
|
|
if k1 is None or k2 is None:
|
|
continue
|
|
if k1[2] < hand_score_th or k2[2] < hand_score_th:
|
|
continue
|
|
|
|
x1 = int(k1[0])
|
|
y1 = int(k1[1])
|
|
x2 = int(k2[0])
|
|
y2 = int(k2[1])
|
|
if x1 > eps and y1 > eps and x2 > eps and y2 > eps:
|
|
cv2.line(
|
|
canvas,
|
|
(x1, y1),
|
|
(x2, y2),
|
|
matplotlib.colors.hsv_to_rgb([ie / float(len(edges)), 1.0, 1.0]) * 255,
|
|
thickness=stickwidth,
|
|
)
|
|
|
|
for keypoint in keypoints:
|
|
|
|
if keypoint is None:
|
|
continue
|
|
if keypoint[2] < hand_score_th:
|
|
continue
|
|
|
|
x, y = keypoint[0], keypoint[1]
|
|
x = int(x)
|
|
y = int(y)
|
|
if x > eps and y > eps:
|
|
cv2.circle(canvas, (x, y), stickwidth, (0, 0, 255), thickness=-1)
|
|
return canvas
|
|
|
|
|
|
def draw_ellipse_by_2kp(img, keypoint1, keypoint2, color, threshold=0.6):
|
|
H, W, C = img.shape
|
|
stickwidth = max(int(min(H, W) / 200), 1)
|
|
|
|
if keypoint1[-1] < threshold or keypoint2[-1] < threshold:
|
|
return img
|
|
|
|
Y = np.array([keypoint1[0], keypoint2[0]])
|
|
X = np.array([keypoint1[1], keypoint2[1]])
|
|
mX = np.mean(X)
|
|
mY = np.mean(Y)
|
|
length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
|
|
angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
|
|
polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth), int(angle), 0, 360, 1)
|
|
cv2.fillConvexPoly(img, polygon, [int(float(c) * 0.6) for c in color])
|
|
return img
|
|
|
|
|
|
def split_pose2d_kps_to_aa(kp2ds: np.ndarray) -> List[np.ndarray]:
|
|
"""Convert the 133 keypoints from pose2d to body and hands keypoints.
|
|
|
|
Args:
|
|
kp2ds (np.ndarray): [133, 2]
|
|
|
|
Returns:
|
|
List[np.ndarray]: _description_
|
|
"""
|
|
kp2ds_body = (
|
|
kp2ds[[0, 6, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 17, 20]]
|
|
+ kp2ds[[0, 5, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 18, 21]]
|
|
) / 2
|
|
kp2ds_lhand = kp2ds[91:112]
|
|
kp2ds_rhand = kp2ds[112:133]
|
|
return kp2ds_body.copy(), kp2ds_lhand.copy(), kp2ds_rhand.copy()
|
|
|
|
|
|
def draw_aapose_by_meta(img, meta: AAPoseMeta, threshold=0.5, stick_width_norm=200, draw_hand=True, draw_head=True):
|
|
kp2ds = np.concatenate([meta.kps_body, meta.kps_body_p[:, None]], axis=1)
|
|
kp2ds_lhand = np.concatenate([meta.kps_lhand, meta.kps_lhand_p[:, None]], axis=1)
|
|
kp2ds_rhand = np.concatenate([meta.kps_rhand, meta.kps_rhand_p[:, None]], axis=1)
|
|
pose_img = draw_aapose(img, kp2ds, threshold, kp2ds_lhand=kp2ds_lhand, kp2ds_rhand=kp2ds_rhand, stick_width_norm=stick_width_norm, draw_hand=draw_hand, draw_head=draw_head)
|
|
return pose_img
|
|
|
|
def draw_aapose_by_meta_new(img, meta: AAPoseMeta, threshold=0.5, stickwidth_type='v2', draw_hand=True, draw_head=True):
|
|
kp2ds = np.concatenate([meta.kps_body, meta.kps_body_p[:, None]], axis=1)
|
|
kp2ds_lhand = np.concatenate([meta.kps_lhand, meta.kps_lhand_p[:, None]], axis=1)
|
|
kp2ds_rhand = np.concatenate([meta.kps_rhand, meta.kps_rhand_p[:, None]], axis=1)
|
|
pose_img = draw_aapose_new(img, kp2ds, threshold, kp2ds_lhand=kp2ds_lhand, kp2ds_rhand=kp2ds_rhand,
|
|
stickwidth_type=stickwidth_type, draw_hand=draw_hand, draw_head=draw_head)
|
|
return pose_img
|
|
|
|
def draw_hand_by_meta(img, meta: AAPoseMeta, threshold=0.5, stick_width_norm=200):
|
|
kp2ds = np.concatenate([meta.kps_body, meta.kps_body_p[:, None] * 0], axis=1)
|
|
kp2ds_lhand = np.concatenate([meta.kps_lhand, meta.kps_lhand_p[:, None]], axis=1)
|
|
kp2ds_rhand = np.concatenate([meta.kps_rhand, meta.kps_rhand_p[:, None]], axis=1)
|
|
pose_img = draw_aapose(img, kp2ds, threshold, kp2ds_lhand=kp2ds_lhand, kp2ds_rhand=kp2ds_rhand, stick_width_norm=stick_width_norm, draw_hand=True, draw_head=False)
|
|
return pose_img
|
|
|
|
|
|
def draw_aaface_by_meta(img, meta: AAPoseMeta, threshold=0.5, stick_width_norm=200, draw_hand=False, draw_head=True):
|
|
kp2ds = np.concatenate([meta.kps_body, meta.kps_body_p[:, None]], axis=1)
|
|
# kp2ds_lhand = np.concatenate([meta.kps_lhand, meta.kps_lhand_p[:, None]], axis=1)
|
|
# kp2ds_rhand = np.concatenate([meta.kps_rhand, meta.kps_rhand_p[:, None]], axis=1)
|
|
pose_img = draw_M(img, kp2ds, threshold, kp2ds_lhand=None, kp2ds_rhand=None, stick_width_norm=stick_width_norm, draw_hand=draw_hand, draw_head=draw_head)
|
|
return pose_img
|
|
|
|
|
|
def draw_aanose_by_meta(img, meta: AAPoseMeta, threshold=0.5, stick_width_norm=100, draw_hand=False):
|
|
kp2ds = np.concatenate([meta.kps_body, meta.kps_body_p[:, None]], axis=1)
|
|
# kp2ds_lhand = np.concatenate([meta.kps_lhand, meta.kps_lhand_p[:, None]], axis=1)
|
|
# kp2ds_rhand = np.concatenate([meta.kps_rhand, meta.kps_rhand_p[:, None]], axis=1)
|
|
pose_img = draw_nose(img, kp2ds, threshold, kp2ds_lhand=None, kp2ds_rhand=None, stick_width_norm=stick_width_norm, draw_hand=draw_hand)
|
|
return pose_img
|
|
|
|
|
|
def gen_face_motion_seq(img, metas: List[AAPoseMeta], threshold=0.5, stick_width_norm=200):
|
|
|
|
return
|
|
|
|
|
|
def draw_M(
|
|
img,
|
|
kp2ds,
|
|
threshold=0.6,
|
|
data_to_json=None,
|
|
idx=-1,
|
|
kp2ds_lhand=None,
|
|
kp2ds_rhand=None,
|
|
draw_hand=False,
|
|
stick_width_norm=200,
|
|
draw_head=True
|
|
):
|
|
"""
|
|
Draw keypoints and connections representing hand pose on a given canvas.
|
|
|
|
Args:
|
|
canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
|
|
keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
|
|
or None if no keypoints are present.
|
|
|
|
Returns:
|
|
np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
|
|
|
|
Note:
|
|
The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
|
|
"""
|
|
|
|
new_kep_list = [
|
|
"Nose",
|
|
"Neck",
|
|
"RShoulder",
|
|
"RElbow",
|
|
"RWrist", # No.4
|
|
"LShoulder",
|
|
"LElbow",
|
|
"LWrist", # No.7
|
|
"RHip",
|
|
"RKnee",
|
|
"RAnkle", # No.10
|
|
"LHip",
|
|
"LKnee",
|
|
"LAnkle", # No.13
|
|
"REye",
|
|
"LEye",
|
|
"REar",
|
|
"LEar",
|
|
"LToe",
|
|
"RToe",
|
|
]
|
|
# kp2ds_body = (kp2ds.copy()[[0, 6, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 17, 20]] + \
|
|
# kp2ds.copy()[[0, 5, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 18, 21]]) / 2
|
|
kp2ds = kp2ds.copy()
|
|
# import ipdb; ipdb.set_trace()
|
|
kp2ds[[1,2,3,4,5,6,7,8,9,10,11,12,13,18,19], 2] = 0
|
|
if not draw_head:
|
|
kp2ds[[0,14,15,16,17], 2] = 0
|
|
kp2ds_body = kp2ds
|
|
# kp2ds_body = kp2ds_body[:18]
|
|
|
|
# kp2ds_lhand = kp2ds.copy()[91:112]
|
|
# kp2ds_rhand = kp2ds.copy()[112:133]
|
|
|
|
limbSeq = [
|
|
# [2, 3],
|
|
# [2, 6], # shoulders
|
|
# [3, 4],
|
|
# [4, 5], # left arm
|
|
# [6, 7],
|
|
# [7, 8], # right arm
|
|
# [2, 9],
|
|
# [9, 10],
|
|
# [10, 11], # right leg
|
|
# [2, 12],
|
|
# [12, 13],
|
|
# [13, 14], # left leg
|
|
# [2, 1],
|
|
[1, 15],
|
|
[15, 17],
|
|
[1, 16],
|
|
[16, 18], # face (nose, eyes, ears)
|
|
# [14, 19],
|
|
# [11, 20], # foot
|
|
]
|
|
|
|
colors = [
|
|
# [255, 0, 0],
|
|
# [255, 85, 0],
|
|
# [255, 170, 0],
|
|
# [255, 255, 0],
|
|
# [170, 255, 0],
|
|
# [85, 255, 0],
|
|
# [0, 255, 0],
|
|
# [0, 255, 85],
|
|
# [0, 255, 170],
|
|
# [0, 255, 255],
|
|
# [0, 170, 255],
|
|
# [0, 85, 255],
|
|
# [0, 0, 255],
|
|
# [85, 0, 255],
|
|
[170, 0, 255],
|
|
[255, 0, 255],
|
|
[255, 0, 170],
|
|
[255, 0, 85],
|
|
# foot
|
|
# [200, 200, 0],
|
|
# [100, 100, 0],
|
|
]
|
|
|
|
H, W, C = img.shape
|
|
stickwidth = max(int(min(H, W) / stick_width_norm), 1)
|
|
|
|
for _idx, ((k1_index, k2_index), color) in enumerate(zip(limbSeq, colors)):
|
|
keypoint1 = kp2ds_body[k1_index - 1]
|
|
keypoint2 = kp2ds_body[k2_index - 1]
|
|
|
|
if keypoint1[-1] < threshold or keypoint2[-1] < threshold:
|
|
continue
|
|
|
|
Y = np.array([keypoint1[0], keypoint2[0]])
|
|
X = np.array([keypoint1[1], keypoint2[1]])
|
|
mX = np.mean(X)
|
|
mY = np.mean(Y)
|
|
length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
|
|
angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
|
|
polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth), int(angle), 0, 360, 1)
|
|
cv2.fillConvexPoly(img, polygon, [int(float(c) * 0.6) for c in color])
|
|
|
|
for _idx, (keypoint, color) in enumerate(zip(kp2ds_body, colors)):
|
|
if keypoint[-1] < threshold:
|
|
continue
|
|
x, y = keypoint[0], keypoint[1]
|
|
# cv2.circle(canvas, (int(x), int(y)), 4, color, thickness=-1)
|
|
cv2.circle(img, (int(x), int(y)), stickwidth, color, thickness=-1)
|
|
|
|
if draw_hand:
|
|
img = draw_handpose(img, kp2ds_lhand, hand_score_th=threshold)
|
|
img = draw_handpose(img, kp2ds_rhand, hand_score_th=threshold)
|
|
|
|
kp2ds_body[:, 0] /= W
|
|
kp2ds_body[:, 1] /= H
|
|
|
|
if data_to_json is not None:
|
|
if idx == -1:
|
|
data_to_json.append(
|
|
{
|
|
"image_id": "frame_{:05d}.jpg".format(len(data_to_json) + 1),
|
|
"height": H,
|
|
"width": W,
|
|
"category_id": 1,
|
|
"keypoints_body": kp2ds_body.tolist(),
|
|
"keypoints_left_hand": kp2ds_lhand.tolist(),
|
|
"keypoints_right_hand": kp2ds_rhand.tolist(),
|
|
}
|
|
)
|
|
else:
|
|
data_to_json[idx] = {
|
|
"image_id": "frame_{:05d}.jpg".format(idx + 1),
|
|
"height": H,
|
|
"width": W,
|
|
"category_id": 1,
|
|
"keypoints_body": kp2ds_body.tolist(),
|
|
"keypoints_left_hand": kp2ds_lhand.tolist(),
|
|
"keypoints_right_hand": kp2ds_rhand.tolist(),
|
|
}
|
|
return img
|
|
|
|
|
|
def draw_nose(
|
|
img,
|
|
kp2ds,
|
|
threshold=0.6,
|
|
data_to_json=None,
|
|
idx=-1,
|
|
kp2ds_lhand=None,
|
|
kp2ds_rhand=None,
|
|
draw_hand=False,
|
|
stick_width_norm=200,
|
|
):
|
|
"""
|
|
Draw keypoints and connections representing hand pose on a given canvas.
|
|
|
|
Args:
|
|
canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
|
|
keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
|
|
or None if no keypoints are present.
|
|
|
|
Returns:
|
|
np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
|
|
|
|
Note:
|
|
The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
|
|
"""
|
|
|
|
new_kep_list = [
|
|
"Nose",
|
|
"Neck",
|
|
"RShoulder",
|
|
"RElbow",
|
|
"RWrist", # No.4
|
|
"LShoulder",
|
|
"LElbow",
|
|
"LWrist", # No.7
|
|
"RHip",
|
|
"RKnee",
|
|
"RAnkle", # No.10
|
|
"LHip",
|
|
"LKnee",
|
|
"LAnkle", # No.13
|
|
"REye",
|
|
"LEye",
|
|
"REar",
|
|
"LEar",
|
|
"LToe",
|
|
"RToe",
|
|
]
|
|
# kp2ds_body = (kp2ds.copy()[[0, 6, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 17, 20]] + \
|
|
# kp2ds.copy()[[0, 5, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 18, 21]]) / 2
|
|
kp2ds = kp2ds.copy()
|
|
kp2ds[1:, 2] = 0
|
|
# kp2ds[0, 2] = 1
|
|
kp2ds_body = kp2ds
|
|
# kp2ds_body = kp2ds_body[:18]
|
|
|
|
# kp2ds_lhand = kp2ds.copy()[91:112]
|
|
# kp2ds_rhand = kp2ds.copy()[112:133]
|
|
|
|
limbSeq = [
|
|
# [2, 3],
|
|
# [2, 6], # shoulders
|
|
# [3, 4],
|
|
# [4, 5], # left arm
|
|
# [6, 7],
|
|
# [7, 8], # right arm
|
|
# [2, 9],
|
|
# [9, 10],
|
|
# [10, 11], # right leg
|
|
# [2, 12],
|
|
# [12, 13],
|
|
# [13, 14], # left leg
|
|
# [2, 1],
|
|
[1, 15],
|
|
[15, 17],
|
|
[1, 16],
|
|
[16, 18], # face (nose, eyes, ears)
|
|
# [14, 19],
|
|
# [11, 20], # foot
|
|
]
|
|
|
|
colors = [
|
|
# [255, 0, 0],
|
|
# [255, 85, 0],
|
|
# [255, 170, 0],
|
|
# [255, 255, 0],
|
|
# [170, 255, 0],
|
|
# [85, 255, 0],
|
|
# [0, 255, 0],
|
|
# [0, 255, 85],
|
|
# [0, 255, 170],
|
|
# [0, 255, 255],
|
|
# [0, 170, 255],
|
|
# [0, 85, 255],
|
|
# [0, 0, 255],
|
|
# [85, 0, 255],
|
|
[170, 0, 255],
|
|
# [255, 0, 255],
|
|
# [255, 0, 170],
|
|
# [255, 0, 85],
|
|
# foot
|
|
# [200, 200, 0],
|
|
# [100, 100, 0],
|
|
]
|
|
|
|
H, W, C = img.shape
|
|
stickwidth = max(int(min(H, W) / stick_width_norm), 1)
|
|
|
|
# for _idx, ((k1_index, k2_index), color) in enumerate(zip(limbSeq, colors)):
|
|
# keypoint1 = kp2ds_body[k1_index - 1]
|
|
# keypoint2 = kp2ds_body[k2_index - 1]
|
|
|
|
# if keypoint1[-1] < threshold or keypoint2[-1] < threshold:
|
|
# continue
|
|
|
|
# Y = np.array([keypoint1[0], keypoint2[0]])
|
|
# X = np.array([keypoint1[1], keypoint2[1]])
|
|
# mX = np.mean(X)
|
|
# mY = np.mean(Y)
|
|
# length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
|
|
# angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
|
|
# polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth), int(angle), 0, 360, 1)
|
|
# cv2.fillConvexPoly(img, polygon, [int(float(c) * 0.6) for c in color])
|
|
|
|
for _idx, (keypoint, color) in enumerate(zip(kp2ds_body, colors)):
|
|
if keypoint[-1] < threshold:
|
|
continue
|
|
x, y = keypoint[0], keypoint[1]
|
|
# cv2.circle(canvas, (int(x), int(y)), 4, color, thickness=-1)
|
|
cv2.circle(img, (int(x), int(y)), stickwidth, color, thickness=-1)
|
|
|
|
if draw_hand:
|
|
img = draw_handpose(img, kp2ds_lhand, hand_score_th=threshold)
|
|
img = draw_handpose(img, kp2ds_rhand, hand_score_th=threshold)
|
|
|
|
kp2ds_body[:, 0] /= W
|
|
kp2ds_body[:, 1] /= H
|
|
|
|
if data_to_json is not None:
|
|
if idx == -1:
|
|
data_to_json.append(
|
|
{
|
|
"image_id": "frame_{:05d}.jpg".format(len(data_to_json) + 1),
|
|
"height": H,
|
|
"width": W,
|
|
"category_id": 1,
|
|
"keypoints_body": kp2ds_body.tolist(),
|
|
"keypoints_left_hand": kp2ds_lhand.tolist(),
|
|
"keypoints_right_hand": kp2ds_rhand.tolist(),
|
|
}
|
|
)
|
|
else:
|
|
data_to_json[idx] = {
|
|
"image_id": "frame_{:05d}.jpg".format(idx + 1),
|
|
"height": H,
|
|
"width": W,
|
|
"category_id": 1,
|
|
"keypoints_body": kp2ds_body.tolist(),
|
|
"keypoints_left_hand": kp2ds_lhand.tolist(),
|
|
"keypoints_right_hand": kp2ds_rhand.tolist(),
|
|
}
|
|
return img
|
|
|
|
|
|
def draw_aapose(
|
|
img,
|
|
kp2ds,
|
|
threshold=0.6,
|
|
data_to_json=None,
|
|
idx=-1,
|
|
kp2ds_lhand=None,
|
|
kp2ds_rhand=None,
|
|
draw_hand=False,
|
|
stick_width_norm=200,
|
|
draw_head=True
|
|
):
|
|
"""
|
|
Draw keypoints and connections representing hand pose on a given canvas.
|
|
|
|
Args:
|
|
canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
|
|
keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
|
|
or None if no keypoints are present.
|
|
|
|
Returns:
|
|
np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
|
|
|
|
Note:
|
|
The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
|
|
"""
|
|
|
|
new_kep_list = [
|
|
"Nose",
|
|
"Neck",
|
|
"RShoulder",
|
|
"RElbow",
|
|
"RWrist", # No.4
|
|
"LShoulder",
|
|
"LElbow",
|
|
"LWrist", # No.7
|
|
"RHip",
|
|
"RKnee",
|
|
"RAnkle", # No.10
|
|
"LHip",
|
|
"LKnee",
|
|
"LAnkle", # No.13
|
|
"REye",
|
|
"LEye",
|
|
"REar",
|
|
"LEar",
|
|
"LToe",
|
|
"RToe",
|
|
]
|
|
# kp2ds_body = (kp2ds.copy()[[0, 6, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 17, 20]] + \
|
|
# kp2ds.copy()[[0, 5, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 18, 21]]) / 2
|
|
kp2ds = kp2ds.copy()
|
|
if not draw_head:
|
|
kp2ds[[0,14,15,16,17], 2] = 0
|
|
kp2ds_body = kp2ds
|
|
|
|
# kp2ds_lhand = kp2ds.copy()[91:112]
|
|
# kp2ds_rhand = kp2ds.copy()[112:133]
|
|
|
|
limbSeq = [
|
|
[2, 3],
|
|
[2, 6], # shoulders
|
|
[3, 4],
|
|
[4, 5], # left arm
|
|
[6, 7],
|
|
[7, 8], # right arm
|
|
[2, 9],
|
|
[9, 10],
|
|
[10, 11], # right leg
|
|
[2, 12],
|
|
[12, 13],
|
|
[13, 14], # left leg
|
|
[2, 1],
|
|
[1, 15],
|
|
[15, 17],
|
|
[1, 16],
|
|
[16, 18], # face (nose, eyes, ears)
|
|
[14, 19],
|
|
[11, 20], # foot
|
|
]
|
|
|
|
colors = [
|
|
[255, 0, 0],
|
|
[255, 85, 0],
|
|
[255, 170, 0],
|
|
[255, 255, 0],
|
|
[170, 255, 0],
|
|
[85, 255, 0],
|
|
[0, 255, 0],
|
|
[0, 255, 85],
|
|
[0, 255, 170],
|
|
[0, 255, 255],
|
|
[0, 170, 255],
|
|
[0, 85, 255],
|
|
[0, 0, 255],
|
|
[85, 0, 255],
|
|
[170, 0, 255],
|
|
[255, 0, 255],
|
|
[255, 0, 170],
|
|
[255, 0, 85],
|
|
# foot
|
|
[200, 200, 0],
|
|
[100, 100, 0],
|
|
]
|
|
|
|
H, W, C = img.shape
|
|
stickwidth = max(int(min(H, W) / stick_width_norm), 1)
|
|
|
|
for _idx, ((k1_index, k2_index), color) in enumerate(zip(limbSeq, colors)):
|
|
keypoint1 = kp2ds_body[k1_index - 1]
|
|
keypoint2 = kp2ds_body[k2_index - 1]
|
|
|
|
if keypoint1[-1] < threshold or keypoint2[-1] < threshold:
|
|
continue
|
|
|
|
Y = np.array([keypoint1[0], keypoint2[0]])
|
|
X = np.array([keypoint1[1], keypoint2[1]])
|
|
mX = np.mean(X)
|
|
mY = np.mean(Y)
|
|
length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
|
|
angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
|
|
polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth), int(angle), 0, 360, 1)
|
|
cv2.fillConvexPoly(img, polygon, [int(float(c) * 0.6) for c in color])
|
|
|
|
for _idx, (keypoint, color) in enumerate(zip(kp2ds_body, colors)):
|
|
if keypoint[-1] < threshold:
|
|
continue
|
|
x, y = keypoint[0], keypoint[1]
|
|
# cv2.circle(canvas, (int(x), int(y)), 4, color, thickness=-1)
|
|
cv2.circle(img, (int(x), int(y)), stickwidth, color, thickness=-1)
|
|
|
|
if draw_hand:
|
|
img = draw_handpose(img, kp2ds_lhand, hand_score_th=threshold)
|
|
img = draw_handpose(img, kp2ds_rhand, hand_score_th=threshold)
|
|
|
|
kp2ds_body[:, 0] /= W
|
|
kp2ds_body[:, 1] /= H
|
|
|
|
if data_to_json is not None:
|
|
if idx == -1:
|
|
data_to_json.append(
|
|
{
|
|
"image_id": "frame_{:05d}.jpg".format(len(data_to_json) + 1),
|
|
"height": H,
|
|
"width": W,
|
|
"category_id": 1,
|
|
"keypoints_body": kp2ds_body.tolist(),
|
|
"keypoints_left_hand": kp2ds_lhand.tolist(),
|
|
"keypoints_right_hand": kp2ds_rhand.tolist(),
|
|
}
|
|
)
|
|
else:
|
|
data_to_json[idx] = {
|
|
"image_id": "frame_{:05d}.jpg".format(idx + 1),
|
|
"height": H,
|
|
"width": W,
|
|
"category_id": 1,
|
|
"keypoints_body": kp2ds_body.tolist(),
|
|
"keypoints_left_hand": kp2ds_lhand.tolist(),
|
|
"keypoints_right_hand": kp2ds_rhand.tolist(),
|
|
}
|
|
return img
|
|
|
|
|
|
def draw_aapose_new(
|
|
img,
|
|
kp2ds,
|
|
threshold=0.6,
|
|
data_to_json=None,
|
|
idx=-1,
|
|
kp2ds_lhand=None,
|
|
kp2ds_rhand=None,
|
|
draw_hand=False,
|
|
stickwidth_type='v2',
|
|
draw_head=True
|
|
):
|
|
"""
|
|
Draw keypoints and connections representing hand pose on a given canvas.
|
|
|
|
Args:
|
|
canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
|
|
keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
|
|
or None if no keypoints are present.
|
|
|
|
Returns:
|
|
np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
|
|
|
|
Note:
|
|
The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
|
|
"""
|
|
|
|
new_kep_list = [
|
|
"Nose",
|
|
"Neck",
|
|
"RShoulder",
|
|
"RElbow",
|
|
"RWrist", # No.4
|
|
"LShoulder",
|
|
"LElbow",
|
|
"LWrist", # No.7
|
|
"RHip",
|
|
"RKnee",
|
|
"RAnkle", # No.10
|
|
"LHip",
|
|
"LKnee",
|
|
"LAnkle", # No.13
|
|
"REye",
|
|
"LEye",
|
|
"REar",
|
|
"LEar",
|
|
"LToe",
|
|
"RToe",
|
|
]
|
|
# kp2ds_body = (kp2ds.copy()[[0, 6, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 17, 20]] + \
|
|
# kp2ds.copy()[[0, 5, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 18, 21]]) / 2
|
|
kp2ds = kp2ds.copy()
|
|
if not draw_head:
|
|
kp2ds[[0,14,15,16,17], 2] = 0
|
|
kp2ds_body = kp2ds
|
|
|
|
# kp2ds_lhand = kp2ds.copy()[91:112]
|
|
# kp2ds_rhand = kp2ds.copy()[112:133]
|
|
|
|
limbSeq = [
|
|
[2, 3],
|
|
[2, 6], # shoulders
|
|
[3, 4],
|
|
[4, 5], # left arm
|
|
[6, 7],
|
|
[7, 8], # right arm
|
|
[2, 9],
|
|
[9, 10],
|
|
[10, 11], # right leg
|
|
[2, 12],
|
|
[12, 13],
|
|
[13, 14], # left leg
|
|
[2, 1],
|
|
[1, 15],
|
|
[15, 17],
|
|
[1, 16],
|
|
[16, 18], # face (nose, eyes, ears)
|
|
[14, 19],
|
|
[11, 20], # foot
|
|
]
|
|
|
|
colors = [
|
|
[255, 0, 0],
|
|
[255, 85, 0],
|
|
[255, 170, 0],
|
|
[255, 255, 0],
|
|
[170, 255, 0],
|
|
[85, 255, 0],
|
|
[0, 255, 0],
|
|
[0, 255, 85],
|
|
[0, 255, 170],
|
|
[0, 255, 255],
|
|
[0, 170, 255],
|
|
[0, 85, 255],
|
|
[0, 0, 255],
|
|
[85, 0, 255],
|
|
[170, 0, 255],
|
|
[255, 0, 255],
|
|
[255, 0, 170],
|
|
[255, 0, 85],
|
|
# foot
|
|
[200, 200, 0],
|
|
[100, 100, 0],
|
|
]
|
|
|
|
H, W, C = img.shape
|
|
H, W, C = img.shape
|
|
|
|
if stickwidth_type == 'v1':
|
|
stickwidth = max(int(min(H, W) / 200), 1)
|
|
elif stickwidth_type == 'v2':
|
|
stickwidth = max(int(min(H, W) / 200) - 1, 1)
|
|
else:
|
|
raise
|
|
|
|
for _idx, ((k1_index, k2_index), color) in enumerate(zip(limbSeq, colors)):
|
|
keypoint1 = kp2ds_body[k1_index - 1]
|
|
keypoint2 = kp2ds_body[k2_index - 1]
|
|
|
|
if keypoint1[-1] < threshold or keypoint2[-1] < threshold:
|
|
continue
|
|
|
|
Y = np.array([keypoint1[0], keypoint2[0]])
|
|
X = np.array([keypoint1[1], keypoint2[1]])
|
|
mX = np.mean(X)
|
|
mY = np.mean(Y)
|
|
length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
|
|
angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
|
|
polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth), int(angle), 0, 360, 1)
|
|
cv2.fillConvexPoly(img, polygon, [int(float(c) * 0.6) for c in color])
|
|
|
|
for _idx, (keypoint, color) in enumerate(zip(kp2ds_body, colors)):
|
|
if keypoint[-1] < threshold:
|
|
continue
|
|
x, y = keypoint[0], keypoint[1]
|
|
# cv2.circle(canvas, (int(x), int(y)), 4, color, thickness=-1)
|
|
cv2.circle(img, (int(x), int(y)), stickwidth, color, thickness=-1)
|
|
|
|
if draw_hand:
|
|
img = draw_handpose_new(img, kp2ds_lhand, stickwidth_type=stickwidth_type, hand_score_th=threshold)
|
|
img = draw_handpose_new(img, kp2ds_rhand, stickwidth_type=stickwidth_type, hand_score_th=threshold)
|
|
|
|
kp2ds_body[:, 0] /= W
|
|
kp2ds_body[:, 1] /= H
|
|
|
|
if data_to_json is not None:
|
|
if idx == -1:
|
|
data_to_json.append(
|
|
{
|
|
"image_id": "frame_{:05d}.jpg".format(len(data_to_json) + 1),
|
|
"height": H,
|
|
"width": W,
|
|
"category_id": 1,
|
|
"keypoints_body": kp2ds_body.tolist(),
|
|
"keypoints_left_hand": kp2ds_lhand.tolist(),
|
|
"keypoints_right_hand": kp2ds_rhand.tolist(),
|
|
}
|
|
)
|
|
else:
|
|
data_to_json[idx] = {
|
|
"image_id": "frame_{:05d}.jpg".format(idx + 1),
|
|
"height": H,
|
|
"width": W,
|
|
"category_id": 1,
|
|
"keypoints_body": kp2ds_body.tolist(),
|
|
"keypoints_left_hand": kp2ds_lhand.tolist(),
|
|
"keypoints_right_hand": kp2ds_rhand.tolist(),
|
|
}
|
|
return img
|
|
|
|
|
|
def draw_bbox(img, bbox, color=(255, 0, 0)):
|
|
img = load_image(img)
|
|
bbox = [int(bbox_tmp) for bbox_tmp in bbox]
|
|
cv2.rectangle(img, (bbox[0], bbox[1]), (bbox[2], bbox[3]), color, 2)
|
|
return img
|
|
|
|
|
|
def draw_kp2ds(img, kp2ds, threshold=0, color=(255, 0, 0), skeleton=None, reverse=False):
|
|
img = load_image(img, reverse)
|
|
|
|
if skeleton is not None:
|
|
if skeleton == "coco17":
|
|
skeleton_list = [
|
|
[6, 8],
|
|
[8, 10],
|
|
[5, 7],
|
|
[7, 9],
|
|
[11, 13],
|
|
[13, 15],
|
|
[12, 14],
|
|
[14, 16],
|
|
[5, 6],
|
|
[6, 12],
|
|
[12, 11],
|
|
[11, 5],
|
|
]
|
|
color_list = [
|
|
(255, 0, 0),
|
|
(0, 255, 0),
|
|
(0, 0, 255),
|
|
(255, 255, 0),
|
|
(255, 0, 255),
|
|
(0, 255, 255),
|
|
]
|
|
elif skeleton == "cocowholebody":
|
|
skeleton_list = [
|
|
[6, 8],
|
|
[8, 10],
|
|
[5, 7],
|
|
[7, 9],
|
|
[11, 13],
|
|
[13, 15],
|
|
[12, 14],
|
|
[14, 16],
|
|
[5, 6],
|
|
[6, 12],
|
|
[12, 11],
|
|
[11, 5],
|
|
[15, 17],
|
|
[15, 18],
|
|
[15, 19],
|
|
[16, 20],
|
|
[16, 21],
|
|
[16, 22],
|
|
[91, 92, 93, 94, 95],
|
|
[91, 96, 97, 98, 99],
|
|
[91, 100, 101, 102, 103],
|
|
[91, 104, 105, 106, 107],
|
|
[91, 108, 109, 110, 111],
|
|
[112, 113, 114, 115, 116],
|
|
[112, 117, 118, 119, 120],
|
|
[112, 121, 122, 123, 124],
|
|
[112, 125, 126, 127, 128],
|
|
[112, 129, 130, 131, 132],
|
|
]
|
|
color_list = [
|
|
(255, 0, 0),
|
|
(0, 255, 0),
|
|
(0, 0, 255),
|
|
(255, 255, 0),
|
|
(255, 0, 255),
|
|
(0, 255, 255),
|
|
]
|
|
else:
|
|
color_list = [color]
|
|
for _idx, _skeleton in enumerate(skeleton_list):
|
|
for i in range(len(_skeleton) - 1):
|
|
cv2.line(
|
|
img,
|
|
(int(kp2ds[_skeleton[i], 0]), int(kp2ds[_skeleton[i], 1])),
|
|
(int(kp2ds[_skeleton[i + 1], 0]), int(kp2ds[_skeleton[i + 1], 1])),
|
|
color_list[_idx % len(color_list)],
|
|
3,
|
|
)
|
|
|
|
for _idx, kp2d in enumerate(kp2ds):
|
|
if kp2d[2] > threshold:
|
|
cv2.circle(img, (int(kp2d[0]), int(kp2d[1])), 3, color, -1)
|
|
# cv2.putText(img,
|
|
# str(_idx),
|
|
# (int(kp2d[0, i, 0])*1,
|
|
# int(kp2d[0, i, 1])*1),
|
|
# cv2.FONT_HERSHEY_SIMPLEX,
|
|
# 0.75,
|
|
# color,
|
|
# 2
|
|
# )
|
|
|
|
return img
|
|
|
|
|
|
def draw_mask(img, mask, background=0, return_rgba=False):
|
|
img = load_image(img)
|
|
h, w, _ = img.shape
|
|
if type(background) == int:
|
|
background = np.ones((h, w, 3)).astype(np.uint8) * 255 * background
|
|
backgournd = cv2.resize(background, (w, h))
|
|
img_rgba = np.concatenate([img, mask], -1)
|
|
return alphaMerge(img_rgba, background, 0, 0, return_rgba=True)
|
|
|
|
|
|
def draw_pcd(pcd_list, save_path=None):
|
|
fig = plt.figure()
|
|
ax = fig.add_subplot(111, projection="3d")
|
|
|
|
color_list = ["r", "g", "b", "y", "p"]
|
|
|
|
for _idx, _pcd in enumerate(pcd_list):
|
|
ax.scatter(_pcd[:, 0], _pcd[:, 1], _pcd[:, 2], c=color_list[_idx], marker="o")
|
|
|
|
ax.set_xlabel("X")
|
|
ax.set_ylabel("Y")
|
|
ax.set_zlabel("Z")
|
|
|
|
if save_path is not None:
|
|
plt.savefig(save_path)
|
|
else:
|
|
plt.savefig("tmp.png")
|
|
|
|
|
|
def load_image(img, reverse=False):
|
|
if type(img) == str:
|
|
img = cv2.imread(img)
|
|
if reverse:
|
|
img = img.astype(np.float32)
|
|
img = img[:, :, ::-1]
|
|
img = img.astype(np.uint8)
|
|
return img
|
|
|
|
|
|
def draw_skeleten(meta):
|
|
kps = []
|
|
for i, kp in enumerate(meta["keypoints_body"]):
|
|
if kp is None:
|
|
# if kp is None:
|
|
kps.append([0, 0, 0])
|
|
else:
|
|
kps.append([*kp, 1])
|
|
kps = np.array(kps)
|
|
|
|
kps[:, 0] *= meta["width"]
|
|
kps[:, 1] *= meta["height"]
|
|
pose_img = np.zeros([meta["height"], meta["width"], 3], dtype=np.uint8)
|
|
|
|
pose_img = draw_aapose(
|
|
pose_img,
|
|
kps,
|
|
draw_hand=True,
|
|
kp2ds_lhand=meta["keypoints_left_hand"],
|
|
kp2ds_rhand=meta["keypoints_right_hand"],
|
|
)
|
|
return pose_img
|
|
|
|
|
|
def draw_skeleten_with_pncc(pncc: np.ndarray, meta: Dict) -> np.ndarray:
|
|
"""
|
|
Args:
|
|
pncc: [H,W,3]
|
|
meta: required keys: keypoints_body: [N, 3] keypoints_left_hand, keypoints_right_hand
|
|
Return:
|
|
np.ndarray [H, W, 3]
|
|
"""
|
|
# preprocess keypoints
|
|
kps = []
|
|
for i, kp in enumerate(meta["keypoints_body"]):
|
|
if kp is None:
|
|
# if kp is None:
|
|
kps.append([0, 0, 0])
|
|
elif i in [14, 15, 16, 17]:
|
|
kps.append([0, 0, 0])
|
|
else:
|
|
kps.append([*kp])
|
|
kps = np.stack(kps)
|
|
|
|
kps[:, 0] *= pncc.shape[1]
|
|
kps[:, 1] *= pncc.shape[0]
|
|
|
|
# draw neck
|
|
canvas = np.zeros_like(pncc)
|
|
if kps[0][2] > 0.6 and kps[1][2] > 0.6:
|
|
canvas = draw_ellipse_by_2kp(canvas, kps[0], kps[1], [0, 0, 255])
|
|
|
|
# draw pncc
|
|
mask = (pncc > 0).max(axis=2)
|
|
canvas[mask] = pncc[mask]
|
|
pncc = canvas
|
|
|
|
# draw other skeleten
|
|
kps[0] = 0
|
|
|
|
meta["keypoints_left_hand"][:, 0] *= meta["width"]
|
|
meta["keypoints_left_hand"][:, 1] *= meta["height"]
|
|
|
|
meta["keypoints_right_hand"][:, 0] *= meta["width"]
|
|
meta["keypoints_right_hand"][:, 1] *= meta["height"]
|
|
pose_img = draw_aapose(
|
|
pncc,
|
|
kps,
|
|
draw_hand=True,
|
|
kp2ds_lhand=meta["keypoints_left_hand"],
|
|
kp2ds_rhand=meta["keypoints_right_hand"],
|
|
)
|
|
return pose_img
|
|
|
|
|
|
FACE_CUSTOM_STYLE = {
|
|
"eyeball": {"indexs": [68, 69], "color": [255, 255, 255], "connect": False},
|
|
"left_eyebrow": {"indexs": [17, 18, 19, 20, 21], "color": [0, 255, 0]},
|
|
"right_eyebrow": {"indexs": [22, 23, 24, 25, 26], "color": [0, 0, 255]},
|
|
"left_eye": {"indexs": [36, 37, 38, 39, 40, 41], "color": [255, 255, 0], "close": True},
|
|
"right_eye": {"indexs": [42, 43, 44, 45, 46, 47], "color": [255, 0, 255], "close": True},
|
|
"mouth_outside": {"indexs": list(range(48, 60)), "color": [100, 255, 50], "close": True},
|
|
"mouth_inside": {"indexs": [60, 61, 62, 63, 64, 65, 66, 67], "color": [255, 100, 50], "close": True},
|
|
}
|
|
|
|
|
|
def draw_face_kp(img, kps, thickness=2, style=FACE_CUSTOM_STYLE):
|
|
"""
|
|
Args:
|
|
img: [H, W, 3]
|
|
kps: [70, 2]
|
|
"""
|
|
img = img.copy()
|
|
for key, item in style.items():
|
|
pts = np.array(kps[item["indexs"]]).astype(np.int32)
|
|
connect = item.get("connect", True)
|
|
color = item["color"]
|
|
close = item.get("close", False)
|
|
if connect:
|
|
cv2.polylines(img, [pts], close, color, thickness=thickness)
|
|
else:
|
|
for kp in pts:
|
|
kp = np.array(kp).astype(np.int32)
|
|
cv2.circle(img, kp, thickness * 2, color=color, thickness=-1)
|
|
return img
|
|
|
|
|
|
def draw_traj(metas: List[AAPoseMeta], threshold=0.6):
|
|
|
|
colors = [[255, 0, 0], [255, 85, 0], [255, 170, 0], [255, 255, 0], [170, 255, 0], [85, 255, 0], [0, 255, 0], \
|
|
[0, 255, 85], [0, 255, 170], [0, 255, 255], [0, 170, 255], [0, 85, 255], [0, 0, 255], [85, 0, 255], \
|
|
[170, 0, 255], [255, 0, 255], [255, 0, 170], [255, 0, 85], [100, 255, 50], [255, 100, 50],
|
|
# foot
|
|
[200, 200, 0],
|
|
[100, 100, 0]
|
|
]
|
|
limbSeq = [
|
|
[1, 2], [1, 5], # shoulders
|
|
[2, 3], [3, 4], # left arm
|
|
[5, 6], [6, 7], # right arm
|
|
[1, 8], [8, 9], [9, 10], # right leg
|
|
[1, 11], [11, 12], [12, 13], # left leg
|
|
# face (nose, eyes, ears)
|
|
[13, 18], [10, 19] # foot
|
|
]
|
|
|
|
face_seq = [[1, 0], [0, 14], [14, 16], [0, 15], [15, 17]]
|
|
kp_body = np.array([meta.kps_body for meta in metas])
|
|
kp_body_p = np.array([meta.kps_body_p for meta in metas])
|
|
|
|
|
|
face_seq = random.sample(face_seq, 2)
|
|
|
|
kp_lh = np.array([meta.kps_lhand for meta in metas])
|
|
kp_rh = np.array([meta.kps_rhand for meta in metas])
|
|
|
|
kp_lh_p = np.array([meta.kps_lhand_p for meta in metas])
|
|
kp_rh_p = np.array([meta.kps_rhand_p for meta in metas])
|
|
|
|
# kp_lh = np.concatenate([kp_lh, kp_lh_p], axis=-1)
|
|
# kp_rh = np.concatenate([kp_rh, kp_rh_p], axis=-1)
|
|
|
|
new_limbSeq = []
|
|
key_point_list = []
|
|
for _idx, ((k1_index, k2_index)) in enumerate(limbSeq):
|
|
|
|
vis = (kp_body_p[:, k1_index] > threshold) * (kp_body_p[:, k2_index] > threshold) * 1
|
|
if vis.sum() * 1.0 / vis.shape[0] > 0.4:
|
|
new_limbSeq.append([k1_index, k2_index])
|
|
|
|
for _idx, ((k1_index, k2_index)) in enumerate(limbSeq):
|
|
|
|
keypoint1 = kp_body[:, k1_index - 1]
|
|
keypoint2 = kp_body[:, k2_index - 1]
|
|
interleave = random.randint(4, 7)
|
|
randind = random.randint(0, interleave - 1)
|
|
# randind = random.rand(range(interleave), sampling_num)
|
|
|
|
Y = np.array([keypoint1[:, 0], keypoint2[:, 0]])
|
|
X = np.array([keypoint1[:, 1], keypoint2[:, 1]])
|
|
|
|
vis = (keypoint1[:, -1] > threshold) * (keypoint2[:, -1] > threshold) * 1
|
|
|
|
# for randidx in randind:
|
|
t = randind / interleave
|
|
x = (1-t)*Y[0, :] + t*Y[1, :]
|
|
y = (1-t)*X[0, :] + t*X[1, :]
|
|
|
|
# np.array([1])
|
|
x = x.astype(int)
|
|
y = y.astype(int)
|
|
|
|
new_array = np.array([x, y, vis]).T
|
|
|
|
key_point_list.append(new_array)
|
|
|
|
indx_lh = random.randint(0, kp_lh.shape[1] - 1)
|
|
lh = kp_lh[:, indx_lh, :]
|
|
lh_p = kp_lh_p[:, indx_lh:indx_lh+1]
|
|
lh = np.concatenate([lh, lh_p], axis=-1)
|
|
|
|
indx_rh = random.randint(0, kp_rh.shape[1] - 1)
|
|
rh = kp_rh[:, random.randint(0, kp_rh.shape[1] - 1), :]
|
|
rh_p = kp_rh_p[:, indx_rh:indx_rh+1]
|
|
rh = np.concatenate([rh, rh_p], axis=-1)
|
|
|
|
|
|
|
|
lh[-1, :] = (lh[-1, :] > threshold) * 1
|
|
rh[-1, :] = (rh[-1, :] > threshold) * 1
|
|
|
|
# print(rh.shape, new_array.shape)
|
|
# exit()
|
|
key_point_list.append(lh.astype(int))
|
|
key_point_list.append(rh.astype(int))
|
|
|
|
|
|
key_points_list = np.stack(key_point_list)
|
|
num_points = len(key_points_list)
|
|
sample_colors = random.sample(colors, num_points)
|
|
|
|
stickwidth = max(int(min(metas[0].width, metas[0].height) / 150), 2)
|
|
|
|
image_list_ori = []
|
|
for i in range(key_points_list.shape[-2]):
|
|
_image_vis = np.zeros((metas[0].width, metas[0].height, 3))
|
|
points = key_points_list[:, i, :]
|
|
for idx, point in enumerate(points):
|
|
x, y, vis = point
|
|
if vis == 1:
|
|
cv2.circle(_image_vis, (x, y), stickwidth, sample_colors[idx], thickness=-1)
|
|
|
|
image_list_ori.append(_image_vis)
|
|
|
|
return image_list_ori
|
|
|
|
return [np.zeros([meta.width, meta.height, 3], dtype=np.uint8) for meta in metas]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
meta = {
|
|
"image_id": "00472.jpg",
|
|
"height": 540,
|
|
"width": 414,
|
|
"category_id": 1,
|
|
"keypoints_body": [
|
|
[0.5084776947463768, 0.11350188078703703],
|
|
[0.504467655495169, 0.20419560185185184],
|
|
[0.3982016153381642, 0.198046875],
|
|
[0.3841664779589372, 0.34869068287037036],
|
|
[0.3901815368357488, 0.4670536747685185],
|
|
[0.610733695652174, 0.2103443287037037],
|
|
[0.6167487545289855, 0.3517650462962963],
|
|
[0.6448190292874396, 0.4762767650462963],
|
|
[0.4523371452294686, 0.47320240162037036],
|
|
[0.4503321256038647, 0.6776475694444445],
|
|
[0.47639738073671495, 0.8544234664351852],
|
|
[0.5766483620169082, 0.47320240162037036],
|
|
[0.5666232638888888, 0.6761103877314815],
|
|
[0.534542949879227, 0.863646556712963],
|
|
[0.4864224788647343, 0.09505570023148148],
|
|
[0.5285278910024155, 0.09351851851851851],
|
|
[0.46236224335748793, 0.10581597222222222],
|
|
[0.5586031853864735, 0.10274160879629629],
|
|
[0.4994551064311594, 0.9405056423611111],
|
|
[0.4152442821557971, 0.9312825520833333],
|
|
],
|
|
"keypoints_left_hand": [
|
|
[267.78515625, 263.830078125, 1.2840936183929443],
|
|
[265.294921875, 269.640625, 1.2546794414520264],
|
|
[263.634765625, 277.111328125, 1.2863062620162964],
|
|
[262.8046875, 285.412109375, 1.267038345336914],
|
|
[261.14453125, 292.8828125, 1.280144453048706],
|
|
[273.595703125, 281.26171875, 1.2592815160751343],
|
|
[271.10546875, 291.22265625, 1.3256099224090576],
|
|
[265.294921875, 294.54296875, 1.2368024587631226],
|
|
[261.14453125, 294.54296875, 0.9771889448165894],
|
|
[274.42578125, 282.091796875, 1.250044584274292],
|
|
[269.4453125, 291.22265625, 1.2571144104003906],
|
|
[264.46484375, 292.8828125, 1.177802324295044],
|
|
[260.314453125, 292.052734375, 0.9283463358879089],
|
|
[273.595703125, 282.091796875, 1.1834490299224854],
|
|
[269.4453125, 290.392578125, 1.188171625137329],
|
|
[265.294921875, 290.392578125, 1.192609429359436],
|
|
[261.974609375, 289.5625, 0.9366656541824341],
|
|
[271.935546875, 281.26171875, 1.0946396589279175],
|
|
[268.615234375, 287.072265625, 0.9906131029129028],
|
|
[265.294921875, 287.90234375, 1.0219476222991943],
|
|
[262.8046875, 287.072265625, 0.9240120053291321],
|
|
],
|
|
"keypoints_right_hand": [
|
|
[161.53515625, 258.849609375, 1.2069408893585205],
|
|
[168.17578125, 263.0, 1.1846840381622314],
|
|
[173.986328125, 269.640625, 1.1435924768447876],
|
|
[173.986328125, 277.94140625, 1.1802611351013184],
|
|
[173.986328125, 286.2421875, 1.2599592208862305],
|
|
[165.685546875, 275.451171875, 1.0633569955825806],
|
|
[167.345703125, 286.2421875, 1.1693341732025146],
|
|
[169.8359375, 291.22265625, 1.2698509693145752],
|
|
[170.666015625, 294.54296875, 1.0619274377822876],
|
|
[160.705078125, 276.28125, 1.0995020866394043],
|
|
[163.1953125, 287.90234375, 1.2735884189605713],
|
|
[166.515625, 291.22265625, 1.339503526687622],
|
|
[169.005859375, 294.54296875, 1.0835273265838623],
|
|
[157.384765625, 277.111328125, 1.0866981744766235],
|
|
[161.53515625, 287.072265625, 1.2468621730804443],
|
|
[164.025390625, 289.5625, 1.2817761898040771],
|
|
[166.515625, 292.052734375, 1.099466323852539],
|
|
[155.724609375, 277.111328125, 1.1065717935562134],
|
|
[159.044921875, 285.412109375, 1.1924479007720947],
|
|
[160.705078125, 287.072265625, 1.1304771900177002],
|
|
[162.365234375, 287.90234375, 1.0040509700775146],
|
|
],
|
|
}
|
|
demo_meta = AAPoseMeta(meta)
|
|
res = draw_traj([demo_meta]*5)
|
|
cv2.imwrite("traj.png", res[0][..., ::-1])
|