fmpose3d 0.0.7__py3-none-any.whl

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 (67) hide show
  1. fmpose3d/__init__.py +38 -0
  2. fmpose3d/aggregation_methods.py +203 -0
  3. fmpose3d/animals/__init__.py +13 -0
  4. fmpose3d/animals/common/__init__.py +12 -0
  5. fmpose3d/animals/common/animal3d_dataset.py +66 -0
  6. fmpose3d/animals/common/animal_visualization.py +111 -0
  7. fmpose3d/animals/common/arber_dataset.py +315 -0
  8. fmpose3d/animals/common/arguments.py +228 -0
  9. fmpose3d/animals/common/camera.py +74 -0
  10. fmpose3d/animals/common/graph_utils.py +69 -0
  11. fmpose3d/animals/common/lifter3d.py +669 -0
  12. fmpose3d/animals/common/mocap_dataset.py +40 -0
  13. fmpose3d/animals/common/skeleton.py +88 -0
  14. fmpose3d/animals/common/utils.py +547 -0
  15. fmpose3d/animals/models/__init__.py +20 -0
  16. fmpose3d/animals/models/graph_frames.py +354 -0
  17. fmpose3d/animals/models/model_animal3d.py +245 -0
  18. fmpose3d/common/__init__.py +41 -0
  19. fmpose3d/common/arguments.py +190 -0
  20. fmpose3d/common/camera.py +74 -0
  21. fmpose3d/common/generator.py +254 -0
  22. fmpose3d/common/graph_utils.py +81 -0
  23. fmpose3d/common/h36m_dataset.py +466 -0
  24. fmpose3d/common/load_data_hm36.py +244 -0
  25. fmpose3d/common/mocap_dataset.py +40 -0
  26. fmpose3d/common/skeleton.py +88 -0
  27. fmpose3d/common/utils.py +471 -0
  28. fmpose3d/lib/__init__.py +0 -0
  29. fmpose3d/lib/checkpoint/__init__.py +0 -0
  30. fmpose3d/lib/checkpoint/download_checkpoints.py +129 -0
  31. fmpose3d/lib/hrnet/__init__.py +0 -0
  32. fmpose3d/lib/hrnet/experiments/w48_384x288_adam_lr1e-3.yaml +127 -0
  33. fmpose3d/lib/hrnet/gen_kpts.py +195 -0
  34. fmpose3d/lib/hrnet/lib/__init__.py +0 -0
  35. fmpose3d/lib/hrnet/lib/config/__init__.py +18 -0
  36. fmpose3d/lib/hrnet/lib/config/default.py +169 -0
  37. fmpose3d/lib/hrnet/lib/config/models.py +67 -0
  38. fmpose3d/lib/hrnet/lib/models/__init__.py +0 -0
  39. fmpose3d/lib/hrnet/lib/models/pose_hrnet.py +510 -0
  40. fmpose3d/lib/hrnet/lib/utils/__init__.py +0 -0
  41. fmpose3d/lib/hrnet/lib/utils/coco_h36m.py +60 -0
  42. fmpose3d/lib/hrnet/lib/utils/inference.py +91 -0
  43. fmpose3d/lib/hrnet/lib/utils/transforms.py +131 -0
  44. fmpose3d/lib/hrnet/lib/utils/utilitys.py +178 -0
  45. fmpose3d/lib/preprocess.py +113 -0
  46. fmpose3d/lib/sort/__init__.py +0 -0
  47. fmpose3d/lib/sort/sort.py +239 -0
  48. fmpose3d/lib/yolov3/__init__.py +0 -0
  49. fmpose3d/lib/yolov3/bbox.py +120 -0
  50. fmpose3d/lib/yolov3/cfg/tiny-yolo-voc.cfg +134 -0
  51. fmpose3d/lib/yolov3/cfg/yolo-voc.cfg +258 -0
  52. fmpose3d/lib/yolov3/cfg/yolo.cfg +258 -0
  53. fmpose3d/lib/yolov3/cfg/yolov3.cfg +789 -0
  54. fmpose3d/lib/yolov3/darknet.py +442 -0
  55. fmpose3d/lib/yolov3/data/coco.names +80 -0
  56. fmpose3d/lib/yolov3/data/voc.names +20 -0
  57. fmpose3d/lib/yolov3/human_detector.py +168 -0
  58. fmpose3d/lib/yolov3/preprocess.py +72 -0
  59. fmpose3d/lib/yolov3/util.py +235 -0
  60. fmpose3d/models/__init__.py +21 -0
  61. fmpose3d/models/graph_frames.py +210 -0
  62. fmpose3d/models/model_GAMLP.py +279 -0
  63. fmpose3d-0.0.7.dist-info/METADATA +156 -0
  64. fmpose3d-0.0.7.dist-info/RECORD +67 -0
  65. fmpose3d-0.0.7.dist-info/WHEEL +5 -0
  66. fmpose3d-0.0.7.dist-info/licenses/LICENSE.txt +201 -0
  67. fmpose3d-0.0.7.dist-info/top_level.txt +1 -0
