keypoints2body 0.1.0__tar.gz
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.
- keypoints2body-0.1.0/PKG-INFO +75 -0
- keypoints2body-0.1.0/README.md +49 -0
- keypoints2body-0.1.0/keypoints2body/__init__.py +28 -0
- keypoints2body-0.1.0/keypoints2body/api/__init__.py +8 -0
- keypoints2body-0.1.0/keypoints2body/api/frame.py +111 -0
- keypoints2body-0.1.0/keypoints2body/api/model_factory.py +31 -0
- keypoints2body-0.1.0/keypoints2body/api/sequence.py +193 -0
- keypoints2body-0.1.0/keypoints2body/cli/__init__.py +1 -0
- keypoints2body-0.1.0/keypoints2body/cli/eval.py +292 -0
- keypoints2body-0.1.0/keypoints2body/cli/fit_frame.py +31 -0
- keypoints2body-0.1.0/keypoints2body/cli/fit_seq.py +29 -0
- keypoints2body-0.1.0/keypoints2body/core/__init__.py +9 -0
- keypoints2body-0.1.0/keypoints2body/core/config.py +50 -0
- keypoints2body-0.1.0/keypoints2body/core/constants.py +63 -0
- keypoints2body-0.1.0/keypoints2body/core/engine.py +151 -0
- keypoints2body-0.1.0/keypoints2body/core/estimators/__init__.py +5 -0
- keypoints2body-0.1.0/keypoints2body/core/estimators/base.py +19 -0
- keypoints2body-0.1.0/keypoints2body/core/estimators/factory.py +36 -0
- keypoints2body-0.1.0/keypoints2body/core/estimators/optimization.py +56 -0
- keypoints2body-0.1.0/keypoints2body/core/fitters/__init__.py +4 -0
- keypoints2body-0.1.0/keypoints2body/core/fitters/camera_space.py +274 -0
- keypoints2body-0.1.0/keypoints2body/core/fitters/world_space.py +208 -0
- keypoints2body-0.1.0/keypoints2body/core/joints/__init__.py +17 -0
- keypoints2body-0.1.0/keypoints2body/core/joints/adapters.py +213 -0
- keypoints2body-0.1.0/keypoints2body/core/losses.py +93 -0
- keypoints2body-0.1.0/keypoints2body/core/prior.py +225 -0
- keypoints2body-0.1.0/keypoints2body/core/shape.py +115 -0
- keypoints2body-0.1.0/keypoints2body/io/__init__.py +3 -0
- keypoints2body-0.1.0/keypoints2body/io/motion.py +138 -0
- keypoints2body-0.1.0/keypoints2body/models/__init__.py +15 -0
- keypoints2body-0.1.0/keypoints2body/models/smpl_data.py +102 -0
- keypoints2body-0.1.0/keypoints2body.egg-info/PKG-INFO +75 -0
- keypoints2body-0.1.0/keypoints2body.egg-info/SOURCES.txt +41 -0
- keypoints2body-0.1.0/keypoints2body.egg-info/dependency_links.txt +1 -0
- keypoints2body-0.1.0/keypoints2body.egg-info/entry_points.txt +4 -0
- keypoints2body-0.1.0/keypoints2body.egg-info/requires.txt +19 -0
- keypoints2body-0.1.0/keypoints2body.egg-info/top_level.txt +1 -0
- keypoints2body-0.1.0/pyproject.toml +44 -0
- keypoints2body-0.1.0/setup.cfg +4 -0
- keypoints2body-0.1.0/tests/test_adapters.py +38 -0
- keypoints2body-0.1.0/tests/test_api_surface.py +6 -0
- keypoints2body-0.1.0/tests/test_integration_smoke.py +20 -0
- keypoints2body-0.1.0/tests/test_models.py +35 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: keypoints2body
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: SMPL/SMPLH/SMPLX optimization library for single frames and sequences
|
|
5
|
+
Author: keypoints2body contributors
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: numpy
|
|
12
|
+
Requires-Dist: torch
|
|
13
|
+
Requires-Dist: smplx
|
|
14
|
+
Requires-Dist: h5py
|
|
15
|
+
Requires-Dist: tqdm
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: ruff; extra == "dev"
|
|
18
|
+
Requires-Dist: pytest; extra == "dev"
|
|
19
|
+
Requires-Dist: mypy; extra == "dev"
|
|
20
|
+
Provides-Extra: docs
|
|
21
|
+
Requires-Dist: sphinx>=7; extra == "docs"
|
|
22
|
+
Requires-Dist: furo>=2024.8.6; extra == "docs"
|
|
23
|
+
Requires-Dist: sphinxcontrib-mermaid>=0.9; extra == "docs"
|
|
24
|
+
Provides-Extra: eval
|
|
25
|
+
Provides-Extra: render
|
|
26
|
+
|
|
27
|
+

