From 4d6ff920bf6f783e5797bfc99bfcb4e5db0e7abf Mon Sep 17 00:00:00 2001 From: Ram Deshmukh Date: Mon, 8 Jan 2024 16:47:59 +0530 Subject: [PATCH] added backpose adaption, hand shifting, handle missing wrist --- __init__.py | 208 ++++++- dwpose/comfy_utils.py | 150 ++++- samples/1.6_backpose_adaption/backpose.json | 526 ++++++++++++++++++ .../backpose_demo_workflow.json | 220 ++++++++ .../1.6_backpose_adaption/left_backpose.json | 526 ++++++++++++++++++ samples/1.6_backpose_adaption/mannequin.json | 1 + .../1.6_backpose_adaption/right_backpose.json | 526 ++++++++++++++++++ 7 files changed, 2127 insertions(+), 30 deletions(-) create mode 100644 samples/1.6_backpose_adaption/backpose.json create mode 100644 samples/1.6_backpose_adaption/backpose_demo_workflow.json create mode 100644 samples/1.6_backpose_adaption/left_backpose.json create mode 100644 samples/1.6_backpose_adaption/mannequin.json create mode 100644 samples/1.6_backpose_adaption/right_backpose.json diff --git a/__init__.py b/__init__.py index 8b0f3fd..b7ad630 100644 --- a/__init__.py +++ b/__init__.py @@ -874,6 +874,8 @@ class TRI3DPosetoImage: canvas = np.zeros(shape=(height, width, 3), dtype=np.uint8) canvas = comfy_utils.draw_bodypose(canvas, keypoints) + canvas = comfy_utils.draw_handpose(canvas, keypoints[88:109]) #right hand + canvas = comfy_utils.draw_handpose(canvas, keypoints[109:]) #left hand canvas = torch.from_numpy(canvas.astype(np.float32)/255.0)[None,] return (canvas, ) @@ -921,38 +923,59 @@ class TRI3DPoseAdaption: if similar_torso == False: canvas = torch.from_numpy(canvas.astype(np.float32)/255.0)[None,] return (canvas, similar_torso) + #Hands - input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 2, 3) # rotate left elbow + if input_keypoints[4] == [-1,-1]: input_keypoints[4] = ref_keypoints[4] + if input_keypoints[7] == [-1,-1]: input_keypoints[7] = ref_keypoints[7] + + input_keypoints[88:] = ref_keypoints[88:] #replace hands with reference hands + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 2, 3) # rotate left elbow + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 2, 2, 3) #scaling w.r.t to shoulder to elbow ratio of ref pose + + prev_lw = input_keypoints[4] input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 3, 4) #rotate left wrist input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 2, 3, 3, 4) #scaling w.r.t to elbow to wrist ratio of ref pose - input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 5, 6) #rotate right elbow + #moving to hand ponts to wrist + input_keypoints[109:] = comfy_utils.move(input_keypoints[109], input_keypoints[4], input_keypoints[109:]) + input_keypoints[109:] = comfy_utils.move(ref_keypoints[4], ref_keypoints[109], input_keypoints[109:]) + # input_keypoints = comfy_utils.rotate_hand(ref_keypoints, input_keypoints, 109) #rotating left hand + input_keypoints = comfy_utils.scale_hand(ref_keypoints, input_keypoints, 3, 4, 109) #scaling left hand w.r.t left wrist + + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 5, 6) #rotate right elbow + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 5, 5, 6) #scaling w.r.t to shoulder to elbow ratio of ref pose + + prev_rw = input_keypoints[7] input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 6, 7) #rotate right wrist input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 5, 6, 6, 7) #scaling w.r.t to elbow to wrist ratio of ref pose + #moving hand points to wrist + input_keypoints[88:109] = comfy_utils.move(input_keypoints[88], input_keypoints[7], input_keypoints[88:109]) + input_keypoints[88:109] = comfy_utils.move(ref_keypoints[7], ref_keypoints[88], input_keypoints[88:109]) + + # input_keypoints = comfy_utils.rotate_hand(ref_keypoints, input_keypoints, 88) #rotating right hand + input_keypoints = comfy_utils.scale_hand(ref_keypoints, input_keypoints, 6, 7, 88) #scaling right hand w.r.t right wrist + + #legs input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 8, 9) #rotate left knee + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 8, 8, 9) #scale left knee input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 9, 10) #rotate left foot input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 8, 9, 9, 10) #scaling w.r.t to knee to foot ratio of ref pose input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 11, 12) #rotate right knee + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 11, 11, 12) #scale right knee input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 12, 13) #rotate right foot input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 11, 12, 12, 13) #scaling w.r.t to knee to foot ratio of ref pose #face - face_points = input_keypoints[14:] - nose = input_keypoints[0] - + prev_nose = input_keypoints[0] input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 1, 0) #rotate nose - + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 2, 5, 1, 0) #scale neck to nose w.r.t to shoulder neck-nose len ratio of ref pose + #changing face points to w.r.t to new nose point after rotation - x_off = input_keypoints[0][0] - nose[0] - y_off = input_keypoints[0][1] - nose[1] - for i in range(4): - new_x = face_points[i][0]+x_off - new_y = face_points[i][1]+y_off - input_keypoints[i+14] = [new_x, new_y] + input_keypoints[14:18] = comfy_utils.move(prev_nose, input_keypoints[0], input_keypoints[14:18]) input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 0, 14) #rotate left eye input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 0, 0, 14) #scaling w.r.t to neck len to eye_nose len ratio of ref pose @@ -967,6 +990,8 @@ class TRI3DPoseAdaption: input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 0, 15, 17) #scaling w.r.t to neck len to ear_nose len ratio of ref pose canvas = comfy_utils.draw_bodypose(canvas, input_keypoints) + canvas = comfy_utils.draw_handpose(canvas, input_keypoints[88:109]) #right hand + canvas = comfy_utils.draw_handpose(canvas, input_keypoints[109:]) #left hand canvas = torch.from_numpy(canvas.astype(np.float32)/255.0)[None,] return (canvas, similar_torso) @@ -997,6 +1022,8 @@ class TRI3DLoadPoseJson: canvas = np.zeros(shape=(height, width, 3), dtype=np.uint8) canvas = comfy_utils.draw_bodypose(canvas, keypoints) + canvas = comfy_utils.draw_handpose(canvas, keypoints[88:109]) #right hand + canvas = comfy_utils.draw_handpose(canvas, keypoints[109:]) #left hand canvas = torch.from_numpy(canvas.astype(np.float32)/255.0)[None,] else: canvas = np.zeros(shape=(height, width, 3), dtype=np.uint8) @@ -1007,21 +1034,145 @@ class TRI3DLoadPoseJson: # mask = torch.zeros((64,64), dtype=torch.float32, device="cpu") return (canvas, ) - # @classmethod - # def IS_CHANGED(s, image): - # image_path = folder_paths.get_annotated_filepath(image) - # m = hashlib.sha256() - # with open(image_path, 'rb') as f: - # m.update(f.read()) - # return m.digest().hex() +class TRI3DBackPoseAdaption: + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "input_pose_json_file": ("STRING", {"default": "dwpose/keypoints"}), + "backpose_json_file": ("STRING", {"default": "dwpose/keypoints"}), + "input_pose_type": (["front_pose", "back_pose"], {"default": "back_pose"}), + "target_pose_type":(["normal_back_pose", "side_facing_back_pose"], {"default": "normal_back_pose"}) + } + } + RETURN_TYPES = ("IMAGE","BOOLEAN") + FUNCTION = "main" + CATEGORY = "TRI3D" + + def main(self, input_pose_json_file, backpose_json_file, input_pose_type, target_pose_type): + from .dwpose import comfy_utils - # @classmethod - # def VALIDATE_INPUTS(s, image): - # if not folder_paths.exists_annotated_filepath(image): - # return "Invalid image file: {}".format(image) + input_pose = json.load(open(input_pose_json_file)) + input_height = input_pose['height'] + input_width = input_pose['width'] + input_keypoints = input_pose['keypoints'] + canvas = np.zeros(shape=(input_height, input_width, 3), dtype=np.uint8) - # return True + ref_pose = json.load(open(backpose_json_file)) + ref_height = ref_pose['height'] + ref_width = ref_pose['width'] + ref_keypoints = ref_pose['keypoints'] + + #check torso similarity + ls_angle_1, rs_angle_1, torso_angle_1 = comfy_utils.get_torso_angles(input_keypoints) + ls_angle_2, rs_angle_2, torso_angle_2 = comfy_utils.get_torso_angles(ref_keypoints) + ls_angle_diff = abs(ls_angle_2 - ls_angle_1) + rs_angle_diff = abs(rs_angle_2 - rs_angle_1) + torso_angle_diff = abs(torso_angle_2 - torso_angle_1) + + similar_torso = False if (ls_angle_diff >= 5) | (rs_angle_diff >= 5) | (torso_angle_diff >= 5) else True + + if similar_torso == False: + canvas = torch.from_numpy(canvas.astype(np.float32)/255.0)[None,] + return (canvas, similar_torso) + + #flip horizontally + if input_pose_type == "front_pose": + null_indices = [i for i in range(len(ref_keypoints)) if ref_keypoints[i] == [-1,-1]] + + for i in null_indices: + input_keypoints[i] = [-1,-1] + + for i in range(len(input_keypoints)): + x,y = input_keypoints[i] + if input_keypoints[i] == [-1,-1]: continue + input_keypoints[i] = [input_width - x, y] + + #Hands + if input_keypoints[4] == [-1,-1]: input_keypoints[4] = ref_keypoints[4] + if input_keypoints[7] == [-1,-1]: input_keypoints[7] = ref_keypoints[7] + input_keypoints[88:] = ref_keypoints[88:] #replace hands with reference hands + + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 2, 3) # rotate left elbow + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 2, 2, 3) #scaling w.r.t to shoulder to elbow ratio of ref pose + + prev_lw = input_keypoints[4] + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 3, 4) #rotate left wrist + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 2, 3, 3, 4) #scaling w.r.t to elbow to wrist ratio of ref pose + + #moving to hand ponts to wrist + input_keypoints[109:] = comfy_utils.move(input_keypoints[109], input_keypoints[4], input_keypoints[109:]) + input_keypoints[109:] = comfy_utils.move(ref_keypoints[4], ref_keypoints[109], input_keypoints[109:]) + + # input_keypoints = comfy_utils.rotate_hand(ref_keypoints, input_keypoints, 109) #rotating left hand + input_keypoints = comfy_utils.scale_hand(ref_keypoints, input_keypoints, 3, 4, 109) #scaling left hand w.r.t left wrist + + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 5, 6) #rotate right elbow + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 5, 5, 6) #scaling w.r.t to shoulder to elbow ratio of ref pose + + prev_rw = input_keypoints[7] + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 6, 7) #rotate right wrist + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 5, 6, 6, 7) #scaling w.r.t to elbow to wrist ratio of ref pose + + #moving hand points to wrist + input_keypoints[88:109] = comfy_utils.move(input_keypoints[88], input_keypoints[7], input_keypoints[88:109]) + input_keypoints[88:109] = comfy_utils.move(ref_keypoints[7], ref_keypoints[88], input_keypoints[88:109]) + + # input_keypoints = comfy_utils.rotate_hand(ref_keypoints, input_keypoints, 88) #rotating right hand + input_keypoints = comfy_utils.scale_hand(ref_keypoints, input_keypoints, 6, 7, 88) #scaling right hand w.r.t right wrist + + #legs + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 8, 9) #rotate left knee + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 8, 8, 9) #scale left knee + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 9, 10) #rotate left foot + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 8, 9, 9, 10) #scaling w.r.t to knee to foot ratio of ref pose + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 11, 12) #rotate right knee + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 11, 11, 12) #scale right knee + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 12, 13) #rotate right foot + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 11, 12, 12, 13) #scaling w.r.t to knee to foot ratio of ref pose + + #face + if target_pose_type == "normal_back_pose": + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 1, 16) #rotate left ear + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 2, 5, 1, 16) #scaling w.r.t to neck len to ear_nose len ratio of ref pose + + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 1,17) #rotate right ear + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 2, 5, 1, 17) #scaling w.r.t to neck len to ear_nose len ratio of ref pose + else: + prev_nose = input_keypoints[0] + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 1, 0) #rotate nose + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 2, 5, 1, 0) #scale neck to nose w.r.t to shoulder neck-nose len ratio of ref pose + + #changing face points to w.r.t to new nose point after rotation + input_keypoints[14:18] = comfy_utils.move(prev_nose, input_keypoints[0], input_keypoints[14:18]) + + if input_keypoints[14] != [-1,-1]: + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 0, 14) #rotate left eye + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 0, 0, 14) #scaling w.r.t to neck len to eye_nose len ratio of ref pose + + if input_keypoints[15] != [-1,-1]: + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 0, 15) #rotate right eye + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 0, 0, 15) #scaling w.r.t to neck len to eye_nose len ratio of ref pose + + if input_keypoints[16] != [-1,-1]: + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 14, 16) #rotate left ear + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 0, 14, 16) #scaling w.r.t to neck len to ear_nose len ratio of ref pose + + if input_keypoints[17] != [-1,-1]: + input_keypoints = comfy_utils.rotate(ref_keypoints, input_keypoints, 15,17) #rotate right ear + input_keypoints = comfy_utils.scale(ref_keypoints, input_keypoints, 1, 0, 15, 17) #scaling w.r.t to neck len to ear_nose len ratio of ref pose + + canvas = comfy_utils.draw_bodypose(canvas, input_keypoints) + canvas = comfy_utils.draw_handpose(canvas, input_keypoints[88:109]) #right hand + canvas = comfy_utils.draw_handpose(canvas, input_keypoints[109:]) #left hand + canvas = torch.from_numpy(canvas.astype(np.float32)/255.0)[None,] + return (canvas, similar_torso) + # A dictionary that contains all nodes you want to export with their names # NOTE: names should be globally unique NODE_CLASS_MAPPINGS = { @@ -1035,10 +1186,12 @@ NODE_CLASS_MAPPINGS = { "tri3d-dwpose": TRI3DDWPose_Preprocessor, "tri3d-pose-to-image": TRI3DPosetoImage, "tri3d-pose-adaption": TRI3DPoseAdaption, - "tri3d-load-pose-json": TRI3DLoadPoseJson + "tri3d-load-pose-json": TRI3DLoadPoseJson, + "tri3d-back-pose-adaption": TRI3DBackPoseAdaption, + } -VERSION = "1.4.0" +VERSION = "1.6.0" # A dictionary that contains the friendly/humanly readable titles for the nodes NODE_DISPLAY_NAME_MAPPINGS = { "tri3d-atr-parse-batch": "ATR Parse Batch" + " v" + VERSION, @@ -1051,5 +1204,6 @@ NODE_DISPLAY_NAME_MAPPINGS = { "tri3d-dwpose": "DWPose" + " v" + VERSION, "tri3d-pose-to-image": "Pose to Image" + " v" + VERSION, "tri3d-pose-adaption": "Pose Adaption" + " v" + VERSION, - "tri3d-load-pose-json": "Load Pose Json" + " v" + VERSION + "tri3d-load-pose-json": "Load Pose Json" + " v" + VERSION, + "tri3d-back-pose-adaption": "Back Pose Adaption" + "v" + VERSION } diff --git a/dwpose/comfy_utils.py b/dwpose/comfy_utils.py index 331ec21..3b076b5 100644 --- a/dwpose/comfy_utils.py +++ b/dwpose/comfy_utils.py @@ -1,6 +1,6 @@ import cv2, os, math, json import numpy as np - +import matplotlib def draw_bodypose(canvas: np.ndarray, keypoints: list) -> np.ndarray: @@ -44,6 +44,35 @@ def draw_bodypose(canvas: np.ndarray, keypoints: list) -> np.ndarray: cv2.circle(canvas, (int(x), int(y)), 4, color, thickness=-1) return canvas +def draw_handpose(canvas: np.ndarray, keypoints: list) -> np.ndarray: + + H, W, _ = canvas.shape + + 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 + + x1 = int(k1[0]) + y1 = int(k1[1]) + x2 = int(k2[0]) + y2 = int(k2[1]) + + cv2.line(canvas, (x1, y1), (x2, y2), matplotlib.colors.hsv_to_rgb([ie / float(len(edges)), 1.0, 1.0]) * 255, thickness=2) + + for keypoint in keypoints: + if keypoint is None: + continue + + x, y = keypoint[0], keypoint[1] + x = int(x) + y = int(y) + cv2.circle(canvas, (x, y), 4, (0, 0, 255), thickness=-1) + return canvas def rotate(src_keypoints, dest_keypoints, point1_idx, point2_idx): @@ -96,6 +125,97 @@ def scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, point1_ return dest_keypoints +def scale_hand(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, starting_idx): + + """ + scales all 20 hand lines for the given reference wrist length + """ + + rotate(src_keypoints, dest_keypoints, 0+starting_idx, 1+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 0+starting_idx, 1+starting_idx) + rotate(src_keypoints, dest_keypoints, 0+starting_idx, 5+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 0+starting_idx, 5+starting_idx) + rotate(src_keypoints, dest_keypoints, 0+starting_idx, 9+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 0+starting_idx, 9+starting_idx) + rotate(src_keypoints, dest_keypoints, 0+starting_idx, 13+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 0+starting_idx, 13+starting_idx) + rotate(src_keypoints, dest_keypoints, 0+starting_idx, 17+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 0+starting_idx, 17+starting_idx) + + rotate(src_keypoints, dest_keypoints, 1+starting_idx, 2+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 1+starting_idx, 2+starting_idx) + rotate(src_keypoints, dest_keypoints, 2+starting_idx, 3+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 2+starting_idx, 3+starting_idx) + rotate(src_keypoints, dest_keypoints, 3+starting_idx, 4+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 3+starting_idx, 4+starting_idx) + + rotate(src_keypoints, dest_keypoints, 5+starting_idx, 6+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 5+starting_idx, 6+starting_idx) + rotate(src_keypoints, dest_keypoints, 6+starting_idx, 7+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 6+starting_idx, 7+starting_idx) + rotate(src_keypoints, dest_keypoints, 7+starting_idx, 8+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 7+starting_idx, 8+starting_idx) + + rotate(src_keypoints, dest_keypoints, 9+starting_idx, 10+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 9+starting_idx, 10+starting_idx) + rotate(src_keypoints, dest_keypoints, 10+starting_idx, 11+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 10+starting_idx, 11+starting_idx) + rotate(src_keypoints, dest_keypoints, 11+starting_idx, 12+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 11+starting_idx, 12+starting_idx) + + rotate(src_keypoints, dest_keypoints, 13+starting_idx, 14+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 13+starting_idx, 14+starting_idx) + rotate(src_keypoints, dest_keypoints, 14+starting_idx, 15+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 14+starting_idx, 15+starting_idx) + rotate(src_keypoints, dest_keypoints, 15+starting_idx, 16+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 15+starting_idx, 16+starting_idx) + + rotate(src_keypoints, dest_keypoints, 17+starting_idx, 18+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 17+starting_idx, 18+starting_idx) + rotate(src_keypoints, dest_keypoints, 18+starting_idx, 19+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 18+starting_idx, 19+starting_idx) + rotate(src_keypoints, dest_keypoints, 19+starting_idx, 20+starting_idx) + scale(src_keypoints, dest_keypoints, ref_point1_idx, ref_point2_idx, 19+starting_idx, 20+starting_idx) + + return dest_keypoints + +def rotate_hand(src_keypoints, dest_keypoints, starting_idx): + + """ + scales all 20 hand lines for the given reference wrist length + src_keypoints: ref keypoints + dest_keypoints: mannequin keypoints + starting_idx: starting index of hand + """ + + rotate(src_keypoints, dest_keypoints, 0+starting_idx, 1+starting_idx) + rotate(src_keypoints, dest_keypoints, 0+starting_idx, 5+starting_idx) + rotate(src_keypoints, dest_keypoints, 0+starting_idx, 9+starting_idx) + rotate(src_keypoints, dest_keypoints, 0+starting_idx, 13+starting_idx) + rotate(src_keypoints, dest_keypoints, 0+starting_idx, 17+starting_idx) + + rotate(src_keypoints, dest_keypoints, 1+starting_idx, 2+starting_idx) + rotate(src_keypoints, dest_keypoints, 2+starting_idx, 3+starting_idx) + rotate(src_keypoints, dest_keypoints, 3+starting_idx, 4+starting_idx) + + rotate(src_keypoints, dest_keypoints, 5+starting_idx, 6+starting_idx) + rotate(src_keypoints, dest_keypoints, 6+starting_idx, 7+starting_idx) + rotate(src_keypoints, dest_keypoints, 7+starting_idx, 8+starting_idx) + + rotate(src_keypoints, dest_keypoints, 9+starting_idx, 10+starting_idx) + rotate(src_keypoints, dest_keypoints, 10+starting_idx, 11+starting_idx) + rotate(src_keypoints, dest_keypoints, 11+starting_idx, 12+starting_idx) + + rotate(src_keypoints, dest_keypoints, 13+starting_idx, 14+starting_idx) + rotate(src_keypoints, dest_keypoints, 14+starting_idx, 15+starting_idx) + rotate(src_keypoints, dest_keypoints, 15+starting_idx, 16+starting_idx) + + rotate(src_keypoints, dest_keypoints, 17+starting_idx, 18+starting_idx) + rotate(src_keypoints, dest_keypoints, 18+starting_idx, 19+starting_idx) + rotate(src_keypoints, dest_keypoints, 19+starting_idx, 20+starting_idx) + + return dest_keypoints + def get_torso_angles(keypoints): """ Function to get torso angles @@ -117,7 +237,31 @@ def get_torso_angles(keypoints): bi = [int((a[0]+c[0])/2), int((a[1]+c[1])/2)] #calculatng angle with y axis - angle_radians = math.atan((bi[1]-b[1])/(bi[0]-b[0])) + angle_radians = math.atan2((bi[1]-b[1]),(bi[0]-b[0])) torso_angle = 90 - abs(math.degrees(angle_radians)) - return ls_angle, rs_angle, torso_angle \ No newline at end of file + return ls_angle, rs_angle, torso_angle + +def move(prev_point, new_point, dependent_points): + """e.g if wrist is moved then rest of the hand points also be moved by same offset where """ + + x_off = new_point[0] - prev_point[0] + y_off = (new_point[1] - prev_point[1]) + + for i in range(len(dependent_points)): + if dependent_points[i] == [-1,-1]: continue + dependent_points[i] = [dependent_points[i][0]+x_off, dependent_points[i][1]+y_off] + + return dependent_points + +def switch_to_backpose(input_keypoints, input_width): + """for the given straight pose flip horizontally """ + + for i in range(len(input_keypoints)): + if i in [0,14,15]: + input_keypoints[i] = [-1, -1] + continue + x,y = input_keypoints[i] + input_keypoints[i] = [input_width - x, y] + + return input_keypoints \ No newline at end of file diff --git a/samples/1.6_backpose_adaption/backpose.json b/samples/1.6_backpose_adaption/backpose.json new file mode 100644 index 0000000..e80b565 --- /dev/null +++ b/samples/1.6_backpose_adaption/backpose.json @@ -0,0 +1,526 @@ +{ + "height": 512, + "width": 512, + "keypoints": [ + [ + -1, + -1 + ], + [ + 264, + 125 + ], + [ + 298, + 125 + ], + [ + 310, + 193 + ], + [ + 314, + 254 + ], + [ + 230, + 125 + ], + [ + 216, + 192 + ], + [ + 211, + 252 + ], + [ + 286, + 244 + ], + [ + 292, + 339 + ], + [ + 294, + 448 + ], + [ + 240, + 247 + ], + [ + 242, + 336 + ], + [ + 246, + 444 + ], + [ + -1, + -1 + ], + [ + -1, + -1 + ], + [ + 246, + 74 + ], + [ + 279, + 74 + ], + [ + 240, + 66 + ], + [ + 240, + 72 + ], + [ + 240, + 76 + ], + [ + 242, + 82 + ], + [ + 242, + 86 + ], + [ + 246, + 88 + ], + [ + 248, + 92 + ], + [ + 252, + 94 + ], + [ + 258, + 94 + ], + [ + 262, + 94 + ], + [ + 266, + 94 + ], + [ + 270, + 92 + ], + [ + 274, + 90 + ], + [ + 276, + 86 + ], + [ + 278, + 82 + ], + [ + 280, + 78 + ], + [ + 282, + 74 + ], + [ + 248, + 58 + ], + [ + 250, + 56 + ], + [ + 252, + 56 + ], + [ + 256, + 56 + ], + [ + 260, + 56 + ], + [ + 268, + 58 + ], + [ + 272, + 58 + ], + [ + 274, + 60 + ], + [ + 278, + 62 + ], + [ + 280, + 64 + ], + [ + 264, + 64 + ], + [ + 262, + 66 + ], + [ + 262, + 68 + ], + [ + 262, + 68 + ], + [ + 258, + 74 + ], + [ + 258, + 74 + ], + [ + 262, + 74 + ], + [ + 264, + 74 + ], + [ + 266, + 74 + ], + [ + 250, + 62 + ], + [ + 252, + 62 + ], + [ + 256, + 62 + ], + [ + 258, + 62 + ], + [ + 254, + 64 + ], + [ + 252, + 62 + ], + [ + 268, + 64 + ], + [ + 272, + 64 + ], + [ + 274, + 64 + ], + [ + 276, + 68 + ], + [ + 274, + 68 + ], + [ + 270, + 66 + ], + [ + 252, + 80 + ], + [ + 256, + 78 + ], + [ + 258, + 78 + ], + [ + 260, + 78 + ], + [ + 262, + 78 + ], + [ + 266, + 80 + ], + [ + 268, + 82 + ], + [ + 266, + 84 + ], + [ + 262, + 84 + ], + [ + 260, + 84 + ], + [ + 256, + 84 + ], + [ + 254, + 82 + ], + [ + 252, + 80 + ], + [ + 256, + 78 + ], + [ + 260, + 78 + ], + [ + 264, + 80 + ], + [ + 268, + 82 + ], + [ + 264, + 84 + ], + [ + 260, + 82 + ], + [ + 256, + 82 + ], + [ + 254, + 62 + ], + [ + 272, + 64 + ], + [ + 211, + 255 + ], + [ + 221, + 262 + ], + [ + 226, + 268 + ], + [ + 229, + 272 + ], + [ + 232, + 278 + ], + [ + 217, + 279 + ], + [ + 223, + 286 + ], + [ + 229, + 288 + ], + [ + 232, + 291 + ], + [ + 214, + 281 + ], + [ + 221, + 288 + ], + [ + 223, + 291 + ], + [ + 229, + 291 + ], + [ + 211, + 281 + ], + [ + 217, + 286 + ], + [ + 223, + 288 + ], + [ + 223, + 291 + ], + [ + 211, + 281 + ], + [ + 214, + 286 + ], + [ + 217, + 288 + ], + [ + 221, + 288 + ], + [ + 314.2191598676356, + 257 + ], + [ + 308.2191598676356, + 262 + ], + [ + 306.2191598676356, + 266 + ], + [ + 303.2191598676356, + 270 + ], + [ + 301.2191598676356, + 276 + ], + [ + 312.2191598676356, + 279 + ], + [ + 311.2191598676356, + 284 + ], + [ + 308.2191598676356, + 290 + ], + [ + 303.2191598676356, + 292 + ], + [ + 313.2191598676356, + 279 + ], + [ + 312.2191598676356, + 284 + ], + [ + 311.2191598676356, + 290 + ], + [ + 307.2191598676356, + 292 + ], + [ + 314.2191598676356, + 279 + ], + [ + 313.2191598676356, + 284 + ], + [ + 312.2191598676356, + 289 + ], + [ + 311.2191598676356, + 293 + ], + [ + 317.2191598676356, + 279 + ], + [ + 314.2191598676356, + 283 + ], + [ + 313.2191598676356, + 287 + ], + [ + 312.2191598676356, + 290 + ] + ] +} \ No newline at end of file diff --git a/samples/1.6_backpose_adaption/backpose_demo_workflow.json b/samples/1.6_backpose_adaption/backpose_demo_workflow.json new file mode 100644 index 0000000..428a526 --- /dev/null +++ b/samples/1.6_backpose_adaption/backpose_demo_workflow.json @@ -0,0 +1,220 @@ +{ + "last_node_id": 423, + "last_link_id": 674, + "nodes": [ + { + "id": 394, + "type": "tri3d-back-pose-adaption", + "pos": [ + 2654, + -135 + ], + "size": { + "0": 315, + "1": 150 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 658 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "BOOLEAN", + "type": "BOOLEAN", + "links": null, + "shape": 3 + } + ], + "properties": { + "Node name for S&R": "tri3d-back-pose-adaption" + }, + "widgets_values": [ + "C:\\tri3d\\pose_library\\testing\\Database\\dump_folder2\\mannequin.json", + "C:\\tri3d\\pose_library\\testing\\backpose\\backpose.json", + "front_pose", + "normal_back_pose" + ] + }, + { + "id": 391, + "type": "tri3d-pose-to-image", + "pos": [ + 2984, + -266 + ], + "size": [ + 210, + 58 + ], + "flags": {}, + "order": 1, + "mode": 0, + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 656 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "tri3d-pose-to-image" + }, + "widgets_values": [ + "C:\\tri3d\\pose_library\\testing\\Database\\dump_folder2\\mannequin.json" + ] + }, + { + "id": 393, + "type": "tri3d-pose-to-image", + "pos": [ + 3206, + -269 + ], + "size": [ + 228.55314621582056, + 58 + ], + "flags": {}, + "order": 2, + "mode": 0, + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 657 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "tri3d-pose-to-image" + }, + "widgets_values": [ + "C:\\tri3d\\pose_library\\testing\\backpose\\backpose.json" + ] + }, + { + "id": 390, + "type": "PreviewImage", + "pos": [ + 2997, + -175 + ], + "size": { + "0": 210, + "1": 246 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 656 + } + ], + "title": "Mannequin pose", + "properties": { + "Node name for S&R": "PreviewImage" + } + }, + { + "id": 395, + "type": "PreviewImage", + "pos": [ + 3430, + -180 + ], + "size": { + "0": 170.9424591064453, + "1": 246 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 658 + } + ], + "title": "adapted pose", + "properties": { + "Node name for S&R": "PreviewImage" + } + }, + { + "id": 392, + "type": "PreviewImage", + "pos": [ + 3213, + -172 + ], + "size": { + "0": 210, + "1": 246 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 657 + } + ], + "title": "ref backpose", + "properties": { + "Node name for S&R": "PreviewImage" + } + } + ], + "links": [ + [ + 656, + 391, + 0, + 390, + 0, + "IMAGE" + ], + [ + 657, + 393, + 0, + 392, + 0, + "IMAGE" + ], + [ + 658, + 394, + 0, + 395, + 0, + "IMAGE" + ] + ], + "groups": [], + "config": {}, + "extra": {}, + "version": 0.4 +} \ No newline at end of file diff --git a/samples/1.6_backpose_adaption/left_backpose.json b/samples/1.6_backpose_adaption/left_backpose.json new file mode 100644 index 0000000..c2366fa --- /dev/null +++ b/samples/1.6_backpose_adaption/left_backpose.json @@ -0,0 +1,526 @@ +{ + "height": 512, + "width": 512, + "keypoints": [ + [ + 234, + 85 + ], + [ + 264, + 125 + ], + [ + 298, + 125 + ], + [ + 310, + 193 + ], + [ + 314, + 254 + ], + [ + 230, + 125 + ], + [ + 216, + 192 + ], + [ + 211, + 252 + ], + [ + 286, + 244 + ], + [ + 292, + 339 + ], + [ + 294, + 448 + ], + [ + 240, + 247 + ], + [ + 242, + 336 + ], + [ + 246, + 444 + ], + [ + -1, + -1 + ], + [ + 238, + 72 + ], + [ + -1, + -1 + ], + [ + 262, + 70 + ], + [ + 212, + 82 + ], + [ + 212, + 88 + ], + [ + 212, + 92 + ], + [ + 214, + 98 + ], + [ + 214, + 102 + ], + [ + 218, + 104 + ], + [ + 220, + 108 + ], + [ + 224, + 110 + ], + [ + 230, + 110 + ], + [ + 234, + 110 + ], + [ + 238, + 110 + ], + [ + 242, + 108 + ], + [ + 246, + 106 + ], + [ + 248, + 102 + ], + [ + 250, + 98 + ], + [ + 252, + 94 + ], + [ + 254, + 90 + ], + [ + 220, + 74 + ], + [ + 222, + 72 + ], + [ + 224, + 72 + ], + [ + 228, + 72 + ], + [ + 232, + 72 + ], + [ + 240, + 74 + ], + [ + 244, + 74 + ], + [ + 246, + 76 + ], + [ + 250, + 78 + ], + [ + 252, + 80 + ], + [ + 236, + 80 + ], + [ + 234, + 82 + ], + [ + 232, + 84 + ], + [ + 255, + 85 + ], + [ + 230, + 90 + ], + [ + 230, + 90 + ], + [ + 234, + 90 + ], + [ + 236, + 90 + ], + [ + 238, + 90 + ], + [ + 222, + 78 + ], + [ + 224, + 78 + ], + [ + 228, + 78 + ], + [ + 230, + 78 + ], + [ + 226, + 80 + ], + [ + 224, + 78 + ], + [ + 240, + 80 + ], + [ + 244, + 80 + ], + [ + 246, + 80 + ], + [ + 248, + 84 + ], + [ + 246, + 84 + ], + [ + 242, + 82 + ], + [ + 224, + 96 + ], + [ + 228, + 94 + ], + [ + 230, + 94 + ], + [ + 232, + 94 + ], + [ + 234, + 94 + ], + [ + 238, + 96 + ], + [ + 240, + 98 + ], + [ + 238, + 100 + ], + [ + 234, + 100 + ], + [ + 232, + 100 + ], + [ + 228, + 100 + ], + [ + 226, + 98 + ], + [ + 224, + 96 + ], + [ + 228, + 94 + ], + [ + 232, + 94 + ], + [ + 236, + 96 + ], + [ + 240, + 98 + ], + [ + 236, + 100 + ], + [ + 232, + 98 + ], + [ + 228, + 98 + ], + [ + 226, + 78 + ], + [ + 244, + 80 + ], + [ + 211, + 255 + ], + [ + 221, + 262 + ], + [ + 226, + 268 + ], + [ + 229, + 272 + ], + [ + 232, + 278 + ], + [ + 217, + 279 + ], + [ + 223, + 286 + ], + [ + 229, + 288 + ], + [ + 232, + 291 + ], + [ + 214, + 281 + ], + [ + 221, + 288 + ], + [ + 223, + 291 + ], + [ + 229, + 291 + ], + [ + 211, + 281 + ], + [ + 217, + 286 + ], + [ + 223, + 288 + ], + [ + 223, + 291 + ], + [ + 211, + 281 + ], + [ + 214, + 286 + ], + [ + 217, + 288 + ], + [ + 221, + 288 + ], + [ + 314, + 257 + ], + [ + 308, + 262 + ], + [ + 306, + 266 + ], + [ + 303, + 270 + ], + [ + 301, + 276 + ], + [ + 312, + 279 + ], + [ + 311, + 284 + ], + [ + 308, + 290 + ], + [ + 303, + 292 + ], + [ + 313, + 279 + ], + [ + 312, + 284 + ], + [ + 311, + 290 + ], + [ + 307, + 292 + ], + [ + 314, + 279 + ], + [ + 313, + 284 + ], + [ + 312, + 289 + ], + [ + 311, + 293 + ], + [ + 317, + 279 + ], + [ + 314, + 283 + ], + [ + 313, + 287 + ], + [ + 312, + 290 + ] + ] +} \ No newline at end of file diff --git a/samples/1.6_backpose_adaption/mannequin.json b/samples/1.6_backpose_adaption/mannequin.json new file mode 100644 index 0000000..a044442 --- /dev/null +++ b/samples/1.6_backpose_adaption/mannequin.json @@ -0,0 +1 @@ +{"height": 768, "width": 512, "keypoints": [[267.4390640258789, 94.31109278028214], [267.99558348270756, 192.25851718212175], [207.33496268838644, 192.25851718212175], [185.07418441524112, 292.43201941127586], [179.5089898469547, 388.15336598580086], [328.6562042770287, 192.25851718212175], [346.4648268955449, 290.20594158396125], [354.2560992911458, 383.70121033117175], [230.70877987518907, 381.47513250385714], [230.70877987518907, 529.5093080202738], [234.04789661616087, 675.3174057093761], [306.39542600388324, 380.36209359019995], [299.71719252193975, 529.5093080202738], [296.37807578096783, 676.430444623033], [256.3086748893063, 82.06766473005212], [280.7955309897661, 83.18070364370942], [240.72613009810448, 96.53717060759664], [296.37807578096783, 98.76324843491113], [242.9522079254191, 86.51982038468122], [241.83916901176167, 94.31109278028214], [242.9522079254191, 100.98932626222575], [244.06524683907628, 108.78059865782654], [246.2913246663909, 115.45883213977015], [250.7434803210199, 122.13706562171376], [255.19563597564888, 126.58922127634287], [260.7608305439353, 129.92833801731467], [267.4390640258789, 131.04137693097198], [275.2303364214797, 129.92833801731467], [280.7955309897661, 126.58922127634287], [285.2476866443951, 122.13706562171376], [289.69984229902434, 115.45883213977015], [291.9259201263387, 109.89363757148385], [293.03895903999614, 103.21540408954024], [294.15199795365334, 95.42413169393933], [294.15199795365334, 88.74589821199572], [246.2913246663909, 78.72854798908031], [250.7434803210199, 77.61550907542312], [255.19563597564888, 76.50247016176581], [258.5347527166207, 76.50247016176581], [262.9869083712499, 77.61550907542312], [274.1172975078225, 78.72854798908031], [278.5694531624516, 77.61550907542312], [281.9085699034233, 77.61550907542312], [285.2476866443951, 78.72854798908031], [289.69984229902434, 79.84158690273762], [268.5521029395362, 84.29374255736673], [268.5521029395362, 88.74589821199572], [268.5521029395362, 92.08501495296753], [268.5521029395362, 95.42413169393933], [261.8738694575925, 100.98932626222575], [265.2129861985643, 100.98932626222575], [267.4390640258789, 100.98932626222575], [270.7781807668507, 100.98932626222575], [274.1172975078225, 100.98932626222575], [251.85651923467708, 84.29374255736673], [255.19563597564888, 83.18070364370942], [258.5347527166207, 83.18070364370942], [261.8738694575925, 84.29374255736673], [258.5347527166207, 85.40678147102392], [255.19563597564888, 85.40678147102392], [275.2303364214797, 85.40678147102392], [278.5694531624516, 84.29374255736673], [283.02160881708073, 84.29374255736673], [285.2476866443951, 86.51982038468122], [281.9085699034233, 86.51982038468122], [278.5694531624516, 86.51982038468122], [258.5347527166207, 112.11971539879835], [261.8738694575925, 108.78059865782654], [266.3260251122217, 106.55452083051205], [267.4390640258789, 107.66755974416935], [269.6651418531935, 106.55452083051205], [274.1172975078225, 107.66755974416935], [277.4564142487943, 112.11971539879835], [275.2303364214797, 114.34579322611296], [271.8912196805079, 116.57187105342746], [267.4390640258789, 116.57187105342746], [264.0999472849071, 116.57187105342746], [260.7608305439353, 114.34579322611296], [259.6477916302781, 112.11971539879835], [262.9869083712499, 109.89363757148385], [267.4390640258789, 108.78059865782654], [273.0042585941653, 109.89363757148385], [277.4564142487943, 112.11971539879835], [273.0042585941653, 113.23275431245565], [268.5521029395362, 114.34579322611296], [262.9869083712499, 113.23275431245565], [256.3086748893063, 82.06766473005212], [280.7955309897661, 83.18070364370942], [354.2560992911458, 395.94463838140166], [350.916982550174, 407.0750275179744], [348.6909047228595, 415.9793388272325], [348.6909047228595, 424.8836501364907], [348.6909047228595, 432.6749225320915], [356.4821771184603, 423.7706112228334], [354.2560992911458, 433.7879614457488], [350.916982550174, 439.3531560140351], [347.5778658092022, 444.9183505823215], [357.5952160321176, 423.7706112228334], [355.369138204803, 433.7879614457488], [352.0300214638312, 439.3531560140351], [348.6909047228595, 444.9183505823215], [357.5952160321176, 422.6575723091761], [355.369138204803, 432.6749225320915], [353.1430603774886, 438.2401171003779], [350.916982550174, 442.6922727550069], [357.5952160321176, 421.5445333955189], [356.4821771184603, 429.3358057911197], [354.2560992911458, 434.9010003594061], [352.0300214638312, 438.2401171003779], [179.5089898469547, 397.05767729505897], [185.07418441524112, 405.96198860431707], [189.52634006987012, 415.9793388272325], [190.63937898352742, 424.8836501364907], [191.7524178971846, 432.6749225320915], [179.5089898469547, 423.7706112228334], [181.73506767426926, 432.6749225320915], [185.07418441524112, 437.1270781867206], [187.30026224255562, 439.3531560140351], [176.1698731059829, 424.8836501364907], [179.5089898469547, 432.6749225320915], [182.84810658792657, 436.0140392730633], [185.07418441524112, 439.3531560140351], [175.0568341923257, 423.7706112228334], [178.3959509332975, 431.5618836184343], [180.622028760612, 434.9010003594061], [182.84810658792657, 437.1270781867206], [175.0568341923257, 422.6575723091761], [177.2829120196402, 429.3358057911197], [180.622028760612, 432.6749225320915], [181.73506767426926, 433.7879614457488]]} \ No newline at end of file diff --git a/samples/1.6_backpose_adaption/right_backpose.json b/samples/1.6_backpose_adaption/right_backpose.json new file mode 100644 index 0000000..ca32270 --- /dev/null +++ b/samples/1.6_backpose_adaption/right_backpose.json @@ -0,0 +1,526 @@ +{ + "height": 512, + "width": 512, + "keypoints": [ + [ + 298, + 85 + ], + [ + 264, + 125 + ], + [ + 298, + 125 + ], + [ + 310, + 193 + ], + [ + 314, + 254 + ], + [ + 230, + 125 + ], + [ + 216, + 192 + ], + [ + 211, + 252 + ], + [ + 286, + 244 + ], + [ + 292, + 339 + ], + [ + 294, + 448 + ], + [ + 240, + 247 + ], + [ + 242, + 336 + ], + [ + 246, + 444 + ], + [ + 293.3658724790831, + 75 + ], + [ + -1, + -1 + ], + [ + 270.3658724790831, + 73 + ], + [ + -1, + -1 + ], + [ + 276.3658724790831, + 82 + ], + [ + 276.3658724790831, + 88 + ], + [ + 276.3658724790831, + 92 + ], + [ + 278.3658724790831, + 98 + ], + [ + 278.3658724790831, + 102 + ], + [ + 282.3658724790831, + 104 + ], + [ + 284.3658724790831, + 108 + ], + [ + 288.3658724790831, + 110 + ], + [ + 294.3658724790831, + 110 + ], + [ + 298.3658724790831, + 110 + ], + [ + 302.3658724790831, + 110 + ], + [ + 306.3658724790831, + 108 + ], + [ + 310.3658724790831, + 106 + ], + [ + 312.3658724790831, + 102 + ], + [ + 314.3658724790831, + 98 + ], + [ + 316.3658724790831, + 94 + ], + [ + 318.3658724790831, + 90 + ], + [ + 284.3658724790831, + 74 + ], + [ + 286.3658724790831, + 72 + ], + [ + 288.3658724790831, + 72 + ], + [ + 292.3658724790831, + 72 + ], + [ + 296.3658724790831, + 72 + ], + [ + 304.3658724790831, + 74 + ], + [ + 308.3658724790831, + 74 + ], + [ + 310.3658724790831, + 76 + ], + [ + 314.3658724790831, + 78 + ], + [ + 316.3658724790831, + 80 + ], + [ + 300.3658724790831, + 80 + ], + [ + 298.3658724790831, + 82 + ], + [ + 296.3658724790831, + 84 + ], + [ + 319.3658724790831, + 85 + ], + [ + 294.3658724790831, + 90 + ], + [ + 294.3658724790831, + 90 + ], + [ + 298.3658724790831, + 90 + ], + [ + 300.3658724790831, + 90 + ], + [ + 302.3658724790831, + 90 + ], + [ + 286.3658724790831, + 78 + ], + [ + 288.3658724790831, + 78 + ], + [ + 292.3658724790831, + 78 + ], + [ + 294.3658724790831, + 78 + ], + [ + 290.3658724790831, + 80 + ], + [ + 288.3658724790831, + 78 + ], + [ + 304.3658724790831, + 80 + ], + [ + 308.3658724790831, + 80 + ], + [ + 310.3658724790831, + 80 + ], + [ + 312.3658724790831, + 84 + ], + [ + 310.3658724790831, + 84 + ], + [ + 306.3658724790831, + 82 + ], + [ + 288.3658724790831, + 96 + ], + [ + 292.3658724790831, + 94 + ], + [ + 294.3658724790831, + 94 + ], + [ + 296.3658724790831, + 94 + ], + [ + 298.3658724790831, + 94 + ], + [ + 302.3658724790831, + 96 + ], + [ + 304.3658724790831, + 98 + ], + [ + 302.3658724790831, + 100 + ], + [ + 298.3658724790831, + 100 + ], + [ + 296.3658724790831, + 100 + ], + [ + 292.3658724790831, + 100 + ], + [ + 290.3658724790831, + 98 + ], + [ + 288.3658724790831, + 96 + ], + [ + 292.3658724790831, + 94 + ], + [ + 296.3658724790831, + 94 + ], + [ + 300.3658724790831, + 96 + ], + [ + 304.3658724790831, + 98 + ], + [ + 300.3658724790831, + 100 + ], + [ + 296.3658724790831, + 98 + ], + [ + 292.3658724790831, + 98 + ], + [ + 290.3658724790831, + 78 + ], + [ + 308.3658724790831, + 80 + ], + [ + 211, + 255 + ], + [ + 221, + 262 + ], + [ + 226, + 268 + ], + [ + 229, + 272 + ], + [ + 232, + 278 + ], + [ + 217, + 279 + ], + [ + 223, + 286 + ], + [ + 229, + 288 + ], + [ + 232, + 291 + ], + [ + 214, + 281 + ], + [ + 221, + 288 + ], + [ + 223, + 291 + ], + [ + 229, + 291 + ], + [ + 211, + 281 + ], + [ + 217, + 286 + ], + [ + 223, + 288 + ], + [ + 223, + 291 + ], + [ + 211, + 281 + ], + [ + 214, + 286 + ], + [ + 217, + 288 + ], + [ + 221, + 288 + ], + [ + 314, + 257 + ], + [ + 308, + 262 + ], + [ + 306, + 266 + ], + [ + 303, + 270 + ], + [ + 301, + 276 + ], + [ + 312, + 279 + ], + [ + 311, + 284 + ], + [ + 308, + 290 + ], + [ + 303, + 292 + ], + [ + 313, + 279 + ], + [ + 312, + 284 + ], + [ + 311, + 290 + ], + [ + 307, + 292 + ], + [ + 314, + 279 + ], + [ + 313, + 284 + ], + [ + 312, + 289 + ], + [ + 311, + 293 + ], + [ + 317, + 279 + ], + [ + 314, + 283 + ], + [ + 313, + 287 + ], + [ + 312, + 290 + ] + ] +} \ No newline at end of file