fmpose3d/__init__.py ADDED
@@ -0,0 +1,38 @@
1
+ """
2
+ FMPose3D: monocular 3D Pose Estimation via Flow Matching
3
+
4
+ Official implementation of the paper:
5
+ "FMPose3D: monocular 3D Pose Estimation via Flow Matching"
6
+ by Ti Wang, Xiaohang Yu, and Mackenzie Weygandt Mathis
7
+ Licensed under Apache 2.0
8
+ """
9
+
10
+ __version__ = "0.0.7"
11
+ __author__ = "Ti Wang, Xiaohang Yu, Mackenzie Weygandt Mathis"
12
+ __license__ = "Apache 2.0"
13
+
14
+ # Import key components for easy access
15
+ from .aggregation_methods import (
16
+ average_aggregation,
17
+ aggregation_select_single_best_hypothesis_by_2D_error,
18
+ aggregation_RPEA_joint_level,
19
+ )
20
+
21
+ # Import 2D pose detection utilities
22
+ from .lib.hrnet.gen_kpts import gen_video_kpts
23
+ from .lib.preprocess import h36m_coco_format, revise_kpts
24
+
25
+ # Make commonly used classes/functions available at package level
26
+ __all__ = [
27
+ # Aggregation methods
28
+ "average_aggregation",
29
+ "aggregation_select_single_best_hypothesis_by_2D_error",
30
+ "aggregation_RPEA_joint_level",
31
+ # 2D pose detection
32
+ "gen_video_kpts",
33
+ "h36m_coco_format",
34
+ "revise_kpts",
35
+ # Version
36
+ "__version__",
37
+ ]
38
+
@@ -0,0 +1,203 @@
1
+ """
2
+ FMPose3D: monocular 3D Pose Estimation via Flow Matching
3
+
4
+ Official implementation of the paper:
5
+ "FMPose3D: monocular 3D Pose Estimation via Flow Matching"
6
+ by Ti Wang, Xiaohang Yu, and Mackenzie Weygandt Mathis
7
+ Licensed under Apache 2.0
8
+ """
9
+
10
+ import torch
11
+ from fmpose3d.common.utils import project_to_2d
12
+
13
+ def average_aggregation(list_hypothesis):
14
+ return torch.mean(torch.stack(list_hypothesis), dim=0)
15
+
16
+
17
+ def aggregation_select_single_best_hypothesis_by_2D_error(args,
18
+ list_hypothesis, batch_cam, input_2D, gt_3D
19
+ ):
20
+ """
21
+ Select per-joint 3D from the hypothesis whose 2D projection yields minimal L2 error.
22
+
23
+ Args:
24
+ list_hypothesis: list of (B,1,J,3) tensors
25
+ batch_cam: (B, 9) or (B, 1, 9) intrinsics [f(2), c(2), k(3), p(2)]
26
+ input_2D: (B, F, J, 2) 2D joints in image coordinates
27
+ gt_3D: (B, F, J, 3) used for shape metadata only
28
+ Returns:
29
+ (B,1,J,3) aggregated 3D pose with joint 0 set to 0
30
+ """
31
+ if len(list_hypothesis) == 0:
32
+ raise ValueError("list_hypothesis is empty")
33
+
34
+ device = list_hypothesis[0].device
35
+ dtype = list_hypothesis[0].dtype
36
+
37
+ # Shapes
38
+ B = gt_3D.size(0)
39
+ J = gt_3D.size(2)
40
+ F = gt_3D.size(1)
41
+ assert F >= 1, "Expected at least one frame"
42
+
43
+ # Stack hypotheses: (H,B,1,J,3) -> (B,H,J,3)
44
+ stack = torch.stack(list_hypothesis, dim=0) # (H,B,1,J,3)
45
+ X_hbj3 = stack[:, :, 0, :, :] # (H,B,J,3)
46
+ X_bhj3 = X_hbj3.transpose(0, 1).contiguous() # (B,H,J,3)
47
+ H = X_bhj3.size(1)
48
+
49
+ # Prepare camera params: (B,9)
50
+ if batch_cam.dim() == 3 and batch_cam.size(1) == 1:
51
+ cam_b9 = batch_cam[:, 0, :].contiguous()
52
+ elif batch_cam.dim() == 2 and batch_cam.size(1) == 9:
53
+ cam_b9 = batch_cam
54
+ else:
55
+ cam_b9 = batch_cam.view(B, -1)
56
+ assert cam_b9.size(1) == 9, f"camera params should be 9-dim, got {cam_b9.size()}"
57
+
58
+ # Target 2D at the same frame index as 3D selection (args.pad)
59
+ # input_2D: (B,F,J,2) -> (B,J,2)
60
+ target_2d = input_2D[:, getattr(args, "pad", 0)].contiguous() # (B,J,2)
61
+
62
+ # Convert hypotheses from root-relative to absolute camera coordinates using GT root
63
+ # Root at frame args.pad: (B,3)
64
+ gt_root = gt_3D[:, getattr(args, "pad", 0), 0, :].contiguous() # (B,3)
65
+ X_abs = X_bhj3.clone()
66
+ X_abs[:, :, 1:, :] = X_abs[:, :, 1:, :] + gt_root.unsqueeze(1).unsqueeze(1)
67
+ X_abs[:, :, 0, :] = gt_root.unsqueeze(1)
68
+
69
+ # Vectorized projection for all hypotheses in absolute coordinates
70
+ # (B,H,J,3) -> (B*H,J,3)
71
+ X_flat = X_abs.view(B * H, J, 3)
72
+ cam_rep = cam_b9.repeat_interleave(H, dim=0) # (B*H,9)
73
+
74
+ # project_to_2d expects last dim=3 and cam (N,9)
75
+ # Returns normalized coordinates (when crop_uv=0) because camera params are normalized
76
+ proj2d_flat = project_to_2d(X_flat, cam_rep) # (B*H,J,2) normalized coordinates
77
+ proj2d_bhj = proj2d_flat.view(B, H, J, 2)
78
+
79
+ # Per-hypothesis per-joint 2D error (both in normalized coordinates)
80
+ diff = proj2d_bhj - target_2d.unsqueeze(1) # (B,H,J,2)
81
+ dist = torch.norm(diff, dim=-1) # (B,H,J)
82
+
83
+ # Exclude root joint (0) due to undefined depth when using root-relative 3D
84
+ dist[:, :, 0] = float("inf")
85
+
86
+ # Argmin across hypotheses per joint
87
+ best_h = torch.argmin(dist, dim=1) # (B,J)
88
+
89
+ # Gather 3D using advanced indexing (return root-relative coordinates)
90
+ b_idx = torch.arange(B, device=device).unsqueeze(1).expand(B, J) # (B,J)
91
+ j_idx = torch.arange(J, device=device).unsqueeze(0).expand(B, J) # (B,J)
92
+ selected_bj3 = X_bhj3[b_idx, best_h, j_idx, :] # (B,J,3)
93
+
94
+ agg = selected_bj3.unsqueeze(1).to(dtype=dtype)
95
+ agg[:, :, 0, :] = 0
96
+ return agg
97
+
98
+
99
+ def aggregation_RPEA_joint_level(
100
+ args, list_hypothesis, batch_cam, input_2D, gt_3D, topk=3
101
+ ):
102
+ """
103
+ Select per-joint 3D from the hypothesis whose 2D projection yields minimal L2 error.
104
+
105
+ Args:
106
+ list_hypothesis: list of (B,1,J,3) tensors
107
+ batch_cam: (B, 9) or (B, 1, 9) intrinsics [f(2), c(2), k(3), p(2)]
108
+ input_2D: (B, F, J, 2) 2D joints in image coordinates
109
+ gt_3D: (B, F, J, 3) used for shape metadata only
110
+ Returns:
111
+ (B,1,J,3) aggregated 3D pose with joint 0 set to 0
112
+ """
113
+ if len(list_hypothesis) == 0:
114
+ raise ValueError("list_hypothesis is empty")
115
+
116
+ device = list_hypothesis[0].device
117
+ dtype = list_hypothesis[0].dtype
118
+
119
+ # Shapes
120
+ B = gt_3D.size(0)
121
+ J = gt_3D.size(2)
122
+ F = gt_3D.size(1)
123
+ assert F >= 1, "Expected at least one frame"
124
+
125
+ # Stack hypotheses: (H,B,1,J,3) -> (B,H,J,3)
126
+ stack = torch.stack(list_hypothesis, dim=0) # (H,B,1,J,3)
127
+ X_hbj3 = stack[:, :, 0, :, :] # (H,B,J,3)
128
+ X_bhj3 = X_hbj3.transpose(0, 1).contiguous() # (B,H,J,3)
129
+ H = X_bhj3.size(1)
130
+
131
+ # Prepare camera params: (B,9)
132
+ if batch_cam.dim() == 3 and batch_cam.size(1) == 1:
133
+ cam_b9 = batch_cam[:, 0, :].contiguous()
134
+ elif batch_cam.dim() == 2 and batch_cam.size(1) == 9:
135
+ cam_b9 = batch_cam
136
+ else:
137
+ cam_b9 = batch_cam.view(B, -1)
138
+ assert cam_b9.size(1) == 9, f"camera params should be 9-dim, got {cam_b9.size()}"
139
+
140
+ # Target 2D at the same frame index as 3D selection (args.pad)
141
+ # input_2D: (B,F,J,2) -> (B,J,2)
142
+ target_2d = input_2D[:, getattr(args, "pad", 0)].contiguous() # (B,J,2)
143
+
144
+ # Convert hypotheses from root-relative to absolute camera coordinates using GT root
145
+ # Root at frame args.pad: (B,3)
146
+ gt_root = gt_3D[:, getattr(args, "pad", 0), 0, :].contiguous() # (B,3)
147
+ X_abs = X_bhj3.clone()
148
+ X_abs[:, :, 1:, :] = X_abs[:, :, 1:, :] + gt_root.unsqueeze(1).unsqueeze(1)
149
+ X_abs[:, :, 0, :] = gt_root.unsqueeze(1)
150
+
151
+ # Vectorized projection for all hypotheses in absolute coordinates
152
+ # (B,H,J,3) -> (B*H,J,3)
153
+ X_flat = X_abs.view(B * H, J, 3)
154
+ cam_rep = cam_b9.repeat_interleave(H, dim=0) # (B*H,9)
155
+
156
+ # project_to_2d expects last dim=3 and cam (N,9)
157
+ proj2d_flat = project_to_2d(X_flat, cam_rep) # (B*H,J,2)
158
+ proj2d_bhj = proj2d_flat.view(B, H, J, 2)
159
+
160
+ # Per-hypothesis per-joint 2D error
161
+ diff = proj2d_bhj - target_2d.unsqueeze(1) # (B,H,J,2)
162
+ dist = torch.norm(diff, dim=-1) # (B,H,J)
163
+
164
+ # For root joint (0), avoid NaNs in softmax by setting equal distances
165
+ # This yields uniform weights at the root (we set root to 0 later anyway)
166
+ dist[:, :, 0] = 0.0
167
+
168
+ # Convert 2D losses to weights using softmax over top-k hypotheses per joint
169
+ tau = float(getattr(args, "weight_softmax_tau", 1.0))
170
+ H = dist.size(1)
171
+ k = int(getattr(args, "topk", None))
172
+ # print("k:", k)
173
+ # k = int(H//2)+1
174
+ k = max(1, min(k, H))
175
+
176
+ # top-k smallest distances along hypothesis dim
177
+ topk_vals, topk_idx = torch.topk(dist, k=k, dim=1, largest=False) # (B,k,J)
178
+
179
+ # Weight calculation method ; weight_method = 'exp'
180
+ temp = args.exp_temp
181
+ max_safe_val = temp * 20
182
+ topk_vals_clipped = torch.clamp(topk_vals, max=max_safe_val)
183
+ exp_vals = torch.exp(-topk_vals_clipped / temp)
184
+ exp_sum = exp_vals.sum(dim=1, keepdim=True)
185
+ topk_weights = exp_vals / torch.clamp(exp_sum, min=1e-10)
186
+ nan_mask = torch.isnan(topk_weights).any(dim=1, keepdim=True)
187
+ uniform_weights = torch.ones_like(topk_weights) / k
188
+ topk_weights = torch.where(
189
+ nan_mask.expand_as(topk_weights), uniform_weights, topk_weights
190
+ )
191
+
192
+ # scatter back to full H with zeros elsewhere
193
+ weights = torch.zeros_like(dist) # (B,H,J)
194
+ weights.scatter_(1, topk_idx, topk_weights)
195
+
196
+ # Weighted sum of root-relative 3D hypotheses per joint
197
+ weights_exp = weights.unsqueeze(-1) # (B,H,J,1)
198
+ weighted_bj3 = torch.sum(X_bhj3 * weights_exp, dim=1) # (B,J,3)
199
+
200
+ # Assemble output (B,1,J,3) and enforce root at origin
201
+ agg = weighted_bj3.unsqueeze(1).to(dtype=dtype)
202
+ agg[:, :, 0, :] = 0
203
+ return agg
@@ -0,0 +1,13 @@
1
+ """
2
+ FMPose3D: monocular 3D Pose Estimation via Flow Matching
3
+
4
+ Official implementation of the paper:
5
+ "FMPose3D: monocular 3D Pose Estimation via Flow Matching"
6
+ by Ti Wang, Xiaohang Yu, and Mackenzie Weygandt Mathis
7
+ Licensed under Apache 2.0
8
+ """
9
+
10
+ __all__ = [
11
+ "common",
12
+ ]
13
+
@@ -0,0 +1,12 @@
1
+ """
2
+ FMPose3D: monocular 3D Pose Estimation via Flow Matching
3
+
4
+ Official implementation of the paper:
5
+ "FMPose3D: monocular 3D Pose Estimation via Flow Matching"
6
+ by Ti Wang, Xiaohang Yu, and Mackenzie Weygandt Mathis
7
+ Licensed under Apache 2.0
8
+ """
9
+
10
+ """
11
+ Shared utilities for animal datasets and models.
12
+ """
@@ -0,0 +1,66 @@
1
+ """
2
+ FMPose3D: monocular 3D Pose Estimation via Flow Matching
3
+
4
+ Official implementation of the paper:
5
+ "FMPose3D: monocular 3D Pose Estimation via Flow Matching"
6
+ by Ti Wang, Xiaohang Yu, and Mackenzie Weygandt Mathis
7
+ Licensed under Apache 2.0
8
+ """
9
+
10
+ import json
11
+
12
+ import numpy as np
13
+ from .camera import normalize_screen_coordinates
14
+ from torch.utils.data import Dataset
15
+
16
+
17
+ class TrainDataset(Dataset):
18
+ def __init__(self, is_train: bool, json_file: str, root_joint: int = 12):
19
+ super().__init__()
20
+ self.focal_length = 1000
21
+ self.root_joint = root_joint # Root joint index for making coordinates relative
22
+
23
+ json_file = json_file
24
+ with open(json_file, "r") as f:
25
+ self.data = json.load(f)
26
+
27
+ self.is_train = is_train
28
+
29
+ def __len__(self):
30
+ return len(self.data["data"])
31
+
32
+ def __getitem__(self, item):
33
+ data = self.data["data"][item]
34
+ # safely check for reproj_kp_2d
35
+ reproj = data.get("reproj_kp_2d", None)
36
+ if reproj is not None:
37
+ keypoint_2d = np.array(reproj, dtype=np.float32)
38
+ else:
39
+ keypoint_2d = np.array(data.get("keypoint_2d", []), dtype=np.float32)
40
+ # normalize 2D keypoints
41
+ hight = np.array(data["height"])
42
+ width = np.array(data["width"])
43
+ keypoint_2d = normalize_screen_coordinates(keypoint_2d[..., :2], width, hight)
44
+
45
+ # build 3D keypoints; append ones; fallback to zeros if missing
46
+ if "keypoint_3d" in data and data["keypoint_3d"] is not None:
47
+ kp3d = np.array(data["keypoint_3d"], dtype=np.float32)
48
+ keypoint_3d = np.concatenate((kp3d, np.ones((len(kp3d), 1), dtype=np.float32)), axis=-1)
49
+ else:
50
+ keypoint_3d = np.zeros((len(keypoint_2d), 4), dtype=np.float32)
51
+
52
+ # Make 3D keypoints root-relative
53
+ if keypoint_3d.shape[0] > self.root_joint:
54
+ root_pos = keypoint_3d[self.root_joint : self.root_joint + 1, :].copy() # (1, 4)
55
+ keypoint_3d = keypoint_3d - root_pos # All joints relative to root
56
+ # Now root joint should be exactly [0,0,0,0]
57
+
58
+ bbox = data["bbox"] # [x, y, w, h]
59
+ ori_keypoint_2d = keypoint_2d.copy()
60
+
61
+ item = {
62
+ "keypoints_2d": keypoint_2d, #
63
+ "keypoints_3d": keypoint_3d,
64
+ "img_path": str(data["img_path"]),
65
+ }
66
+ return item
@@ -0,0 +1,111 @@
1
+ """
2
+ FMPose3D: monocular 3D Pose Estimation via Flow Matching
3
+
4
+ Official implementation of the paper:
5
+ "FMPose3D: monocular 3D Pose Estimation via Flow Matching"
6
+ by Ti Wang, Xiaohang Yu, and Mackenzie Weygandt Mathis
7
+ Licensed under Apache 2.0
8
+ """
9
+
10
+ import os
11
+
12
+ import cv2
13
+ import matplotlib.pyplot as plt
14
+ import numpy as np
15
+ import pandas as pd
16
+
17
+
18
+ def save_3Dpose_colored(pre_pose, gt_pose, figure_name):
19
+ fig = plt.figure()
20
+ ax1 = fig.add_subplot(211, projection="3d")
21
+ ax1.scatter(
22
+ pre_pose[:, 0], pre_pose[:, 1], pre_pose[:, 2], c=list(range(pre_pose.shape[0])), cmap="jet"
23
+ )
24
+ # plt.axis('off')
25
+ ax2 = fig.add_subplot(212, projection="3d")
26
+ ax2.scatter(
27
+ gt_pose[:, 0], gt_pose[:, 1], gt_pose[:, 2], c=list(range(gt_pose.shape[0])), cmap="jet"
28
+ )
29
+ # plt.axis('off')
30
+ plt.show()
31
+ plt.savefig(figure_name, dpi=400.0)
32
+ plt.close()
33
+
34
+
35
+ def save_absolute_3Dpose_image(image, pre_pose, gt_pose, vid_3D, skeleton, figure_name):
36
+ fig = plt.figure(figsize=(20, 9))
37
+ ax1 = fig.add_subplot(131, projection="3d")
38
+ ax1.scatter(
39
+ pre_pose[:, 0],
40
+ pre_pose[:, 2],
41
+ -pre_pose[:, 1],
42
+ c=list(range(pre_pose.shape[0])),
43
+ cmap="jet",
44
+ )
45
+ for i in range(skeleton.shape[0]):
46
+ ax1.plot(
47
+ [pre_pose[skeleton[i, 0], 0], pre_pose[skeleton[i, 1], 0]],
48
+ [pre_pose[skeleton[i, 0], 2], pre_pose[skeleton[i, 1], 2]],
49
+ [-pre_pose[skeleton[i, 0], 1], -pre_pose[skeleton[i, 1], 1]],
50
+ c="black",
51
+ )
52
+ ax1.set_xlim([-3, 3])
53
+ ax1.set_zlim([-1.5, 3])
54
+ ax1.set_ylim([12, 20])
55
+ ax1.title.set_text("Prediction")
56
+
57
+ # plt.axis('off')
58
+ ax2 = fig.add_subplot(132, projection="3d")
59
+ visiable_gt = gt_pose[np.where(vid_3D)[0], :]
60
+ ax2.scatter(
61
+ visiable_gt[:, 0],
62
+ visiable_gt[:, 2],
63
+ -visiable_gt[:, 1],
64
+ c=list(np.array(range(gt_pose.shape[0]))[np.where(vid_3D)]),
65
+ cmap="jet",
66
+ )
67
+ for i in range(skeleton.shape[0]):
68
+ if vid_3D[skeleton[i, 0]] > 0 and vid_3D[skeleton[i, 1]] > 0:
69
+ ax2.plot(
70
+ [gt_pose[skeleton[i, 0], 0], gt_pose[skeleton[i, 1], 0]],
71
+ [gt_pose[skeleton[i, 0], 2], gt_pose[skeleton[i, 1], 2]],
72
+ [-gt_pose[skeleton[i, 0], 1], -gt_pose[skeleton[i, 1], 1]],
73
+ c="black",
74
+ )
75
+ ax2.set_xlim([-3, 3])
76
+ ax2.set_zlim([-1.5, 3])
77
+ ax2.set_ylim([12, 20])
78
+ ax2.title.set_text("GT")
79
+ # plt.axis('off')
80
+ ax3 = fig.add_subplot(133)
81
+ ax3.imshow(image)
82
+ ax3.title.set_text("Camera1 view")
83
+ plt.show()
84
+ plt.savefig(figure_name, dpi=200.0)
85
+ plt.close()
86
+
87
+
88
+ def save_absolute_3Dpose(pre_pose, skeleton, figure_name):
89
+ fig = plt.figure(figsize=(20, 9))
90
+ ax1 = fig.add_subplot(111, projection="3d")
91
+ ax1.scatter(
92
+ pre_pose[:, 0],
93
+ pre_pose[:, 2],
94
+ -pre_pose[:, 1],
95
+ c=list(range(pre_pose.shape[0])),
96
+ cmap="jet",
97
+ )
98
+ for i in range(skeleton.shape[0]):
99
+ ax1.plot(
100
+ [pre_pose[skeleton[i, 0], 0], pre_pose[skeleton[i, 1], 0]],
101
+ [pre_pose[skeleton[i, 0], 2], pre_pose[skeleton[i, 1], 2]],
102
+ [-pre_pose[skeleton[i, 0], 1], -pre_pose[skeleton[i, 1], 1]],
103
+ c="black",
104
+ )
105
+ ax1.set_xlim([-1, 1])
106
+ ax1.set_zlim([-1, 1])
107
+ ax1.set_ylim([-1, 1])
108
+ ax1.title.set_text("gt")
109
+ plt.show()
110
+ plt.savefig(figure_name, dpi=200.0)
111
+ plt.close()