@ignix-social/creator 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +57 -2
  2. package/dist/box-kit/comfyui/locks/linux-x64.txt +2409 -0
  3. package/dist/box-kit/comfyui/locks/macos-arm64.txt +2243 -0
  4. package/dist/box-kit/comfyui/locks/windows-x64.txt +2322 -0
  5. package/dist/box-kit/comfyui/recast/LICENSE-WAN.txt +201 -0
  6. package/dist/box-kit/comfyui/recast/people.py +115 -0
  7. package/dist/box-kit/comfyui/recast/persons.py +90 -0
  8. package/dist/box-kit/comfyui/recast/prep.py +204 -0
  9. package/dist/box-kit/comfyui/recast/wan_pose_draw.py +1368 -0
  10. package/dist/box-kit/comfyui/recast/wan_pose_utils.py +1160 -0
  11. package/dist/box-kit/comfyui/recast/wan_utils.py +227 -0
  12. package/dist/box-kit/comfyui/workflows/infinitetalk.v1.json +94 -0
  13. package/dist/box-kit/comfyui/workflows/wan22-i2v-14b.v1.json +112 -0
  14. package/dist/box-kit/comfyui/workflows/wan22-i2v.v1.json +62 -0
  15. package/dist/cli.cjs +23801 -0
  16. package/dist/core.cjs +63459 -0
  17. package/dist/sfx-kit/achievement.wav +0 -0
  18. package/dist/sfx-kit/applause.wav +0 -0
  19. package/dist/sfx-kit/aww.wav +0 -0
  20. package/dist/sfx-kit/boing.wav +0 -0
  21. package/dist/sfx-kit/bonk.wav +0 -0
  22. package/dist/sfx-kit/boo.wav +0 -0
  23. package/dist/sfx-kit/boom.wav +0 -0
  24. package/dist/sfx-kit/camera-shutter.wav +0 -0
  25. package/dist/sfx-kit/cash-register.wav +0 -0
  26. package/dist/sfx-kit/cheer.wav +0 -0
  27. package/dist/sfx-kit/clap-hit.wav +0 -0
  28. package/dist/sfx-kit/click.wav +0 -0
  29. package/dist/sfx-kit/clock-tick.wav +0 -0
  30. package/dist/sfx-kit/coffee-pour.wav +0 -0
  31. package/dist/sfx-kit/coin.wav +0 -0
  32. package/dist/sfx-kit/coins.wav +0 -0
  33. package/dist/sfx-kit/correct.wav +0 -0
  34. package/dist/sfx-kit/countdown-beep.wav +0 -0
  35. package/dist/sfx-kit/crickets.wav +0 -0
  36. package/dist/sfx-kit/ding.wav +0 -0
  37. package/dist/sfx-kit/door-bell.wav +0 -0
  38. package/dist/sfx-kit/door-knock.wav +0 -0
  39. package/dist/sfx-kit/error.wav +0 -0
  40. package/dist/sfx-kit/flash.wav +0 -0
  41. package/dist/sfx-kit/gasp.wav +0 -0
  42. package/dist/sfx-kit/glitch.wav +0 -0
  43. package/dist/sfx-kit/heartbeat.wav +0 -0
  44. package/dist/sfx-kit/honk.wav +0 -0
  45. package/dist/sfx-kit/impact.wav +0 -0
  46. package/dist/sfx-kit/laugh.wav +0 -0
  47. package/dist/sfx-kit/level-up.wav +0 -0
  48. package/dist/sfx-kit/message-received.wav +0 -0
  49. package/dist/sfx-kit/message-sent.wav +0 -0
  50. package/dist/sfx-kit/notification.wav +0 -0
  51. package/dist/sfx-kit/ooh.wav +0 -0
  52. package/dist/sfx-kit/page-turn.wav +0 -0
  53. package/dist/sfx-kit/paper-crumple.wav +0 -0
  54. package/dist/sfx-kit/pen-write.wav +0 -0
  55. package/dist/sfx-kit/phone-vibrate.wav +0 -0
  56. package/dist/sfx-kit/pop-clean.wav +0 -0
  57. package/dist/sfx-kit/pop.wav +0 -0
  58. package/dist/sfx-kit/punch.wav +0 -0
  59. package/dist/sfx-kit/record-scratch.wav +0 -0
  60. package/dist/sfx-kit/reverse-cymbal.wav +0 -0
  61. package/dist/sfx-kit/rimshot.wav +0 -0
  62. package/dist/sfx-kit/riser-short.wav +0 -0
  63. package/dist/sfx-kit/sad-trombone.wav +0 -0
  64. package/dist/sfx-kit/scroll.wav +0 -0
  65. package/dist/sfx-kit/slide-whistle.wav +0 -0
  66. package/dist/sfx-kit/snap.wav +0 -0
  67. package/dist/sfx-kit/sparkle.wav +0 -0
  68. package/dist/sfx-kit/splat.wav +0 -0
  69. package/dist/sfx-kit/squeak.wav +0 -0
  70. package/dist/sfx-kit/stamp.wav +0 -0
  71. package/dist/sfx-kit/stomp.wav +0 -0
  72. package/dist/sfx-kit/sub-drop.wav +0 -0
  73. package/dist/sfx-kit/success.wav +0 -0
  74. package/dist/sfx-kit/swipe.wav +0 -0
  75. package/dist/sfx-kit/swoosh-down.wav +0 -0
  76. package/dist/sfx-kit/swoosh-up.wav +0 -0
  77. package/dist/sfx-kit/tap.wav +0 -0
  78. package/dist/sfx-kit/tape-stop.wav +0 -0
  79. package/dist/sfx-kit/thud.wav +0 -0
  80. package/dist/sfx-kit/timer-end.wav +0 -0
  81. package/dist/sfx-kit/toggle.wav +0 -0
  82. package/dist/sfx-kit/typing-mobile.wav +0 -0
  83. package/dist/sfx-kit/typing-slow.wav +0 -0
  84. package/dist/sfx-kit/typing.wav +0 -0
  85. package/dist/sfx-kit/whoosh-fast.wav +0 -0
  86. package/dist/sfx-kit/whoosh-heavy.wav +0 -0
  87. package/dist/sfx-kit/whoosh-soft.wav +0 -0
  88. package/dist/sfx-kit/wow.wav +0 -0
  89. package/dist/sfx-kit/wrong.wav +0 -0
  90. package/dist/sfx-kit/zipper.wav +0 -0
  91. package/dist/sfx-kit/zoom-in.wav +0 -0
  92. package/package.json +32 -4