|
|
28
|
+
|
|
29
|
+
# keypoints2body
|
|
30
|
+
|
|
31
|
+
`keypoints2body` is a Python library for optimizing SMPL-family body model parameters
|
|
32
|
+
from 3D joints for both single frames and motion sequences.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install -e .
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick usage
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import numpy as np
|
|
44
|
+
from keypoints2body import optimize_params_frame
|
|
45
|
+
|
|
46
|
+
joints = np.zeros((22, 3), dtype=np.float32)
|
|
47
|
+
result = optimize_params_frame(joints, joint_layout="AMASS")
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Documentation
|
|
51
|
+
|
|
52
|
+
Full documentation lives under [`docs/`](docs/) and is intended for Sphinx.
|
|
53
|
+
|
|
54
|
+
Suggested starting points:
|
|
55
|
+
|
|
56
|
+
- [Getting started](docs/getting_started.rst)
|
|
57
|
+
- [Library usage](docs/usage.rst)
|
|
58
|
+
- [CLI reference](docs/cli.rst)
|
|
59
|
+
- [Architecture](docs/architecture.rst)
|
|
60
|
+
- [API reference](docs/api.rst)
|
|
61
|
+
- [Contributor guide](docs/contributing.rst)
|
|
62
|
+
|
|
63
|
+
## CLI
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
keypoints2body-fit-frame --help
|
|
67
|
+
keypoints2body-fit-seq --help
|
|
68
|
+
keypoints2body-eval --help
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Project script:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
python smpl_fit.py --help
|
|
75
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# keypoints2body
|
|
4
|
+
|
|
5
|
+
`keypoints2body` is a Python library for optimizing SMPL-family body model parameters
|
|
6
|
+
from 3D joints for both single frames and motion sequences.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install -e .
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick usage
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
import numpy as np
|
|
18
|
+
from keypoints2body import optimize_params_frame
|
|
19
|
+
|
|
20
|
+
joints = np.zeros((22, 3), dtype=np.float32)
|
|
21
|
+
result = optimize_params_frame(joints, joint_layout="AMASS")
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Documentation
|
|
25
|
+
|
|
26
|
+
Full documentation lives under [`docs/`](docs/) and is intended for Sphinx.
|
|
27
|
+
|
|
28
|
+
Suggested starting points:
|
|
29
|
+
|
|
30
|
+
- [Getting started](docs/getting_started.rst)
|
|
31
|
+
- [Library usage](docs/usage.rst)
|
|
32
|
+
- [CLI reference](docs/cli.rst)
|
|
33
|
+
- [Architecture](docs/architecture.rst)
|
|
34
|
+
- [API reference](docs/api.rst)
|
|
35
|
+
- [Contributor guide](docs/contributing.rst)
|
|
36
|
+
|
|
37
|
+
## CLI
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
keypoints2body-fit-frame --help
|
|
41
|
+
keypoints2body-fit-seq --help
|
|
42
|
+
keypoints2body-eval --help
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Project script:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
python smpl_fit.py --help
|
|
49
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
2
|
+
|
|
3
|
+
from .api.frame import optimize_params_frame
|
|
4
|
+
from .api.sequence import optimize_params_sequence, optimize_shape_sequence
|
|
5
|
+
from .models.smpl_data import (
|
|
6
|
+
BodyModelFitResult,
|
|
7
|
+
BodyModelParams,
|
|
8
|
+
SMPLData,
|
|
9
|
+
SMPLHData,
|
|
10
|
+
SMPLXData,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
__version__ = version("keypoints2body")
|
|
15
|
+
except PackageNotFoundError:
|
|
16
|
+
__version__ = "0.0.0"
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"__version__",
|
|
20
|
+
"optimize_params_frame",
|
|
21
|
+
"optimize_params_sequence",
|
|
22
|
+
"optimize_shape_sequence",
|
|
23
|
+
"BodyModelFitResult",
|
|
24
|
+
"BodyModelParams",
|
|
25
|
+
"SMPLData",
|
|
26
|
+
"SMPLHData",
|
|
27
|
+
"SMPLXData",
|
|
28
|
+
]
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import torch
|
|
6
|
+
|
|
7
|
+
from ..core.config import BodyModelConfig, FrameOptimizeConfig
|
|
8
|
+
from ..core.engine import OptimizeEngine, default_init_params, load_mean_pose_shape
|
|
9
|
+
from ..core.joints.adapters import adapt_layout_and_conf, normalize_joints_frame
|
|
10
|
+
from ..models.smpl_data import BodyModelFitResult, BodyModelParams, SMPLData
|
|
11
|
+
from .model_factory import load_body_model
|
|
12
|
+
|
|
13
|
+
DEFAULT_MEAN_FILE = "./data/models/neutral_smpl_mean_params.h5"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def optimize_params_frame(
|
|
17
|
+
joints,
|
|
18
|
+
*,
|
|
19
|
+
prev_params: Optional[BodyModelParams] = None,
|
|
20
|
+
body_model: str = "smpl",
|
|
21
|
+
joint_layout: Optional[str] = None,
|
|
22
|
+
model=None,
|
|
23
|
+
config: Optional[FrameOptimizeConfig | dict] = None,
|
|
24
|
+
device=None,
|
|
25
|
+
) -> BodyModelFitResult:
|
|
26
|
+
"""Optimize body parameters for a single frame of 3D joints.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
joints: Frame keypoints with shape ``(K,3)`` or ``(K,4)``.
|
|
30
|
+
prev_params: Optional warm-start parameters from a previous fit.
|
|
31
|
+
body_model: Body model type (for example ``"smpl"``).
|
|
32
|
+
joint_layout: Optional explicit layout label for adapter selection.
|
|
33
|
+
model: Optional preloaded body model instance.
|
|
34
|
+
config: Optional frame config or dict equivalent.
|
|
35
|
+
device: Optional torch device specifier.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Typed fitting result containing optimized parameters, joints, vertices, and loss.
|
|
39
|
+
"""
|
|
40
|
+
device = torch.device(device) if device is not None else torch.device("cpu")
|
|
41
|
+
|
|
42
|
+
if isinstance(config, dict):
|
|
43
|
+
frame_cfg = FrameOptimizeConfig(**config)
|
|
44
|
+
elif isinstance(config, FrameOptimizeConfig):
|
|
45
|
+
frame_cfg = config
|
|
46
|
+
else:
|
|
47
|
+
frame_cfg = FrameOptimizeConfig()
|
|
48
|
+
|
|
49
|
+
if frame_cfg.input_type != "joints3d":
|
|
50
|
+
raise NotImplementedError(
|
|
51
|
+
f"input_type='{frame_cfg.input_type}' is not implemented in this release. "
|
|
52
|
+
"Current APIs support only joints3d."
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
j3d, conf_3d = normalize_joints_frame(joints)
|
|
56
|
+
j_np = j3d.squeeze(0).cpu().numpy()[None, ...]
|
|
57
|
+
c_np = conf_3d.cpu().numpy()[None, ...]
|
|
58
|
+
j_np, c_np, out_layout = adapt_layout_and_conf(j_np, c_np, joint_layout)
|
|
59
|
+
j3d = torch.as_tensor(j_np, dtype=torch.float32, device=device)
|
|
60
|
+
conf_3d = torch.as_tensor(c_np[0], dtype=torch.float32, device=device)
|
|
61
|
+
|
|
62
|
+
if out_layout not in ("SMPL24", "AMASS"):
|
|
63
|
+
raise ValueError(f"Unsupported output layout after adaptation: {out_layout}")
|
|
64
|
+
frame_cfg.joints_category = out_layout
|
|
65
|
+
|
|
66
|
+
if model is None:
|
|
67
|
+
body_cfg = BodyModelConfig(model_type=body_model)
|
|
68
|
+
model = load_body_model(body_cfg, device)
|
|
69
|
+
|
|
70
|
+
engine = OptimizeEngine(model=model, frame_config=frame_cfg, device=device)
|
|
71
|
+
|
|
72
|
+
if prev_params is None:
|
|
73
|
+
init_mean_pose, init_mean_shape = load_mean_pose_shape(
|
|
74
|
+
DEFAULT_MEAN_FILE, device
|
|
75
|
+
)
|
|
76
|
+
init_params = default_init_params(
|
|
77
|
+
init_mean_pose,
|
|
78
|
+
init_mean_shape,
|
|
79
|
+
j3d,
|
|
80
|
+
model,
|
|
81
|
+
joints_category=frame_cfg.joints_category,
|
|
82
|
+
coordinate_mode=frame_cfg.coordinate_mode,
|
|
83
|
+
)
|
|
84
|
+
else:
|
|
85
|
+
init_params = prev_params.to(device)
|
|
86
|
+
if frame_cfg.coordinate_mode == "world" and init_params.transl is None:
|
|
87
|
+
pose = init_params.pose
|
|
88
|
+
if not isinstance(pose, torch.Tensor):
|
|
89
|
+
pose = torch.as_tensor(pose, dtype=torch.float32, device=device)
|
|
90
|
+
betas = init_params.betas
|
|
91
|
+
if not isinstance(betas, torch.Tensor):
|
|
92
|
+
betas = torch.as_tensor(betas, dtype=torch.float32, device=device)
|
|
93
|
+
transl = default_init_params(
|
|
94
|
+
pose,
|
|
95
|
+
betas,
|
|
96
|
+
j3d,
|
|
97
|
+
model,
|
|
98
|
+
frame_cfg.joints_category,
|
|
99
|
+
frame_cfg.coordinate_mode,
|
|
100
|
+
).transl
|
|
101
|
+
init_params = SMPLData(
|
|
102
|
+
betas=betas,
|
|
103
|
+
global_orient=pose[:, :3],
|
|
104
|
+
body_pose=pose[:, 3:],
|
|
105
|
+
transl=transl,
|
|
106
|
+
metadata=dict(getattr(init_params, "metadata", {})),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return engine.fit_frame(
|
|
110
|
+
init_params=init_params, j3d=j3d, conf_3d=conf_3d, seq_ind=0
|
|
111
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import smplx
|
|
6
|
+
import torch
|
|
7
|
+
|
|
8
|
+
from ..core.config import BodyModelConfig
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def load_body_model(
|
|
12
|
+
config: BodyModelConfig,
|
|
13
|
+
device: torch.device,
|
|
14
|
+
):
|
|
15
|
+
"""Load a body model module with ``smplx.create``.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
config: Model-loading configuration.
|
|
19
|
+
device: Torch device where the model should live.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
A body model module returned by ``smplx.create`` moved to ``device``.
|
|
23
|
+
"""
|
|
24
|
+
model_dir = Path(config.model_dir).expanduser()
|
|
25
|
+
return smplx.create(
|
|
26
|
+
str(model_dir),
|
|
27
|
+
model_type=config.model_type,
|
|
28
|
+
gender=config.gender,
|
|
29
|
+
ext=config.ext,
|
|
30
|
+
batch_size=config.batch_size,
|
|
31
|
+
).to(device)
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import torch
|
|
6
|
+
|
|
7
|
+
from ..core.config import BodyModelConfig, FrameOptimizeConfig, SequenceOptimizeConfig
|
|
8
|
+
from ..core.engine import (
|
|
9
|
+
OptimizeEngine,
|
|
10
|
+
default_init_params,
|
|
11
|
+
load_mean_pose_shape,
|
|
12
|
+
optimize_shape_pass,
|
|
13
|
+
)
|
|
14
|
+
from ..core.joints.adapters import adapt_layout_and_conf, normalize_joints_sequence
|
|
15
|
+
from ..models.smpl_data import BodyModelFitResult, BodyModelParams, SMPLData
|
|
16
|
+
from .model_factory import load_body_model
|
|
17
|
+
|
|
18
|
+
DEFAULT_MEAN_FILE = "./data/models/neutral_smpl_mean_params.h5"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def optimize_params_sequence(
|
|
22
|
+
joints_seq,
|
|
23
|
+
*,
|
|
24
|
+
init_params: Optional[BodyModelParams] = None,
|
|
25
|
+
body_model: str = "smpl",
|
|
26
|
+
joint_layout: Optional[str] = None,
|
|
27
|
+
model=None,
|
|
28
|
+
config: Optional[SequenceOptimizeConfig | dict] = None,
|
|
29
|
+
device=None,
|
|
30
|
+
) -> list[BodyModelFitResult]:
|
|
31
|
+
"""Optimize body parameters for a full motion sequence.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
joints_seq: Sequence keypoints with shape ``(T,K,3)`` or ``(T,K,4)``.
|
|
35
|
+
init_params: Optional initial parameters for frame 0.
|
|
36
|
+
body_model: Body model type (for example ``"smpl"``).
|
|
37
|
+
joint_layout: Optional explicit layout label for adapter selection.
|
|
38
|
+
model: Optional preloaded body model instance.
|
|
39
|
+
config: Optional sequence config or dict equivalent.
|
|
40
|
+
device: Optional torch device specifier.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Per-frame optimization results in temporal order.
|
|
44
|
+
"""
|
|
45
|
+
device = torch.device(device) if device is not None else torch.device("cpu")
|
|
46
|
+
|
|
47
|
+
if isinstance(config, dict):
|
|
48
|
+
frame_cfg = FrameOptimizeConfig(**config.get("frame", {}))
|
|
49
|
+
seq_cfg = SequenceOptimizeConfig(
|
|
50
|
+
frame=frame_cfg,
|
|
51
|
+
num_shape_iters=config.get("num_shape_iters", 40),
|
|
52
|
+
num_shape_frames=config.get("num_shape_frames", 50),
|
|
53
|
+
use_shape_optimization=config.get("use_shape_optimization", True),
|
|
54
|
+
use_previous_frame_init=config.get("use_previous_frame_init", True),
|
|
55
|
+
fix_foot=config.get("fix_foot", False),
|
|
56
|
+
limit_frames=config.get("limit_frames", None),
|
|
57
|
+
)
|
|
58
|
+
elif isinstance(config, SequenceOptimizeConfig):
|
|
59
|
+
seq_cfg = config
|
|
60
|
+
else:
|
|
61
|
+
seq_cfg = SequenceOptimizeConfig()
|
|
62
|
+
|
|
63
|
+
if seq_cfg.frame.input_type != "joints3d":
|
|
64
|
+
raise NotImplementedError(
|
|
65
|
+
f"input_type='{seq_cfg.frame.input_type}' is not implemented in this release. "
|
|
66
|
+
"Current APIs support only joints3d."
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
xyz, conf = normalize_joints_sequence(joints_seq)
|
|
70
|
+
xyz_np, conf_np, out_layout = adapt_layout_and_conf(
|
|
71
|
+
xyz.cpu().numpy(), conf.cpu().numpy(), joint_layout
|
|
72
|
+
)
|
|
73
|
+
xyz = torch.as_tensor(xyz_np, dtype=torch.float32, device=device)
|
|
74
|
+
conf = torch.as_tensor(conf_np, dtype=torch.float32, device=device)
|
|
75
|
+
|
|
76
|
+
if out_layout not in ("SMPL24", "AMASS"):
|
|
77
|
+
raise ValueError(f"Unsupported output layout after adaptation: {out_layout}")
|
|
78
|
+
seq_cfg.frame.joints_category = out_layout
|
|
79
|
+
|
|
80
|
+
if seq_cfg.limit_frames is not None and seq_cfg.limit_frames > 0:
|
|
81
|
+
xyz = xyz[: seq_cfg.limit_frames]
|
|
82
|
+
conf = conf[: seq_cfg.limit_frames]
|
|
83
|
+
|
|
84
|
+
if seq_cfg.fix_foot and xyz.shape[1] > 11:
|
|
85
|
+
conf[:, 7] = 1.5
|
|
86
|
+
conf[:, 8] = 1.5
|
|
87
|
+
conf[:, 10] = 1.5
|
|
88
|
+
conf[:, 11] = 1.5
|
|
89
|
+
|
|
90
|
+
if model is None:
|
|
91
|
+
body_cfg = BodyModelConfig(model_type=body_model)
|
|
92
|
+
model = load_body_model(body_cfg, device)
|
|
93
|
+
|
|
94
|
+
init_mean_pose, init_mean_shape = load_mean_pose_shape(DEFAULT_MEAN_FILE, device)
|
|
95
|
+
betas_opt = optimize_shape_pass(
|
|
96
|
+
model=model,
|
|
97
|
+
seq_config=seq_cfg,
|
|
98
|
+
init_mean_shape=init_mean_shape,
|
|
99
|
+
init_mean_pose=init_mean_pose,
|
|
100
|
+
data_tensor=xyz,
|
|
101
|
+
confidence_input=conf[0],
|
|
102
|
+
device=device,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
engine = OptimizeEngine(model=model, frame_config=seq_cfg.frame, device=device)
|
|
106
|
+
results: list[BodyModelFitResult] = []
|
|
107
|
+
|
|
108
|
+
if init_params is None:
|
|
109
|
+
prev = default_init_params(
|
|
110
|
+
init_mean_pose,
|
|
111
|
+
betas_opt,
|
|
112
|
+
xyz[0:1],
|
|
113
|
+
model,
|
|
114
|
+
joints_category=seq_cfg.frame.joints_category,
|
|
115
|
+
coordinate_mode=seq_cfg.frame.coordinate_mode,
|
|
116
|
+
)
|
|
117
|
+
else:
|
|
118
|
+
prev = init_params.to(device)
|
|
119
|
+
|
|
120
|
+
for idx in range(xyz.shape[0]):
|
|
121
|
+
frame = xyz[idx : idx + 1]
|
|
122
|
+
frame_conf = conf[idx]
|
|
123
|
+
|
|
124
|
+
if seq_cfg.frame.coordinate_mode == "world" and prev.transl is None:
|
|
125
|
+
pose = (
|
|
126
|
+
prev.pose
|
|
127
|
+
if isinstance(prev.pose, torch.Tensor)
|
|
128
|
+
else torch.as_tensor(prev.pose, dtype=torch.float32, device=device)
|
|
129
|
+
)
|
|
130
|
+
betas = (
|
|
131
|
+
prev.betas
|
|
132
|
+
if isinstance(prev.betas, torch.Tensor)
|
|
133
|
+
else torch.as_tensor(prev.betas, dtype=torch.float32, device=device)
|
|
134
|
+
)
|
|
135
|
+
prev = SMPLData(
|
|
136
|
+
betas=betas,
|
|
137
|
+
global_orient=pose[:, :3],
|
|
138
|
+
body_pose=pose[:, 3:],
|
|
139
|
+
transl=default_init_params(
|
|
140
|
+
pose,
|
|
141
|
+
betas,
|
|
142
|
+
frame,
|
|
143
|
+
model,
|
|
144
|
+
seq_cfg.frame.joints_category,
|
|
145
|
+
seq_cfg.frame.coordinate_mode,
|
|
146
|
+
).transl,
|
|
147
|
+
metadata=dict(getattr(prev, "metadata", {})),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
res = engine.fit_frame(
|
|
151
|
+
init_params=prev, j3d=frame, conf_3d=frame_conf, seq_ind=idx
|
|
152
|
+
)
|
|
153
|
+
results.append(res)
|
|
154
|
+
if seq_cfg.use_previous_frame_init:
|
|
155
|
+
prev = res.params
|
|
156
|
+
|
|
157
|
+
return results
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def optimize_shape_sequence(
|
|
161
|
+
joints_seq,
|
|
162
|
+
*,
|
|
163
|
+
body_model: str = "smpl",
|
|
164
|
+
joint_layout: Optional[str] = None,
|
|
165
|
+
model=None,
|
|
166
|
+
config: Optional[SequenceOptimizeConfig | dict] = None,
|
|
167
|
+
device=None,
|
|
168
|
+
) -> BodyModelParams:
|
|
169
|
+
"""Run sequence optimization and return the final frame parameters.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
joints_seq: Sequence keypoints input.
|
|
173
|
+
body_model: Body model type.
|
|
174
|
+
joint_layout: Optional explicit layout label.
|
|
175
|
+
model: Optional preloaded body model instance.
|
|
176
|
+
config: Optional sequence config.
|
|
177
|
+
device: Optional torch device specifier.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
Parameter object from the last optimized frame.
|
|
181
|
+
"""
|
|
182
|
+
results = optimize_params_sequence(
|
|
183
|
+
joints_seq,
|
|
184
|
+
init_params=None,
|
|
185
|
+
body_model=body_model,
|
|
186
|
+
joint_layout=joint_layout,
|
|
187
|
+
model=model,
|
|
188
|
+
config=config,
|
|
189
|
+
device=device,
|
|
190
|
+
)
|
|
191
|
+
if not results:
|
|
192
|
+
raise ValueError("No frames were optimized")
|
|
193
|
+
return results[-1].params
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__all__ = []
|