@@ -0,0 +1,1368 @@
1
+ # Copyright 2024-2025 The Alibaba Wan Team Authors. All rights reserved.
2
+ # Modified by Ignix (2026-10-05) for Ignix Creator: matplotlib replaced by colorsys for the one colour helper used; imports renamed. Apache-2.0 (see LICENSE-WAN.txt).
3
+ import os
4
+ import cv2
5
+ import time
6
+ import math
7
+ import colorsys
8
+
9
+
10
+ class matplotlib: # noqa: N801 - the one matplotlib call this file needs, without matplotlib
11
+ class colors: # noqa: N801
12
+ @staticmethod
13
+ def hsv_to_rgb(hsv):
14
+ return np.array(colorsys.hsv_to_rgb(*hsv))
15
+
16
+
17
+ import numpy as np
18
+ from typing import Dict, List
19
+ import random
20
+ from wan_pose_utils import AAPoseMeta
21
+
22
+
23
+ def draw_handpose(canvas, keypoints, hand_score_th=0.6):
24
+ """
25
+ Draw keypoints and connections representing hand pose on a given canvas.
26
+
27
+ Args:
28
+ canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
29
+ keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
30
+ or None if no keypoints are present.
31
+
32
+ Returns:
33
+ np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
34
+
35
+ Note:
36
+ The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
37
+ """
38
+ eps = 0.01
39
+
40
+ H, W, C = canvas.shape
41
+ stickwidth = max(int(min(H, W) / 200), 1)
42
+
43
+ edges = [
44
+ [0, 1],
45
+ [1, 2],
46
+ [2, 3],
47
+ [3, 4],
48
+ [0, 5],
49
+ [5, 6],
50
+ [6, 7],
51
+ [7, 8],
52
+ [0, 9],
53
+ [9, 10],
54
+ [10, 11],
55
+ [11, 12],
56
+ [0, 13],
57
+ [13, 14],
58
+ [14, 15],
59
+ [15, 16],
60
+ [0, 17],
61
+ [17, 18],
62
+ [18, 19],
63
+ [19, 20],
64
+ ]
65
+
66
+ for ie, (e1, e2) in enumerate(edges):
67
+ k1 = keypoints[e1]
68
+ k2 = keypoints[e2]
69
+ if k1 is None or k2 is None:
70
+ continue
71
+ if k1[2] < hand_score_th or k2[2] < hand_score_th:
72
+ continue
73
+
74
+ x1 = int(k1[0])
75
+ y1 = int(k1[1])
76
+ x2 = int(k2[0])
77
+ y2 = int(k2[1])
78
+ if x1 > eps and y1 > eps and x2 > eps and y2 > eps:
79
+ cv2.line(
80
+ canvas,
81
+ (x1, y1),
82
+ (x2, y2),
83
+ matplotlib.colors.hsv_to_rgb([ie / float(len(edges)), 1.0, 1.0]) * 255,
84
+ thickness=stickwidth,
85
+ )
86
+
87
+ for keypoint in keypoints:
88
+
89
+ if keypoint is None:
90
+ continue
91
+ if keypoint[2] < hand_score_th:
92
+ continue
93
+
94
+ x, y = keypoint[0], keypoint[1]
95
+ x = int(x)
96
+ y = int(y)
97
+ if x > eps and y > eps:
98
+ cv2.circle(canvas, (x, y), stickwidth, (0, 0, 255), thickness=-1)
99
+ return canvas
100
+
101
+
102
+ def draw_handpose_new(canvas, keypoints, stickwidth_type='v2', hand_score_th=0.6):
103
+ """
104
+ Draw keypoints and connections representing hand pose on a given canvas.
105
+
106
+ Args:
107
+ canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
108
+ keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
109
+ or None if no keypoints are present.
110
+
111
+ Returns:
112
+ np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
113
+
114
+ Note:
115
+ The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
116
+ """
117
+ eps = 0.01
118
+
119
+ H, W, C = canvas.shape
120
+ if stickwidth_type == 'v1':
121
+ stickwidth = max(int(min(H, W) / 200), 1)
122
+ elif stickwidth_type == 'v2':
123
+ stickwidth = max(max(int(min(H, W) / 200) - 1, 1) // 2, 1)
124
+
125
+ edges = [
126
+ [0, 1],
127
+ [1, 2],
128
+ [2, 3],
129
+ [3, 4],
130
+ [0, 5],
131
+ [5, 6],
132
+ [6, 7],
133
+ [7, 8],
134
+ [0, 9],
135
+ [9, 10],
136
+ [10, 11],
137
+ [11, 12],
138
+ [0, 13],
139
+ [13, 14],
140
+ [14, 15],
141
+ [15, 16],
142
+ [0, 17],
143
+ [17, 18],
144
+ [18, 19],
145
+ [19, 20],
146
+ ]
147
+
148
+ for ie, (e1, e2) in enumerate(edges):
149
+ k1 = keypoints[e1]
150
+ k2 = keypoints[e2]
151
+ if k1 is None or k2 is None:
152
+ continue
153
+ if k1[2] < hand_score_th or k2[2] < hand_score_th:
154
+ continue
155
+
156
+ x1 = int(k1[0])
157
+ y1 = int(k1[1])
158
+ x2 = int(k2[0])
159
+ y2 = int(k2[1])
160
+ if x1 > eps and y1 > eps and x2 > eps and y2 > eps:
161
+ cv2.line(
162
+ canvas,
163
+ (x1, y1),
164
+ (x2, y2),
165
+ matplotlib.colors.hsv_to_rgb([ie / float(len(edges)), 1.0, 1.0]) * 255,
166
+ thickness=stickwidth,
167
+ )
168
+
169
+ for keypoint in keypoints:
170
+
171
+ if keypoint is None:
172
+ continue
173
+ if keypoint[2] < hand_score_th:
174
+ continue
175
+
176
+ x, y = keypoint[0], keypoint[1]
177
+ x = int(x)
178
+ y = int(y)
179
+ if x > eps and y > eps:
180
+ cv2.circle(canvas, (x, y), stickwidth, (0, 0, 255), thickness=-1)
181
+ return canvas
182
+
183
+
184
+ def draw_ellipse_by_2kp(img, keypoint1, keypoint2, color, threshold=0.6):
185
+ H, W, C = img.shape
186
+ stickwidth = max(int(min(H, W) / 200), 1)
187
+
188
+ if keypoint1[-1] < threshold or keypoint2[-1] < threshold:
189
+ return img
190
+
191
+ Y = np.array([keypoint1[0], keypoint2[0]])
192
+ X = np.array([keypoint1[1], keypoint2[1]])
193
+ mX = np.mean(X)
194
+ mY = np.mean(Y)
195
+ length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
196
+ angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
197
+ polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth), int(angle), 0, 360, 1)
198
+ cv2.fillConvexPoly(img, polygon, [int(float(c) * 0.6) for c in color])
199
+ return img
200
+
201
+
202
+ def split_pose2d_kps_to_aa(kp2ds: np.ndarray) -> List[np.ndarray]:
203
+ """Convert the 133 keypoints from pose2d to body and hands keypoints.
204
+
205
+ Args:
206
+ kp2ds (np.ndarray): [133, 2]
207
+
208
+ Returns:
209
+ List[np.ndarray]: _description_
210
+ """
211
+ kp2ds_body = (
212
+ kp2ds[[0, 6, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 17, 20]]
213
+ + kp2ds[[0, 5, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 18, 21]]
214
+ ) / 2
215
+ kp2ds_lhand = kp2ds[91:112]
216
+ kp2ds_rhand = kp2ds[112:133]
217
+ return kp2ds_body.copy(), kp2ds_lhand.copy(), kp2ds_rhand.copy()
218
+
219
+
220
+ def draw_aapose_by_meta(img, meta: AAPoseMeta, threshold=0.5, stick_width_norm=200, draw_hand=True, draw_head=True):
221
+ kp2ds = np.concatenate([meta.kps_body, meta.kps_body_p[:, None]], axis=1)
222
+ kp2ds_lhand = np.concatenate([meta.kps_lhand, meta.kps_lhand_p[:, None]], axis=1)
223
+ kp2ds_rhand = np.concatenate([meta.kps_rhand, meta.kps_rhand_p[:, None]], axis=1)
224
+ 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)
225
+ return pose_img
226
+
227
+ def draw_aapose_by_meta_new(img, meta: AAPoseMeta, threshold=0.5, stickwidth_type='v2', draw_hand=True, draw_head=True):
228
+ kp2ds = np.concatenate([meta.kps_body, meta.kps_body_p[:, None]], axis=1)
229
+ kp2ds_lhand = np.concatenate([meta.kps_lhand, meta.kps_lhand_p[:, None]], axis=1)
230
+ kp2ds_rhand = np.concatenate([meta.kps_rhand, meta.kps_rhand_p[:, None]], axis=1)
231
+ pose_img = draw_aapose_new(img, kp2ds, threshold, kp2ds_lhand=kp2ds_lhand, kp2ds_rhand=kp2ds_rhand,
232
+ stickwidth_type=stickwidth_type, draw_hand=draw_hand, draw_head=draw_head)
233
+ return pose_img
234
+
235
+ def draw_hand_by_meta(img, meta: AAPoseMeta, threshold=0.5, stick_width_norm=200):
236
+ kp2ds = np.concatenate([meta.kps_body, meta.kps_body_p[:, None] * 0], axis=1)
237
+ kp2ds_lhand = np.concatenate([meta.kps_lhand, meta.kps_lhand_p[:, None]], axis=1)
238
+ kp2ds_rhand = np.concatenate([meta.kps_rhand, meta.kps_rhand_p[:, None]], axis=1)
239
+ 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)
240
+ return pose_img
241
+
242
+
243
+ def draw_aaface_by_meta(img, meta: AAPoseMeta, threshold=0.5, stick_width_norm=200, draw_hand=False, draw_head=True):
244
+ kp2ds = np.concatenate([meta.kps_body, meta.kps_body_p[:, None]], axis=1)
245
+ # kp2ds_lhand = np.concatenate([meta.kps_lhand, meta.kps_lhand_p[:, None]], axis=1)
246
+ # kp2ds_rhand = np.concatenate([meta.kps_rhand, meta.kps_rhand_p[:, None]], axis=1)
247
+ 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)
248
+ return pose_img
249
+
250
+
251
+ def draw_aanose_by_meta(img, meta: AAPoseMeta, threshold=0.5, stick_width_norm=100, draw_hand=False):
252
+ kp2ds = np.concatenate([meta.kps_body, meta.kps_body_p[:, None]], axis=1)
253
+ # kp2ds_lhand = np.concatenate([meta.kps_lhand, meta.kps_lhand_p[:, None]], axis=1)
254
+ # kp2ds_rhand = np.concatenate([meta.kps_rhand, meta.kps_rhand_p[:, None]], axis=1)
255
+ pose_img = draw_nose(img, kp2ds, threshold, kp2ds_lhand=None, kp2ds_rhand=None, stick_width_norm=stick_width_norm, draw_hand=draw_hand)
256
+ return pose_img
257
+
258
+
259
+ def gen_face_motion_seq(img, metas: List[AAPoseMeta], threshold=0.5, stick_width_norm=200):
260
+
261
+ return
262
+
263
+
264
+ def draw_M(
265
+ img,
266
+ kp2ds,
267
+ threshold=0.6,
268
+ data_to_json=None,
269
+ idx=-1,
270
+ kp2ds_lhand=None,
271
+ kp2ds_rhand=None,
272
+ draw_hand=False,
273
+ stick_width_norm=200,
274
+ draw_head=True
275
+ ):
276
+ """
277
+ Draw keypoints and connections representing hand pose on a given canvas.
278
+
279
+ Args:
280
+ canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
281
+ keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
282
+ or None if no keypoints are present.
283
+
284
+ Returns:
285
+ np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
286
+
287
+ Note:
288
+ The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
289
+ """
290
+
291
+ new_kep_list = [
292
+ "Nose",
293
+ "Neck",
294
+ "RShoulder",
295
+ "RElbow",
296
+ "RWrist", # No.4
297
+ "LShoulder",
298
+ "LElbow",
299
+ "LWrist", # No.7
300
+ "RHip",
301
+ "RKnee",
302
+ "RAnkle", # No.10
303
+ "LHip",
304
+ "LKnee",
305
+ "LAnkle", # No.13
306
+ "REye",
307
+ "LEye",
308
+ "REar",
309
+ "LEar",
310
+ "LToe",
311
+ "RToe",
312
+ ]
313
+ # kp2ds_body = (kp2ds.copy()[[0, 6, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 17, 20]] + \
314
+ # kp2ds.copy()[[0, 5, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 18, 21]]) / 2
315
+ kp2ds = kp2ds.copy()
316
+ # import ipdb; ipdb.set_trace()
317
+ kp2ds[[1,2,3,4,5,6,7,8,9,10,11,12,13,18,19], 2] = 0
318
+ if not draw_head:
319
+ kp2ds[[0,14,15,16,17], 2] = 0
320
+ kp2ds_body = kp2ds
321
+ # kp2ds_body = kp2ds_body[:18]
322
+
323
+ # kp2ds_lhand = kp2ds.copy()[91:112]
324
+ # kp2ds_rhand = kp2ds.copy()[112:133]
325
+
326
+ limbSeq = [
327
+ # [2, 3],
328
+ # [2, 6], # shoulders
329
+ # [3, 4],
330
+ # [4, 5], # left arm
331
+ # [6, 7],
332
+ # [7, 8], # right arm
333
+ # [2, 9],
334
+ # [9, 10],
335
+ # [10, 11], # right leg
336
+ # [2, 12],
337
+ # [12, 13],
338
+ # [13, 14], # left leg
339
+ # [2, 1],
340
+ [1, 15],
341
+ [15, 17],
342
+ [1, 16],
343
+ [16, 18], # face (nose, eyes, ears)
344
+ # [14, 19],
345
+ # [11, 20], # foot
346
+ ]
347
+
348
+ colors = [
349
+ # [255, 0, 0],
350
+ # [255, 85, 0],
351
+ # [255, 170, 0],
352
+ # [255, 255, 0],
353
+ # [170, 255, 0],
354
+ # [85, 255, 0],
355
+ # [0, 255, 0],
356
+ # [0, 255, 85],
357
+ # [0, 255, 170],
358
+ # [0, 255, 255],
359
+ # [0, 170, 255],
360
+ # [0, 85, 255],
361
+ # [0, 0, 255],
362
+ # [85, 0, 255],
363
+ [170, 0, 255],
364
+ [255, 0, 255],
365
+ [255, 0, 170],
366
+ [255, 0, 85],
367
+ # foot
368
+ # [200, 200, 0],
369
+ # [100, 100, 0],
370
+ ]
371
+
372
+ H, W, C = img.shape
373
+ stickwidth = max(int(min(H, W) / stick_width_norm), 1)
374
+
375
+ for _idx, ((k1_index, k2_index), color) in enumerate(zip(limbSeq, colors)):
376
+ keypoint1 = kp2ds_body[k1_index - 1]
377
+ keypoint2 = kp2ds_body[k2_index - 1]
378
+
379
+ if keypoint1[-1] < threshold or keypoint2[-1] < threshold:
380
+ continue
381
+
382
+ Y = np.array([keypoint1[0], keypoint2[0]])
383
+ X = np.array([keypoint1[1], keypoint2[1]])
384
+ mX = np.mean(X)
385
+ mY = np.mean(Y)
386
+ length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
387
+ angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
388
+ polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth), int(angle), 0, 360, 1)
389
+ cv2.fillConvexPoly(img, polygon, [int(float(c) * 0.6) for c in color])
390
+
391
+ for _idx, (keypoint, color) in enumerate(zip(kp2ds_body, colors)):
392
+ if keypoint[-1] < threshold:
393
+ continue
394
+ x, y = keypoint[0], keypoint[1]
395
+ # cv2.circle(canvas, (int(x), int(y)), 4, color, thickness=-1)
396
+ cv2.circle(img, (int(x), int(y)), stickwidth, color, thickness=-1)
397
+
398
+ if draw_hand:
399
+ img = draw_handpose(img, kp2ds_lhand, hand_score_th=threshold)
400
+ img = draw_handpose(img, kp2ds_rhand, hand_score_th=threshold)
401
+
402
+ kp2ds_body[:, 0] /= W
403
+ kp2ds_body[:, 1] /= H
404
+
405
+ if data_to_json is not None:
406
+ if idx == -1:
407
+ data_to_json.append(
408
+ {
409
+ "image_id": "frame_{:05d}.jpg".format(len(data_to_json) + 1),
410
+ "height": H,
411
+ "width": W,
412
+ "category_id": 1,
413
+ "keypoints_body": kp2ds_body.tolist(),
414
+ "keypoints_left_hand": kp2ds_lhand.tolist(),
415
+ "keypoints_right_hand": kp2ds_rhand.tolist(),
416
+ }
417
+ )
418
+ else:
419
+ data_to_json[idx] = {
420
+ "image_id": "frame_{:05d}.jpg".format(idx + 1),
421
+ "height": H,
422
+ "width": W,
423
+ "category_id": 1,
424
+ "keypoints_body": kp2ds_body.tolist(),
425
+ "keypoints_left_hand": kp2ds_lhand.tolist(),
426
+ "keypoints_right_hand": kp2ds_rhand.tolist(),
427
+ }
428
+ return img
429
+
430
+
431
+ def draw_nose(
432
+ img,
433
+ kp2ds,
434
+ threshold=0.6,
435
+ data_to_json=None,
436
+ idx=-1,
437
+ kp2ds_lhand=None,
438
+ kp2ds_rhand=None,
439
+ draw_hand=False,
440
+ stick_width_norm=200,
441
+ ):
442
+ """
443
+ Draw keypoints and connections representing hand pose on a given canvas.
444
+
445
+ Args:
446
+ canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
447
+ keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
448
+ or None if no keypoints are present.
449
+
450
+ Returns:
451
+ np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
452
+
453
+ Note:
454
+ The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
455
+ """
456
+
457
+ new_kep_list = [
458
+ "Nose",
459
+ "Neck",
460
+ "RShoulder",
461
+ "RElbow",
462
+ "RWrist", # No.4
463
+ "LShoulder",
464
+ "LElbow",
465
+ "LWrist", # No.7
466
+ "RHip",
467
+ "RKnee",
468
+ "RAnkle", # No.10
469
+ "LHip",
470
+ "LKnee",
471
+ "LAnkle", # No.13
472
+ "REye",
473
+ "LEye",
474
+ "REar",
475
+ "LEar",
476
+ "LToe",
477
+ "RToe",
478
+ ]
479
+ # kp2ds_body = (kp2ds.copy()[[0, 6, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 17, 20]] + \
480
+ # kp2ds.copy()[[0, 5, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 18, 21]]) / 2
481
+ kp2ds = kp2ds.copy()
482
+ kp2ds[1:, 2] = 0
483
+ # kp2ds[0, 2] = 1
484
+ kp2ds_body = kp2ds
485
+ # kp2ds_body = kp2ds_body[:18]
486
+
487
+ # kp2ds_lhand = kp2ds.copy()[91:112]
488
+ # kp2ds_rhand = kp2ds.copy()[112:133]
489
+
490
+ limbSeq = [
491
+ # [2, 3],
492
+ # [2, 6], # shoulders
493
+ # [3, 4],
494
+ # [4, 5], # left arm
495
+ # [6, 7],
496
+ # [7, 8], # right arm
497
+ # [2, 9],
498
+ # [9, 10],
499
+ # [10, 11], # right leg
500
+ # [2, 12],
501
+ # [12, 13],
502
+ # [13, 14], # left leg
503
+ # [2, 1],
504
+ [1, 15],
505
+ [15, 17],
506
+ [1, 16],
507
+ [16, 18], # face (nose, eyes, ears)
508
+ # [14, 19],
509
+ # [11, 20], # foot
510
+ ]
511
+
512
+ colors = [
513
+ # [255, 0, 0],
514
+ # [255, 85, 0],
515
+ # [255, 170, 0],
516
+ # [255, 255, 0],
517
+ # [170, 255, 0],
518
+ # [85, 255, 0],
519
+ # [0, 255, 0],
520
+ # [0, 255, 85],
521
+ # [0, 255, 170],
522
+ # [0, 255, 255],
523
+ # [0, 170, 255],
524
+ # [0, 85, 255],
525
+ # [0, 0, 255],
526
+ # [85, 0, 255],
527
+ [170, 0, 255],
528
+ # [255, 0, 255],
529
+ # [255, 0, 170],
530
+ # [255, 0, 85],
531
+ # foot
532
+ # [200, 200, 0],
533
+ # [100, 100, 0],
534
+ ]
535
+
536
+ H, W, C = img.shape
537
+ stickwidth = max(int(min(H, W) / stick_width_norm), 1)
538
+
539
+ # for _idx, ((k1_index, k2_index), color) in enumerate(zip(limbSeq, colors)):
540
+ # keypoint1 = kp2ds_body[k1_index - 1]
541
+ # keypoint2 = kp2ds_body[k2_index - 1]
542
+
543
+ # if keypoint1[-1] < threshold or keypoint2[-1] < threshold:
544
+ # continue
545
+
546
+ # Y = np.array([keypoint1[0], keypoint2[0]])
547
+ # X = np.array([keypoint1[1], keypoint2[1]])
548
+ # mX = np.mean(X)
549
+ # mY = np.mean(Y)
550
+ # length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
551
+ # angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
552
+ # polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth), int(angle), 0, 360, 1)
553
+ # cv2.fillConvexPoly(img, polygon, [int(float(c) * 0.6) for c in color])
554
+
555
+ for _idx, (keypoint, color) in enumerate(zip(kp2ds_body, colors)):
556
+ if keypoint[-1] < threshold:
557
+ continue
558
+ x, y = keypoint[0], keypoint[1]
559
+ # cv2.circle(canvas, (int(x), int(y)), 4, color, thickness=-1)
560
+ cv2.circle(img, (int(x), int(y)), stickwidth, color, thickness=-1)
561
+
562
+ if draw_hand:
563
+ img = draw_handpose(img, kp2ds_lhand, hand_score_th=threshold)
564
+ img = draw_handpose(img, kp2ds_rhand, hand_score_th=threshold)
565
+
566
+ kp2ds_body[:, 0] /= W
567
+ kp2ds_body[:, 1] /= H
568
+
569
+ if data_to_json is not None:
570
+ if idx == -1:
571
+ data_to_json.append(
572
+ {
573
+ "image_id": "frame_{:05d}.jpg".format(len(data_to_json) + 1),
574
+ "height": H,
575
+ "width": W,
576
+ "category_id": 1,
577
+ "keypoints_body": kp2ds_body.tolist(),
578
+ "keypoints_left_hand": kp2ds_lhand.tolist(),
579
+ "keypoints_right_hand": kp2ds_rhand.tolist(),
580
+ }
581
+ )
582
+ else:
583
+ data_to_json[idx] = {
584
+ "image_id": "frame_{:05d}.jpg".format(idx + 1),
585
+ "height": H,
586
+ "width": W,
587
+ "category_id": 1,
588
+ "keypoints_body": kp2ds_body.tolist(),
589
+ "keypoints_left_hand": kp2ds_lhand.tolist(),
590
+ "keypoints_right_hand": kp2ds_rhand.tolist(),
591
+ }
592
+ return img
593
+
594
+
595
+ def draw_aapose(
596
+ img,
597
+ kp2ds,
598
+ threshold=0.6,
599
+ data_to_json=None,
600
+ idx=-1,
601
+ kp2ds_lhand=None,
602
+ kp2ds_rhand=None,
603
+ draw_hand=False,
604
+ stick_width_norm=200,
605
+ draw_head=True
606
+ ):
607
+ """
608
+ Draw keypoints and connections representing hand pose on a given canvas.
609
+
610
+ Args:
611
+ canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
612
+ keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
613
+ or None if no keypoints are present.
614
+
615
+ Returns:
616
+ np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
617
+
618
+ Note:
619
+ The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
620
+ """
621
+
622
+ new_kep_list = [
623
+ "Nose",
624
+ "Neck",
625
+ "RShoulder",
626
+ "RElbow",
627
+ "RWrist", # No.4
628
+ "LShoulder",
629
+ "LElbow",
630
+ "LWrist", # No.7
631
+ "RHip",
632
+ "RKnee",
633
+ "RAnkle", # No.10
634
+ "LHip",
635
+ "LKnee",
636
+ "LAnkle", # No.13
637
+ "REye",
638
+ "LEye",
639
+ "REar",
640
+ "LEar",
641
+ "LToe",
642
+ "RToe",
643
+ ]
644
+ # kp2ds_body = (kp2ds.copy()[[0, 6, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 17, 20]] + \
645
+ # kp2ds.copy()[[0, 5, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 18, 21]]) / 2
646
+ kp2ds = kp2ds.copy()
647
+ if not draw_head:
648
+ kp2ds[[0,14,15,16,17], 2] = 0
649
+ kp2ds_body = kp2ds
650
+
651
+ # kp2ds_lhand = kp2ds.copy()[91:112]
652
+ # kp2ds_rhand = kp2ds.copy()[112:133]
653
+
654
+ limbSeq = [
655
+ [2, 3],
656
+ [2, 6], # shoulders
657
+ [3, 4],
658
+ [4, 5], # left arm
659
+ [6, 7],
660
+ [7, 8], # right arm
661
+ [2, 9],
662
+ [9, 10],
663
+ [10, 11], # right leg
664
+ [2, 12],
665
+ [12, 13],
666
+ [13, 14], # left leg
667
+ [2, 1],
668
+ [1, 15],
669
+ [15, 17],
670
+ [1, 16],
671
+ [16, 18], # face (nose, eyes, ears)
672
+ [14, 19],
673
+ [11, 20], # foot
674
+ ]
675
+
676
+ colors = [
677
+ [255, 0, 0],
678
+ [255, 85, 0],
679
+ [255, 170, 0],
680
+ [255, 255, 0],
681
+ [170, 255, 0],
682
+ [85, 255, 0],
683
+ [0, 255, 0],
684
+ [0, 255, 85],
685
+ [0, 255, 170],
686
+ [0, 255, 255],
687
+ [0, 170, 255],
688
+ [0, 85, 255],
689
+ [0, 0, 255],
690
+ [85, 0, 255],
691
+ [170, 0, 255],
692
+ [255, 0, 255],
693
+ [255, 0, 170],
694
+ [255, 0, 85],
695
+ # foot
696
+ [200, 200, 0],
697
+ [100, 100, 0],
698
+ ]
699
+
700
+ H, W, C = img.shape
701
+ stickwidth = max(int(min(H, W) / stick_width_norm), 1)
702
+
703
+ for _idx, ((k1_index, k2_index), color) in enumerate(zip(limbSeq, colors)):
704
+ keypoint1 = kp2ds_body[k1_index - 1]
705
+ keypoint2 = kp2ds_body[k2_index - 1]
706
+
707
+ if keypoint1[-1] < threshold or keypoint2[-1] < threshold:
708
+ continue
709
+
710
+ Y = np.array([keypoint1[0], keypoint2[0]])
711
+ X = np.array([keypoint1[1], keypoint2[1]])
712
+ mX = np.mean(X)
713
+ mY = np.mean(Y)
714
+ length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
715
+ angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
716
+ polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth), int(angle), 0, 360, 1)
717
+ cv2.fillConvexPoly(img, polygon, [int(float(c) * 0.6) for c in color])
718
+
719
+ for _idx, (keypoint, color) in enumerate(zip(kp2ds_body, colors)):
720
+ if keypoint[-1] < threshold:
721
+ continue
722
+ x, y = keypoint[0], keypoint[1]
723
+ # cv2.circle(canvas, (int(x), int(y)), 4, color, thickness=-1)
724
+ cv2.circle(img, (int(x), int(y)), stickwidth, color, thickness=-1)
725
+
726
+ if draw_hand:
727
+ img = draw_handpose(img, kp2ds_lhand, hand_score_th=threshold)
728
+ img = draw_handpose(img, kp2ds_rhand, hand_score_th=threshold)
729
+
730
+ kp2ds_body[:, 0] /= W
731
+ kp2ds_body[:, 1] /= H
732
+
733
+ if data_to_json is not None:
734
+ if idx == -1:
735
+ data_to_json.append(
736
+ {
737
+ "image_id": "frame_{:05d}.jpg".format(len(data_to_json) + 1),
738
+ "height": H,
739
+ "width": W,
740
+ "category_id": 1,
741
+ "keypoints_body": kp2ds_body.tolist(),
742
+ "keypoints_left_hand": kp2ds_lhand.tolist(),
743
+ "keypoints_right_hand": kp2ds_rhand.tolist(),
744
+ }
745
+ )
746
+ else:
747
+ data_to_json[idx] = {
748
+ "image_id": "frame_{:05d}.jpg".format(idx + 1),
749
+ "height": H,
750
+ "width": W,
751
+ "category_id": 1,
752
+ "keypoints_body": kp2ds_body.tolist(),
753
+ "keypoints_left_hand": kp2ds_lhand.tolist(),
754
+ "keypoints_right_hand": kp2ds_rhand.tolist(),
755
+ }
756
+ return img
757
+
758
+
759
+ def draw_aapose_new(
760
+ img,
761
+ kp2ds,
762
+ threshold=0.6,
763
+ data_to_json=None,
764
+ idx=-1,
765
+ kp2ds_lhand=None,
766
+ kp2ds_rhand=None,
767
+ draw_hand=False,
768
+ stickwidth_type='v2',
769
+ draw_head=True
770
+ ):
771
+ """
772
+ Draw keypoints and connections representing hand pose on a given canvas.
773
+
774
+ Args:
775
+ canvas (np.ndarray): A 3D numpy array representing the canvas (image) on which to draw the hand pose.
776
+ keypoints (List[Keypoint]| None): A list of Keypoint objects representing the hand keypoints to be drawn
777
+ or None if no keypoints are present.
778
+
779
+ Returns:
780
+ np.ndarray: A 3D numpy array representing the modified canvas with the drawn hand pose.
781
+
782
+ Note:
783
+ The function expects the x and y coordinates of the keypoints to be normalized between 0 and 1.
784
+ """
785
+
786
+ new_kep_list = [
787
+ "Nose",
788
+ "Neck",
789
+ "RShoulder",
790
+ "RElbow",
791
+ "RWrist", # No.4
792
+ "LShoulder",
793
+ "LElbow",
794
+ "LWrist", # No.7
795
+ "RHip",
796
+ "RKnee",
797
+ "RAnkle", # No.10
798
+ "LHip",
799
+ "LKnee",
800
+ "LAnkle", # No.13
801
+ "REye",
802
+ "LEye",
803
+ "REar",
804
+ "LEar",
805
+ "LToe",
806
+ "RToe",
807
+ ]
808
+ # kp2ds_body = (kp2ds.copy()[[0, 6, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 17, 20]] + \
809
+ # kp2ds.copy()[[0, 5, 6, 8, 10, 5, 7, 9, 12, 14, 16, 11, 13, 15, 2, 1, 4, 3, 18, 21]]) / 2
810
+ kp2ds = kp2ds.copy()
811
+ if not draw_head:
812
+ kp2ds[[0,14,15,16,17], 2] = 0
813
+ kp2ds_body = kp2ds
814
+
815
+ # kp2ds_lhand = kp2ds.copy()[91:112]
816
+ # kp2ds_rhand = kp2ds.copy()[112:133]
817
+
818
+ limbSeq = [
819
+ [2, 3],
820
+ [2, 6], # shoulders
821
+ [3, 4],
822
+ [4, 5], # left arm
823
+ [6, 7],
824
+ [7, 8], # right arm
825
+ [2, 9],
826
+ [9, 10],
827
+ [10, 11], # right leg
828
+ [2, 12],
829
+ [12, 13],
830
+ [13, 14], # left leg
831
+ [2, 1],
832
+ [1, 15],
833
+ [15, 17],
834
+ [1, 16],
835
+ [16, 18], # face (nose, eyes, ears)
836
+ [14, 19],
837
+ [11, 20], # foot
838
+ ]
839
+
840
+ colors = [
841
+ [255, 0, 0],
842
+ [255, 85, 0],
843
+ [255, 170, 0],
844
+ [255, 255, 0],
845
+ [170, 255, 0],
846
+ [85, 255, 0],
847
+ [0, 255, 0],
848
+ [0, 255, 85],
849
+ [0, 255, 170],
850
+ [0, 255, 255],
851
+ [0, 170, 255],
852
+ [0, 85, 255],
853
+ [0, 0, 255],
854
+ [85, 0, 255],
855
+ [170, 0, 255],
856
+ [255, 0, 255],
857
+ [255, 0, 170],
858
+ [255, 0, 85],
859
+ # foot
860
+ [200, 200, 0],
861
+ [100, 100, 0],
862
+ ]
863
+
864
+ H, W, C = img.shape
865
+ H, W, C = img.shape
866
+
867
+ if stickwidth_type == 'v1':
868
+ stickwidth = max(int(min(H, W) / 200), 1)
869
+ elif stickwidth_type == 'v2':
870
+ stickwidth = max(int(min(H, W) / 200) - 1, 1)
871
+ else:
872
+ raise
873
+
874
+ for _idx, ((k1_index, k2_index), color) in enumerate(zip(limbSeq, colors)):
875
+ keypoint1 = kp2ds_body[k1_index - 1]
876
+ keypoint2 = kp2ds_body[k2_index - 1]
877
+
878
+ if keypoint1[-1] < threshold or keypoint2[-1] < threshold:
879
+ continue
880
+
881
+ Y = np.array([keypoint1[0], keypoint2[0]])
882
+ X = np.array([keypoint1[1], keypoint2[1]])
883
+ mX = np.mean(X)
884
+ mY = np.mean(Y)
885
+ length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
886
+ angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
887
+ polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth), int(angle), 0, 360, 1)
888
+ cv2.fillConvexPoly(img, polygon, [int(float(c) * 0.6) for c in color])
889
+
890
+ for _idx, (keypoint, color) in enumerate(zip(kp2ds_body, colors)):
891
+ if keypoint[-1] < threshold:
892
+ continue
893
+ x, y = keypoint[0], keypoint[1]
894
+ # cv2.circle(canvas, (int(x), int(y)), 4, color, thickness=-1)
895
+ cv2.circle(img, (int(x), int(y)), stickwidth, color, thickness=-1)
896
+
897
+ if draw_hand:
898
+ img = draw_handpose_new(img, kp2ds_lhand, stickwidth_type=stickwidth_type, hand_score_th=threshold)
899
+ img = draw_handpose_new(img, kp2ds_rhand, stickwidth_type=stickwidth_type, hand_score_th=threshold)
900
+
901
+ kp2ds_body[:, 0] /= W
902
+ kp2ds_body[:, 1] /= H
903
+
904
+ if data_to_json is not None:
905
+ if idx == -1:
906
+ data_to_json.append(
907
+ {
908
+ "image_id": "frame_{:05d}.jpg".format(len(data_to_json) + 1),
909
+ "height": H,
910
+ "width": W,
911
+ "category_id": 1,
912
+ "keypoints_body": kp2ds_body.tolist(),
913
+ "keypoints_left_hand": kp2ds_lhand.tolist(),
914
+ "keypoints_right_hand": kp2ds_rhand.tolist(),
915
+ }
916
+ )
917
+ else:
918
+ data_to_json[idx] = {
919
+ "image_id": "frame_{:05d}.jpg".format(idx + 1),
920
+ "height": H,
921
+ "width": W,
922
+ "category_id": 1,
923
+ "keypoints_body": kp2ds_body.tolist(),
924
+ "keypoints_left_hand": kp2ds_lhand.tolist(),
925
+ "keypoints_right_hand": kp2ds_rhand.tolist(),
926
+ }
927
+ return img
928
+
929
+
930
+ def draw_bbox(img, bbox, color=(255, 0, 0)):
931
+ img = load_image(img)
932
+ bbox = [int(bbox_tmp) for bbox_tmp in bbox]
933
+ cv2.rectangle(img, (bbox[0], bbox[1]), (bbox[2], bbox[3]), color, 2)
934
+ return img
935
+
936
+
937
+ def draw_kp2ds(img, kp2ds, threshold=0, color=(255, 0, 0), skeleton=None, reverse=False):
938
+ img = load_image(img, reverse)
939
+
940
+ if skeleton is not None:
941
+ if skeleton == "coco17":
942
+ skeleton_list = [
943
+ [6, 8],
944
+ [8, 10],
945
+ [5, 7],
946
+ [7, 9],
947
+ [11, 13],
948
+ [13, 15],
949
+ [12, 14],
950
+ [14, 16],
951
+ [5, 6],
952
+ [6, 12],
953
+ [12, 11],
954
+ [11, 5],
955
+ ]
956
+ color_list = [
957
+ (255, 0, 0),
958
+ (0, 255, 0),
959
+ (0, 0, 255),
960
+ (255, 255, 0),
961
+ (255, 0, 255),
962
+ (0, 255, 255),
963
+ ]
964
+ elif skeleton == "cocowholebody":
965
+ skeleton_list = [
966
+ [6, 8],
967
+ [8, 10],
968
+ [5, 7],
969
+ [7, 9],
970
+ [11, 13],
971
+ [13, 15],
972
+ [12, 14],
973
+ [14, 16],
974
+ [5, 6],
975
+ [6, 12],
976
+ [12, 11],
977
+ [11, 5],
978
+ [15, 17],
979
+ [15, 18],
980
+ [15, 19],
981
+ [16, 20],
982
+ [16, 21],
983
+ [16, 22],
984
+ [91, 92, 93, 94, 95],
985
+ [91, 96, 97, 98, 99],
986
+ [91, 100, 101, 102, 103],
987
+ [91, 104, 105, 106, 107],
988
+ [91, 108, 109, 110, 111],
989
+ [112, 113, 114, 115, 116],
990
+ [112, 117, 118, 119, 120],
991
+ [112, 121, 122, 123, 124],
992
+ [112, 125, 126, 127, 128],
993
+ [112, 129, 130, 131, 132],
994
+ ]
995
+ color_list = [
996
+ (255, 0, 0),
997
+ (0, 255, 0),
998
+ (0, 0, 255),
999
+ (255, 255, 0),
1000
+ (255, 0, 255),
1001
+ (0, 255, 255),
1002
+ ]
1003
+ else:
1004
+ color_list = [color]
1005
+ for _idx, _skeleton in enumerate(skeleton_list):
1006
+ for i in range(len(_skeleton) - 1):
1007
+ cv2.line(
1008
+ img,
1009
+ (int(kp2ds[_skeleton[i], 0]), int(kp2ds[_skeleton[i], 1])),
1010
+ (int(kp2ds[_skeleton[i + 1], 0]), int(kp2ds[_skeleton[i + 1], 1])),
1011
+ color_list[_idx % len(color_list)],
1012
+ 3,
1013
+ )
1014
+
1015
+ for _idx, kp2d in enumerate(kp2ds):
1016
+ if kp2d[2] > threshold:
1017
+ cv2.circle(img, (int(kp2d[0]), int(kp2d[1])), 3, color, -1)
1018
+ # cv2.putText(img,
1019
+ # str(_idx),
1020
+ # (int(kp2d[0, i, 0])*1,
1021
+ # int(kp2d[0, i, 1])*1),
1022
+ # cv2.FONT_HERSHEY_SIMPLEX,
1023
+ # 0.75,
1024
+ # color,
1025
+ # 2
1026
+ # )
1027
+
1028
+ return img
1029
+
1030
+
1031
+ def draw_mask(img, mask, background=0, return_rgba=False):
1032
+ img = load_image(img)
1033
+ h, w, _ = img.shape
1034
+ if type(background) == int:
1035
+ background = np.ones((h, w, 3)).astype(np.uint8) * 255 * background
1036
+ backgournd = cv2.resize(background, (w, h))
1037
+ img_rgba = np.concatenate([img, mask], -1)
1038
+ return alphaMerge(img_rgba, background, 0, 0, return_rgba=True)
1039
+
1040
+
1041
+ def draw_pcd(pcd_list, save_path=None):
1042
+ import matplotlib.pyplot as plt # noqa: F811 - only for this unused debug helper
1043
+
1044
+ fig = plt.figure()
1045
+ ax = fig.add_subplot(111, projection="3d")
1046
+
1047
+ color_list = ["r", "g", "b", "y", "p"]
1048
+
1049
+ for _idx, _pcd in enumerate(pcd_list):
1050
+ ax.scatter(_pcd[:, 0], _pcd[:, 1], _pcd[:, 2], c=color_list[_idx], marker="o")
1051
+
1052
+ ax.set_xlabel("X")
1053
+ ax.set_ylabel("Y")
1054
+ ax.set_zlabel("Z")
1055
+
1056
+ if save_path is not None:
1057
+ plt.savefig(save_path)
1058
+ else:
1059
+ plt.savefig("tmp.png")
1060
+
1061
+
1062
+ def load_image(img, reverse=False):
1063
+ if type(img) == str:
1064
+ img = cv2.imread(img)
1065
+ if reverse:
1066
+ img = img.astype(np.float32)
1067
+ img = img[:, :, ::-1]
1068
+ img = img.astype(np.uint8)
1069
+ return img
1070
+
1071
+
1072
+ def draw_skeleten(meta):
1073
+ kps = []
1074
+ for i, kp in enumerate(meta["keypoints_body"]):
1075
+ if kp is None:
1076
+ # if kp is None:
1077
+ kps.append([0, 0, 0])
1078
+ else:
1079
+ kps.append([*kp, 1])
1080
+ kps = np.array(kps)
1081
+
1082
+ kps[:, 0] *= meta["width"]
1083
+ kps[:, 1] *= meta["height"]
1084
+ pose_img = np.zeros([meta["height"], meta["width"], 3], dtype=np.uint8)
1085
+
1086
+ pose_img = draw_aapose(
1087
+ pose_img,
1088
+ kps,
1089
+ draw_hand=True,
1090
+ kp2ds_lhand=meta["keypoints_left_hand"],
1091
+ kp2ds_rhand=meta["keypoints_right_hand"],
1092
+ )
1093
+ return pose_img
1094
+
1095
+
1096
+ def draw_skeleten_with_pncc(pncc: np.ndarray, meta: Dict) -> np.ndarray:
1097
+ """
1098
+ Args:
1099
+ pncc: [H,W,3]
1100
+ meta: required keys: keypoints_body: [N, 3] keypoints_left_hand, keypoints_right_hand
1101
+ Return:
1102
+ np.ndarray [H, W, 3]
1103
+ """
1104
+ # preprocess keypoints
1105
+ kps = []
1106
+ for i, kp in enumerate(meta["keypoints_body"]):
1107
+ if kp is None:
1108
+ # if kp is None:
1109
+ kps.append([0, 0, 0])
1110
+ elif i in [14, 15, 16, 17]:
1111
+ kps.append([0, 0, 0])
1112
+ else:
1113
+ kps.append([*kp])
1114
+ kps = np.stack(kps)
1115
+
1116
+ kps[:, 0] *= pncc.shape[1]
1117
+ kps[:, 1] *= pncc.shape[0]
1118
+
1119
+ # draw neck
1120
+ canvas = np.zeros_like(pncc)
1121
+ if kps[0][2] > 0.6 and kps[1][2] > 0.6:
1122
+ canvas = draw_ellipse_by_2kp(canvas, kps[0], kps[1], [0, 0, 255])
1123
+
1124
+ # draw pncc
1125
+ mask = (pncc > 0).max(axis=2)
1126
+ canvas[mask] = pncc[mask]
1127
+ pncc = canvas
1128
+
1129
+ # draw other skeleten
1130
+ kps[0] = 0
1131
+
1132
+ meta["keypoints_left_hand"][:, 0] *= meta["width"]
1133
+ meta["keypoints_left_hand"][:, 1] *= meta["height"]
1134
+
1135
+ meta["keypoints_right_hand"][:, 0] *= meta["width"]
1136
+ meta["keypoints_right_hand"][:, 1] *= meta["height"]
1137
+ pose_img = draw_aapose(
1138
+ pncc,
1139
+ kps,
1140
+ draw_hand=True,
1141
+ kp2ds_lhand=meta["keypoints_left_hand"],
1142
+ kp2ds_rhand=meta["keypoints_right_hand"],
1143
+ )
1144
+ return pose_img
1145
+
1146
+
1147
+ FACE_CUSTOM_STYLE = {
1148
+ "eyeball": {"indexs": [68, 69], "color": [255, 255, 255], "connect": False},
1149
+ "left_eyebrow": {"indexs": [17, 18, 19, 20, 21], "color": [0, 255, 0]},
1150
+ "right_eyebrow": {"indexs": [22, 23, 24, 25, 26], "color": [0, 0, 255]},
1151
+ "left_eye": {"indexs": [36, 37, 38, 39, 40, 41], "color": [255, 255, 0], "close": True},
1152
+ "right_eye": {"indexs": [42, 43, 44, 45, 46, 47], "color": [255, 0, 255], "close": True},
1153
+ "mouth_outside": {"indexs": list(range(48, 60)), "color": [100, 255, 50], "close": True},
1154
+ "mouth_inside": {"indexs": [60, 61, 62, 63, 64, 65, 66, 67], "color": [255, 100, 50], "close": True},
1155
+ }
1156
+
1157
+
1158
+ def draw_face_kp(img, kps, thickness=2, style=FACE_CUSTOM_STYLE):
1159
+ """
1160
+ Args:
1161
+ img: [H, W, 3]
1162
+ kps: [70, 2]
1163
+ """
1164
+ img = img.copy()
1165
+ for key, item in style.items():
1166
+ pts = np.array(kps[item["indexs"]]).astype(np.int32)
1167
+ connect = item.get("connect", True)
1168
+ color = item["color"]
1169
+ close = item.get("close", False)
1170
+ if connect:
1171
+ cv2.polylines(img, [pts], close, color, thickness=thickness)
1172
+ else:
1173
+ for kp in pts:
1174
+ kp = np.array(kp).astype(np.int32)
1175
+ cv2.circle(img, kp, thickness * 2, color=color, thickness=-1)
1176
+ return img
1177
+
1178
+
1179
+ def draw_traj(metas: List[AAPoseMeta], threshold=0.6):
1180
+
1181
+ colors = [[255, 0, 0], [255, 85, 0], [255, 170, 0], [255, 255, 0], [170, 255, 0], [85, 255, 0], [0, 255, 0], \
1182
+ [0, 255, 85], [0, 255, 170], [0, 255, 255], [0, 170, 255], [0, 85, 255], [0, 0, 255], [85, 0, 255], \
1183
+ [170, 0, 255], [255, 0, 255], [255, 0, 170], [255, 0, 85], [100, 255, 50], [255, 100, 50],
1184
+ # foot
1185
+ [200, 200, 0],
1186
+ [100, 100, 0]
1187
+ ]
1188
+ limbSeq = [
1189
+ [1, 2], [1, 5], # shoulders
1190
+ [2, 3], [3, 4], # left arm
1191
+ [5, 6], [6, 7], # right arm
1192
+ [1, 8], [8, 9], [9, 10], # right leg
1193
+ [1, 11], [11, 12], [12, 13], # left leg
1194
+ # face (nose, eyes, ears)
1195
+ [13, 18], [10, 19] # foot
1196
+ ]
1197
+
1198
+ face_seq = [[1, 0], [0, 14], [14, 16], [0, 15], [15, 17]]
1199
+ kp_body = np.array([meta.kps_body for meta in metas])
1200
+ kp_body_p = np.array([meta.kps_body_p for meta in metas])
1201
+
1202
+
1203
+ face_seq = random.sample(face_seq, 2)
1204
+
1205
+ kp_lh = np.array([meta.kps_lhand for meta in metas])
1206
+ kp_rh = np.array([meta.kps_rhand for meta in metas])
1207
+
1208
+ kp_lh_p = np.array([meta.kps_lhand_p for meta in metas])
1209
+ kp_rh_p = np.array([meta.kps_rhand_p for meta in metas])
1210
+
1211
+ # kp_lh = np.concatenate([kp_lh, kp_lh_p], axis=-1)
1212
+ # kp_rh = np.concatenate([kp_rh, kp_rh_p], axis=-1)
1213
+
1214
+ new_limbSeq = []
1215
+ key_point_list = []
1216
+ for _idx, ((k1_index, k2_index)) in enumerate(limbSeq):
1217
+
1218
+ vis = (kp_body_p[:, k1_index] > threshold) * (kp_body_p[:, k2_index] > threshold) * 1
1219
+ if vis.sum() * 1.0 / vis.shape[0] > 0.4:
1220
+ new_limbSeq.append([k1_index, k2_index])
1221
+
1222
+ for _idx, ((k1_index, k2_index)) in enumerate(limbSeq):
1223
+
1224
+ keypoint1 = kp_body[:, k1_index - 1]
1225
+ keypoint2 = kp_body[:, k2_index - 1]
1226
+ interleave = random.randint(4, 7)
1227
+ randind = random.randint(0, interleave - 1)
1228
+ # randind = random.rand(range(interleave), sampling_num)
1229
+
1230
+ Y = np.array([keypoint1[:, 0], keypoint2[:, 0]])
1231
+ X = np.array([keypoint1[:, 1], keypoint2[:, 1]])
1232
+
1233
+ vis = (keypoint1[:, -1] > threshold) * (keypoint2[:, -1] > threshold) * 1
1234
+
1235
+ # for randidx in randind:
1236
+ t = randind / interleave
1237
+ x = (1-t)*Y[0, :] + t*Y[1, :]
1238
+ y = (1-t)*X[0, :] + t*X[1, :]
1239
+
1240
+ # np.array([1])
1241
+ x = x.astype(int)
1242
+ y = y.astype(int)
1243
+
1244
+ new_array = np.array([x, y, vis]).T
1245
+
1246
+ key_point_list.append(new_array)
1247
+
1248
+ indx_lh = random.randint(0, kp_lh.shape[1] - 1)
1249
+ lh = kp_lh[:, indx_lh, :]
1250
+ lh_p = kp_lh_p[:, indx_lh:indx_lh+1]
1251
+ lh = np.concatenate([lh, lh_p], axis=-1)
1252
+
1253
+ indx_rh = random.randint(0, kp_rh.shape[1] - 1)
1254
+ rh = kp_rh[:, random.randint(0, kp_rh.shape[1] - 1), :]
1255
+ rh_p = kp_rh_p[:, indx_rh:indx_rh+1]
1256
+ rh = np.concatenate([rh, rh_p], axis=-1)
1257
+
1258
+
1259
+
1260
+ lh[-1, :] = (lh[-1, :] > threshold) * 1
1261
+ rh[-1, :] = (rh[-1, :] > threshold) * 1
1262
+
1263
+ # print(rh.shape, new_array.shape)
1264
+ # exit()
1265
+ key_point_list.append(lh.astype(int))
1266
+ key_point_list.append(rh.astype(int))
1267
+
1268
+
1269
+ key_points_list = np.stack(key_point_list)
1270
+ num_points = len(key_points_list)
1271
+ sample_colors = random.sample(colors, num_points)
1272
+
1273
+ stickwidth = max(int(min(metas[0].width, metas[0].height) / 150), 2)
1274
+
1275
+ image_list_ori = []
1276
+ for i in range(key_points_list.shape[-2]):
1277
+ _image_vis = np.zeros((metas[0].width, metas[0].height, 3))
1278
+ points = key_points_list[:, i, :]
1279
+ for idx, point in enumerate(points):
1280
+ x, y, vis = point
1281
+ if vis == 1:
1282
+ cv2.circle(_image_vis, (x, y), stickwidth, sample_colors[idx], thickness=-1)
1283
+
1284
+ image_list_ori.append(_image_vis)
1285
+
1286
+ return image_list_ori
1287
+
1288
+ return [np.zeros([meta.width, meta.height, 3], dtype=np.uint8) for meta in metas]
1289
+
1290
+
1291
+ if __name__ == "__main__":
1292
+ meta = {
1293
+ "image_id": "00472.jpg",
1294
+ "height": 540,
1295
+ "width": 414,
1296
+ "category_id": 1,
1297
+ "keypoints_body": [
1298
+ [0.5084776947463768, 0.11350188078703703],
1299
+ [0.504467655495169, 0.20419560185185184],
1300
+ [0.3982016153381642, 0.198046875],
1301
+ [0.3841664779589372, 0.34869068287037036],
1302
+ [0.3901815368357488, 0.4670536747685185],
1303
+ [0.610733695652174, 0.2103443287037037],
1304
+ [0.6167487545289855, 0.3517650462962963],
1305
+ [0.6448190292874396, 0.4762767650462963],
1306
+ [0.4523371452294686, 0.47320240162037036],
1307
+ [0.4503321256038647, 0.6776475694444445],
1308
+ [0.47639738073671495, 0.8544234664351852],
1309
+ [0.5766483620169082, 0.47320240162037036],
1310
+ [0.5666232638888888, 0.6761103877314815],
1311
+ [0.534542949879227, 0.863646556712963],
1312
+ [0.4864224788647343, 0.09505570023148148],
1313
+ [0.5285278910024155, 0.09351851851851851],
1314
+ [0.46236224335748793, 0.10581597222222222],
1315
+ [0.5586031853864735, 0.10274160879629629],
1316
+ [0.4994551064311594, 0.9405056423611111],
1317
+ [0.4152442821557971, 0.9312825520833333],
1318
+ ],
1319
+ "keypoints_left_hand": [
1320
+ [267.78515625, 263.830078125, 1.2840936183929443],
1321
+ [265.294921875, 269.640625, 1.2546794414520264],
1322
+ [263.634765625, 277.111328125, 1.2863062620162964],
1323
+ [262.8046875, 285.412109375, 1.267038345336914],
1324
+ [261.14453125, 292.8828125, 1.280144453048706],
1325
+ [273.595703125, 281.26171875, 1.2592815160751343],
1326
+ [271.10546875, 291.22265625, 1.3256099224090576],
1327
+ [265.294921875, 294.54296875, 1.2368024587631226],
1328
+ [261.14453125, 294.54296875, 0.9771889448165894],
1329
+ [274.42578125, 282.091796875, 1.250044584274292],
1330
+ [269.4453125, 291.22265625, 1.2571144104003906],
1331
+ [264.46484375, 292.8828125, 1.177802324295044],
1332
+ [260.314453125, 292.052734375, 0.9283463358879089],
1333
+ [273.595703125, 282.091796875, 1.1834490299224854],
1334
+ [269.4453125, 290.392578125, 1.188171625137329],
1335
+ [265.294921875, 290.392578125, 1.192609429359436],
1336
+ [261.974609375, 289.5625, 0.9366656541824341],
1337
+ [271.935546875, 281.26171875, 1.0946396589279175],
1338
+ [268.615234375, 287.072265625, 0.9906131029129028],
1339
+ [265.294921875, 287.90234375, 1.0219476222991943],
1340
+ [262.8046875, 287.072265625, 0.9240120053291321],
1341
+ ],
1342
+ "keypoints_right_hand": [
1343
+ [161.53515625, 258.849609375, 1.2069408893585205],
1344
+ [168.17578125, 263.0, 1.1846840381622314],
1345
+ [173.986328125, 269.640625, 1.1435924768447876],
1346
+ [173.986328125, 277.94140625, 1.1802611351013184],
1347
+ [173.986328125, 286.2421875, 1.2599592208862305],
1348
+ [165.685546875, 275.451171875, 1.0633569955825806],
1349
+ [167.345703125, 286.2421875, 1.1693341732025146],
1350
+ [169.8359375, 291.22265625, 1.2698509693145752],
1351
+ [170.666015625, 294.54296875, 1.0619274377822876],
1352
+ [160.705078125, 276.28125, 1.0995020866394043],
1353
+ [163.1953125, 287.90234375, 1.2735884189605713],
1354
+ [166.515625, 291.22265625, 1.339503526687622],
1355
+ [169.005859375, 294.54296875, 1.0835273265838623],
1356
+ [157.384765625, 277.111328125, 1.0866981744766235],
1357
+ [161.53515625, 287.072265625, 1.2468621730804443],
1358
+ [164.025390625, 289.5625, 1.2817761898040771],
1359
+ [166.515625, 292.052734375, 1.099466323852539],
1360
+ [155.724609375, 277.111328125, 1.1065717935562134],
1361
+ [159.044921875, 285.412109375, 1.1924479007720947],
1362
+ [160.705078125, 287.072265625, 1.1304771900177002],
1363
+ [162.365234375, 287.90234375, 1.0040509700775146],
1364
+ ],
1365
+ }
1366
+ demo_meta = AAPoseMeta(meta)
1367
+ res = draw_traj([demo_meta]*5)
1368
+ cv2.imwrite("traj.png", res[0][..., ::-1])