smplfitter 0.2.10__tar.gz → 0.3.2.dev0__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.
- smplfitter-0.3.2.dev0/.editorconfig +18 -0
- smplfitter-0.3.2.dev0/.github/dependabot.yml +11 -0
- smplfitter-0.3.2.dev0/.github/workflows/ci.yml +27 -0
- smplfitter-0.3.2.dev0/.github/workflows/python-publish.yml +80 -0
- smplfitter-0.3.2.dev0/.pre-commit-config.yaml +17 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/.readthedocs.yaml +1 -2
- smplfitter-0.3.2.dev0/Makefile +22 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/PKG-INFO +51 -29
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/README.md +8 -10
- smplfitter-0.3.2.dev0/benchmark/README.md +29 -0
- smplfitter-0.3.2.dev0/benchmark/bench_bodymodel.py +106 -0
- smplfitter-0.3.2.dev0/benchmark/bench_converter.py +354 -0
- smplfitter-0.3.2.dev0/benchmark/bench_rotvec.py +66 -0
- smplfitter-0.3.2.dev0/benchmark/benchmark.png +0 -0
- smplfitter-0.3.2.dev0/benchmark/benchmark_smpl.png +0 -0
- smplfitter-0.3.2.dev0/benchmark/benchmark_smplx.png +0 -0
- smplfitter-0.3.2.dev0/benchmark/benchmark_vs_smplx.png +0 -0
- smplfitter-0.3.2.dev0/benchmark/benchmark_vs_smplx_smpl.png +0 -0
- smplfitter-0.3.2.dev0/benchmark/benchmark_vs_smplx_smplx.png +0 -0
- smplfitter-0.3.2.dev0/benchmark/plot_results.py +136 -0
- smplfitter-0.3.2.dev0/benchmark/run_benchmark.py +558 -0
- smplfitter-0.3.2.dev0/docs/Makefile +20 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/conf.py +60 -43
- smplfitter-0.3.2.dev0/docs/howto.rst +422 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/index.rst +3 -2
- smplfitter-0.3.2.dev0/docs/make.bat +35 -0
- smplfitter-0.3.2.dev0/docs/smpl_to_smplx.rst +133 -0
- smplfitter-0.3.2.dev0/pyproject.toml +110 -0
- smplfitter-0.3.2.dev0/src/smplfitter/__init__.py +20 -0
- smplfitter-0.3.2.dev0/src/smplfitter/_version.py +34 -0
- smplfitter-0.3.2.dev0/src/smplfitter/common.py +250 -0
- smplfitter-0.3.2.dev0/src/smplfitter/decimation/__init__.py +1 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/decimation/decimate_body_models.py +3 -2
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/decimation/make_post_lbs_joint_regressors.py +6 -5
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/decimation/make_post_lbs_joint_regressors_tf.py +8 -5
- smplfitter-0.3.2.dev0/src/smplfitter/download.py +412 -0
- smplfitter-0.3.2.dev0/src/smplfitter/jax/__init__.py +25 -0
- smplfitter-0.3.2.dev0/src/smplfitter/jax/bodyconverter.py +156 -0
- smplfitter-0.3.2.dev0/src/smplfitter/jax/bodyfitter.py +1004 -0
- smplfitter-0.3.2.dev0/src/smplfitter/jax/bodymodel.py +189 -0
- smplfitter-0.3.2.dev0/src/smplfitter/jax/lstsq.py +119 -0
- smplfitter-0.3.2.dev0/src/smplfitter/jax/rotation.py +98 -0
- smplfitter-0.3.2.dev0/src/smplfitter/nb/__init__.py +25 -0
- smplfitter-0.3.2.dev0/src/smplfitter/nb/bodyconverter.py +153 -0
- smplfitter-0.3.2.dev0/src/smplfitter/nb/bodyfitter.py +1321 -0
- smplfitter-0.3.2.dev0/src/smplfitter/nb/bodymodel.py +443 -0
- smplfitter-0.3.2.dev0/src/smplfitter/nb/lstsq.py +315 -0
- smplfitter-0.3.2.dev0/src/smplfitter/nb/precompile.py +109 -0
- smplfitter-0.3.2.dev0/src/smplfitter/nb/rotation.py +120 -0
- smplfitter-0.3.2.dev0/src/smplfitter/nb/util.py +58 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/__init__.py +7 -3
- smplfitter-0.3.2.dev0/src/smplfitter/np/bodyconverter.py +153 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/bodyfitter.py +430 -89
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/bodymodel.py +54 -26
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/lstsq.py +11 -4
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/rotation.py +2 -1
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/util.py +1 -0
- smplfitter-0.3.2.dev0/src/smplfitter/pt/__init__.py +158 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/bodyconverter.py +4 -2
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/bodyfitter.py +93 -87
- smplfitter-0.3.2.dev0/src/smplfitter/pt/bodyfitter_opt.py +255 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/bodyflipper.py +8 -8
- smplfitter-0.3.2.dev0/src/smplfitter/pt/bodyflipper_opt.py +181 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/bodymodel.py +41 -24
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/handreplacer.py +4 -3
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/lstsq.py +6 -4
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/rotation.py +9 -2
- smplfitter-0.3.2.dev0/src/smplfitter/tf/__init__.py +188 -0
- smplfitter-0.3.2.dev0/src/smplfitter/tf/bodyconverter.py +168 -0
- smplfitter-0.3.2.dev0/src/smplfitter/tf/bodyfitter.py +1074 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/tf/bodymodel.py +50 -24
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/tf/lstsq.py +28 -4
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/tf/rotation.py +1 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/tf/util.py +1 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter.egg-info/PKG-INFO +51 -29
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter.egg-info/SOURCES.txt +43 -3
- smplfitter-0.3.2.dev0/src/smplfitter.egg-info/requires.txt +38 -0
- smplfitter-0.3.2.dev0/tests/conftest.py +200 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/tests/np/test_bodymodel.py +1 -2
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/tests/pt/test_bodymodel.py +1 -8
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/tests/pt/test_converter.py +9 -9
- smplfitter-0.3.2.dev0/tests/pt/test_flipper.py +74 -0
- smplfitter-0.3.2.dev0/tests/test_converter_common.py +120 -0
- smplfitter-0.3.2.dev0/tests/test_fitter_common.py +331 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/tests/test_forward.py +2 -6
- smplfitter-0.2.10/.github/workflows/python-publish.yml +0 -35
- smplfitter-0.2.10/docs/modules.rst +0 -10
- smplfitter-0.2.10/pyproject.toml +0 -69
- smplfitter-0.2.10/src/smplfitter/__init__.py +0 -7
- smplfitter-0.2.10/src/smplfitter/_version.py +0 -21
- smplfitter-0.2.10/src/smplfitter/common.py +0 -166
- smplfitter-0.2.10/src/smplfitter/pt/__init__.py +0 -94
- smplfitter-0.2.10/src/smplfitter/tf/__init__.py +0 -107
- smplfitter-0.2.10/src/smplfitter/tf/bodyfitter.py +0 -655
- smplfitter-0.2.10/src/smplfitter.egg-info/requires.txt +0 -26
- smplfitter-0.2.10/tests/np/test_fitter.py +0 -29
- smplfitter-0.2.10/tests/pt/__init__.py +0 -0
- smplfitter-0.2.10/tests/pt/test_fitter.py +0 -36
- smplfitter-0.2.10/tests/pt/test_flipper.py +0 -36
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/.gitignore +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/LICENSE +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/example.gif +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/image.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/image_example.jpg +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/on_image.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/on_image_fit.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/overlay_after_rot1.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/overlay_after_rot1_shape.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/overlay_after_rot2.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/overlay_after_rot2_shape.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/overlay_after_rot3.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/parts_overlay1.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/parts_overlay1_rot.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/parts_overlay2.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/parts_overlay2_rot.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/pose3d.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/pose3d_parts_color.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/pose3d_parts_color_blown.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/tmean_parts.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/tmean_parts_blown.png +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/styles/my_theme.css +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/index.rst +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/attribute.rst +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/class.rst +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/data.rst +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/exception.rst +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/function.rst +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/method.rst +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/module.rst +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/package.rst +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/property.rst +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/copyright.html +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/abbrev_long.bib +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/references.bib +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/setup.cfg +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter.egg-info/dependency_links.txt +0 -0
- {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter.egg-info/top_level.txt +0 -0
- {smplfitter-0.2.10/src/smplfitter/decimation → smplfitter-0.3.2.dev0/tests/np}/__init__.py +0 -0
- {smplfitter-0.2.10/tests/np → smplfitter-0.3.2.dev0/tests/pt}/__init__.py +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
indent_style = space
|
|
5
|
+
indent_size = 4
|
|
6
|
+
end_of_line = lf
|
|
7
|
+
charset = utf-8
|
|
8
|
+
trim_trailing_whitespace = true
|
|
9
|
+
insert_final_newline = true
|
|
10
|
+
|
|
11
|
+
[*.{yml,yaml}]
|
|
12
|
+
indent_size = 2
|
|
13
|
+
|
|
14
|
+
[*.md]
|
|
15
|
+
trim_trailing_whitespace = false
|
|
16
|
+
|
|
17
|
+
[Makefile]
|
|
18
|
+
indent_style = tab
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
name: Lint
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up Python
|
|
17
|
+
uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.10"
|
|
20
|
+
|
|
21
|
+
- name: Install ruff
|
|
22
|
+
run: pip install ruff==0.4.10
|
|
23
|
+
|
|
24
|
+
- name: Lint with ruff
|
|
25
|
+
run: |
|
|
26
|
+
ruff check .
|
|
27
|
+
ruff format --check .
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
name: Build and Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch: # Allow manual trigger for testing
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
lint:
|
|
13
|
+
name: Lint
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.10"
|
|
22
|
+
|
|
23
|
+
- name: Install ruff
|
|
24
|
+
run: pip install ruff==0.4.10
|
|
25
|
+
|
|
26
|
+
- name: Lint with ruff
|
|
27
|
+
run: |
|
|
28
|
+
ruff check .
|
|
29
|
+
ruff format --check .
|
|
30
|
+
|
|
31
|
+
build:
|
|
32
|
+
name: Build distribution
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
needs: lint
|
|
35
|
+
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
with:
|
|
39
|
+
fetch-depth: 0 # Required for setuptools-scm
|
|
40
|
+
|
|
41
|
+
- name: Set up Python
|
|
42
|
+
uses: actions/setup-python@v5
|
|
43
|
+
with:
|
|
44
|
+
python-version: "3.12"
|
|
45
|
+
|
|
46
|
+
- name: Install build tools
|
|
47
|
+
run: python -m pip install --upgrade pip build
|
|
48
|
+
|
|
49
|
+
- name: Build wheel and sdist
|
|
50
|
+
run: python -m build
|
|
51
|
+
|
|
52
|
+
- name: Verify package
|
|
53
|
+
run: |
|
|
54
|
+
pip install dist/*.whl --no-deps
|
|
55
|
+
pip install numpy scipy chumpy --only-binary=:all: || pip install numpy scipy
|
|
56
|
+
python -c "import smplfitter; print(smplfitter.__version__)"
|
|
57
|
+
|
|
58
|
+
- uses: actions/upload-artifact@v4
|
|
59
|
+
with:
|
|
60
|
+
name: dist
|
|
61
|
+
path: dist/
|
|
62
|
+
|
|
63
|
+
publish:
|
|
64
|
+
name: Publish to PyPI
|
|
65
|
+
needs: build
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
environment: pypi
|
|
68
|
+
permissions:
|
|
69
|
+
id-token: write # Required for trusted publishing
|
|
70
|
+
# Only publish on release, not on workflow_dispatch
|
|
71
|
+
if: github.event_name == 'release'
|
|
72
|
+
|
|
73
|
+
steps:
|
|
74
|
+
- uses: actions/download-artifact@v4
|
|
75
|
+
with:
|
|
76
|
+
name: dist
|
|
77
|
+
path: dist/
|
|
78
|
+
|
|
79
|
+
- name: Publish to PyPI
|
|
80
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Run `pre-commit install` to set up hooks
|
|
2
|
+
# Run `pre-commit autoupdate` to update hook versions
|
|
3
|
+
repos:
|
|
4
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
5
|
+
rev: v0.8.0
|
|
6
|
+
hooks:
|
|
7
|
+
- id: ruff
|
|
8
|
+
args: [--fix]
|
|
9
|
+
- id: ruff-format
|
|
10
|
+
|
|
11
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
12
|
+
rev: v5.0.0
|
|
13
|
+
hooks:
|
|
14
|
+
- id: trailing-whitespace
|
|
15
|
+
- id: end-of-file-fixer
|
|
16
|
+
- id: check-yaml
|
|
17
|
+
- id: check-added-large-files
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
.PHONY: install test lint format docs clean
|
|
2
|
+
|
|
3
|
+
install:
|
|
4
|
+
pip install -e ".[dev]"
|
|
5
|
+
|
|
6
|
+
test:
|
|
7
|
+
pytest -v --cov=smplfitter
|
|
8
|
+
|
|
9
|
+
lint:
|
|
10
|
+
ruff check .
|
|
11
|
+
ruff format --check .
|
|
12
|
+
|
|
13
|
+
format:
|
|
14
|
+
ruff check --fix .
|
|
15
|
+
ruff format .
|
|
16
|
+
|
|
17
|
+
docs:
|
|
18
|
+
cd docs && make html
|
|
19
|
+
|
|
20
|
+
clean:
|
|
21
|
+
rm -rf build dist *.egg-info .pytest_cache .ruff_cache .coverage
|
|
22
|
+
find . -type d -name __pycache__ -exec rm -rf {} +
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: smplfitter
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: Fast inverse kinematics and shape fitting for SMPL-family models in NumPy, PyTorch, and
|
|
3
|
+
Version: 0.3.2.dev0
|
|
4
|
+
Summary: Fast inverse kinematics and shape fitting for SMPL-family models in NumPy, PyTorch, TensorFlow, JAX, and Numba
|
|
5
5
|
Author-email: István Sárándi <istvan.sarandi@uni-tuebingen.de>
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
@@ -27,9 +27,26 @@ License: MIT License
|
|
|
27
27
|
|
|
28
28
|
Project-URL: Homepage, https://github.com/isarandi/smplfitter
|
|
29
29
|
Project-URL: Repository, https://github.com/isarandi/smplfitter
|
|
30
|
+
Project-URL: Documentation, https://smplfitter.readthedocs.io/
|
|
30
31
|
Project-URL: Issues, https://github.com/isarandi/smplfitter/issues
|
|
32
|
+
Project-URL: Changelog, https://github.com/isarandi/smplfitter/releases
|
|
31
33
|
Project-URL: Author, https://istvansarandi.com
|
|
32
|
-
|
|
34
|
+
Keywords: smpl,smplx,smplh,3d-human,body-model,ik,inverse-kinematics,parametric-model,pose-estimation,differentiable,gpu,tensorflow,pytorch,jax,numba,numpy,batch-processing
|
|
35
|
+
Classifier: Development Status :: 4 - Beta
|
|
36
|
+
Classifier: Intended Audience :: Science/Research
|
|
37
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
38
|
+
Classifier: Programming Language :: Python
|
|
39
|
+
Classifier: Programming Language :: Python :: 3
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
46
|
+
Classifier: Operating System :: OS Independent
|
|
47
|
+
Classifier: Topic :: Scientific/Engineering
|
|
48
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
49
|
+
Requires-Python: >=3.8
|
|
33
50
|
Description-Content-Type: text/markdown
|
|
34
51
|
License-File: LICENSE
|
|
35
52
|
Requires-Dist: numpy
|
|
@@ -39,22 +56,29 @@ Provides-Extra: tensorflow
|
|
|
39
56
|
Requires-Dist: tensorflow; extra == "tensorflow"
|
|
40
57
|
Provides-Extra: pytorch
|
|
41
58
|
Requires-Dist: torch; extra == "pytorch"
|
|
42
|
-
Provides-Extra:
|
|
43
|
-
Requires-Dist:
|
|
44
|
-
Requires-Dist:
|
|
45
|
-
|
|
46
|
-
Requires-Dist:
|
|
47
|
-
|
|
48
|
-
Requires-Dist:
|
|
49
|
-
Requires-Dist:
|
|
50
|
-
|
|
51
|
-
Requires-Dist:
|
|
52
|
-
Requires-Dist:
|
|
53
|
-
|
|
54
|
-
Requires-Dist:
|
|
55
|
-
Requires-Dist:
|
|
56
|
-
Requires-Dist:
|
|
57
|
-
Requires-Dist:
|
|
59
|
+
Provides-Extra: jax
|
|
60
|
+
Requires-Dist: jax; extra == "jax"
|
|
61
|
+
Requires-Dist: jaxlib; extra == "jax"
|
|
62
|
+
Provides-Extra: numba
|
|
63
|
+
Requires-Dist: numba; extra == "numba"
|
|
64
|
+
Provides-Extra: test
|
|
65
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
66
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
67
|
+
Provides-Extra: lint
|
|
68
|
+
Requires-Dist: ruff; extra == "lint"
|
|
69
|
+
Requires-Dist: pre-commit; extra == "lint"
|
|
70
|
+
Provides-Extra: docs
|
|
71
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
72
|
+
Requires-Dist: sphinxcontrib-bibtex; extra == "docs"
|
|
73
|
+
Requires-Dist: sphinx-autoapi; extra == "docs"
|
|
74
|
+
Requires-Dist: sphinx-autobuild; extra == "docs"
|
|
75
|
+
Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
|
|
76
|
+
Requires-Dist: sphinx-codeautolink; extra == "docs"
|
|
77
|
+
Requires-Dist: pydata-sphinx-theme; extra == "docs"
|
|
78
|
+
Requires-Dist: setuptools-scm; extra == "docs"
|
|
79
|
+
Requires-Dist: toml; extra == "docs"
|
|
80
|
+
Provides-Extra: dev
|
|
81
|
+
Requires-Dist: smplfitter[docs,lint,pytorch,test]; extra == "dev"
|
|
58
82
|
Dynamic: license-file
|
|
59
83
|
|
|
60
84
|
# SMPLFitter: The Fast Way From Vertices to Parametric 3D Humans
|
|
@@ -77,11 +101,9 @@ It can fit a batch of 4096 instances in 423 ms on a single RTX 3090 GPU giving a
|
|
|
77
101
|
## Installation
|
|
78
102
|
|
|
79
103
|
```bash
|
|
80
|
-
pip install
|
|
104
|
+
pip install smplfitter
|
|
81
105
|
```
|
|
82
106
|
|
|
83
|
-
(Packaging for PyPI is planned for later.)
|
|
84
|
-
|
|
85
107
|
### Download Body Model Files
|
|
86
108
|
|
|
87
109
|
You need to download the body model data files from the corresponding websites for this code to work. You only need the ones that you plan to use. There should be a `DATA_ROOT` environment variable under which a `body_models` directory should look like this:
|
|
@@ -111,7 +133,7 @@ $DATA_ROOT/body_models
|
|
|
111
133
|
└── smplx2smpl_deftrafo_setup.pkl
|
|
112
134
|
```
|
|
113
135
|
|
|
114
|
-
You can refer to the relevant [script](https://github.com/isarandi/
|
|
136
|
+
You can refer to the relevant [script](https://github.com/isarandi/posepile/tree/main/posepile/src/get_body_models.sh) in the PosePile repo about how to download these files.
|
|
115
137
|
|
|
116
138
|
## Usage Examples
|
|
117
139
|
|
|
@@ -121,8 +143,8 @@ You can refer to the relevant [script](https://github.com/isarandi/PosePile/tree
|
|
|
121
143
|
import torch
|
|
122
144
|
from smplfitter.pt import BodyModel, BodyFitter
|
|
123
145
|
|
|
124
|
-
body_model = BodyModel('smpl', 'neutral').cuda() # create the body model to be fitted
|
|
125
|
-
fitter = BodyFitter(body_model
|
|
146
|
+
body_model = BodyModel('smpl', 'neutral', num_betas=10).cuda() # create the body model to be fitted
|
|
147
|
+
fitter = BodyFitter(body_model).cuda() # create the fitter
|
|
126
148
|
fitter = torch.jit.script(fitter) # optional: compile the fitter for faster execution
|
|
127
149
|
|
|
128
150
|
# Obtain a batch of nonparametric vertex and joint locations (here we use dummy random data)
|
|
@@ -131,7 +153,7 @@ vertices = torch.rand((batch_size, 6890, 3)).cuda()
|
|
|
131
153
|
joints = torch.rand((batch_size, 24, 3)).cuda()
|
|
132
154
|
|
|
133
155
|
# Do the fitting!
|
|
134
|
-
fit_res = fitter.fit(vertices, joints,
|
|
156
|
+
fit_res = fitter.fit(vertices, joints, num_iter=3, beta_regularizer=1)
|
|
135
157
|
fit_res['pose_rotvecs'], fit_res['shape_betas'], fit_res['trans']
|
|
136
158
|
```
|
|
137
159
|
|
|
@@ -139,7 +161,7 @@ fit_res['pose_rotvecs'], fit_res['shape_betas'], fit_res['trans']
|
|
|
139
161
|
|
|
140
162
|
```python
|
|
141
163
|
import torch
|
|
142
|
-
from smplfitter.pt import BodyConverter
|
|
164
|
+
from smplfitter.pt import BodyModel, BodyConverter
|
|
143
165
|
|
|
144
166
|
bm_in = BodyModel('smpl', 'neutral')
|
|
145
167
|
bm_out = BodyModel('smplx', 'neutral')
|
|
@@ -158,11 +180,11 @@ out['pose_rotvecs'], out['shape_betas'], out['trans']
|
|
|
158
180
|
|
|
159
181
|
## The Algorithm
|
|
160
182
|
|
|
161
|
-
SMPL(-X/+H) is a parametric body model that takes body part orientations $\theta$ and body shape vector $\beta$ as inputs and yields vertex and joint locations as outputs.
|
|
183
|
+
SMPL(-X/+H) is a parametric body model that takes body part orientations $\theta$ and body shape vector $\beta$ as inputs and yields vertex and joint locations as outputs. SMPLFitter approximates the **inverse operation**: it takes vertex and joint locations as inputs and yields orientations $\theta$ and shape $\beta$ as outputs.
|
|
162
184
|
|
|
163
185
|
Our algorithm alternates between fitting orientations and fitting shape. A good result can be obtained already with 1-3 iterations.
|
|
164
186
|
|
|
165
|
-
We illustrate the steps with the following example. Given the depicted RGB image, we used [Neural Localizer Fields (NLF)](https://
|
|
187
|
+
We illustrate the steps with the following example. Given the depicted RGB image, we used [Neural Localizer Fields (NLF)](https://istvansarandi.com/nlf) to obtain nonparametric vertex and joint locations as follows:
|
|
166
188
|
|
|
167
189
|
<img src="docs/_static/images/image.png" alt="on_image" width="300"/>
|
|
168
190
|
<img src="docs/_static/images/on_image.png" alt="on_image" width="300"/>
|
|
@@ -18,11 +18,9 @@ It can fit a batch of 4096 instances in 423 ms on a single RTX 3090 GPU giving a
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
pip install
|
|
21
|
+
pip install smplfitter
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
(Packaging for PyPI is planned for later.)
|
|
25
|
-
|
|
26
24
|
### Download Body Model Files
|
|
27
25
|
|
|
28
26
|
You need to download the body model data files from the corresponding websites for this code to work. You only need the ones that you plan to use. There should be a `DATA_ROOT` environment variable under which a `body_models` directory should look like this:
|
|
@@ -52,7 +50,7 @@ $DATA_ROOT/body_models
|
|
|
52
50
|
└── smplx2smpl_deftrafo_setup.pkl
|
|
53
51
|
```
|
|
54
52
|
|
|
55
|
-
You can refer to the relevant [script](https://github.com/isarandi/
|
|
53
|
+
You can refer to the relevant [script](https://github.com/isarandi/posepile/tree/main/posepile/src/get_body_models.sh) in the PosePile repo about how to download these files.
|
|
56
54
|
|
|
57
55
|
## Usage Examples
|
|
58
56
|
|
|
@@ -62,8 +60,8 @@ You can refer to the relevant [script](https://github.com/isarandi/PosePile/tree
|
|
|
62
60
|
import torch
|
|
63
61
|
from smplfitter.pt import BodyModel, BodyFitter
|
|
64
62
|
|
|
65
|
-
body_model = BodyModel('smpl', 'neutral').cuda() # create the body model to be fitted
|
|
66
|
-
fitter = BodyFitter(body_model
|
|
63
|
+
body_model = BodyModel('smpl', 'neutral', num_betas=10).cuda() # create the body model to be fitted
|
|
64
|
+
fitter = BodyFitter(body_model).cuda() # create the fitter
|
|
67
65
|
fitter = torch.jit.script(fitter) # optional: compile the fitter for faster execution
|
|
68
66
|
|
|
69
67
|
# Obtain a batch of nonparametric vertex and joint locations (here we use dummy random data)
|
|
@@ -72,7 +70,7 @@ vertices = torch.rand((batch_size, 6890, 3)).cuda()
|
|
|
72
70
|
joints = torch.rand((batch_size, 24, 3)).cuda()
|
|
73
71
|
|
|
74
72
|
# Do the fitting!
|
|
75
|
-
fit_res = fitter.fit(vertices, joints,
|
|
73
|
+
fit_res = fitter.fit(vertices, joints, num_iter=3, beta_regularizer=1)
|
|
76
74
|
fit_res['pose_rotvecs'], fit_res['shape_betas'], fit_res['trans']
|
|
77
75
|
```
|
|
78
76
|
|
|
@@ -80,7 +78,7 @@ fit_res['pose_rotvecs'], fit_res['shape_betas'], fit_res['trans']
|
|
|
80
78
|
|
|
81
79
|
```python
|
|
82
80
|
import torch
|
|
83
|
-
from smplfitter.pt import BodyConverter
|
|
81
|
+
from smplfitter.pt import BodyModel, BodyConverter
|
|
84
82
|
|
|
85
83
|
bm_in = BodyModel('smpl', 'neutral')
|
|
86
84
|
bm_out = BodyModel('smplx', 'neutral')
|
|
@@ -99,11 +97,11 @@ out['pose_rotvecs'], out['shape_betas'], out['trans']
|
|
|
99
97
|
|
|
100
98
|
## The Algorithm
|
|
101
99
|
|
|
102
|
-
SMPL(-X/+H) is a parametric body model that takes body part orientations $\theta$ and body shape vector $\beta$ as inputs and yields vertex and joint locations as outputs.
|
|
100
|
+
SMPL(-X/+H) is a parametric body model that takes body part orientations $\theta$ and body shape vector $\beta$ as inputs and yields vertex and joint locations as outputs. SMPLFitter approximates the **inverse operation**: it takes vertex and joint locations as inputs and yields orientations $\theta$ and shape $\beta$ as outputs.
|
|
103
101
|
|
|
104
102
|
Our algorithm alternates between fitting orientations and fitting shape. A good result can be obtained already with 1-3 iterations.
|
|
105
103
|
|
|
106
|
-
We illustrate the steps with the following example. Given the depicted RGB image, we used [Neural Localizer Fields (NLF)](https://
|
|
104
|
+
We illustrate the steps with the following example. Given the depicted RGB image, we used [Neural Localizer Fields (NLF)](https://istvansarandi.com/nlf) to obtain nonparametric vertex and joint locations as follows:
|
|
107
105
|
|
|
108
106
|
<img src="docs/_static/images/image.png" alt="on_image" width="300"/>
|
|
109
107
|
<img src="docs/_static/images/on_image.png" alt="on_image" width="300"/>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Benchmark Results
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
## Summary (RTX 4090)
|
|
6
|
+
|
|
7
|
+
**With Vertices (batch=64):**
|
|
8
|
+
| Backend | Throughput |
|
|
9
|
+
|---------|------------|
|
|
10
|
+
| NumPy | 83/sec |
|
|
11
|
+
| Numba | 2,600/sec |
|
|
12
|
+
| PT compile GPU | **64,000/sec** |
|
|
13
|
+
| TF function GPU | 40,000/sec |
|
|
14
|
+
|
|
15
|
+
**Joints Only (batch=64):**
|
|
16
|
+
| Backend | Throughput |
|
|
17
|
+
|---------|------------|
|
|
18
|
+
| Numba | **152,000/sec** |
|
|
19
|
+
| NumPy | 95,000/sec |
|
|
20
|
+
| PT compile GPU | 69,000/sec |
|
|
21
|
+
|
|
22
|
+
For joints-only, CPU backends win due to GPU kernel overhead.
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
python benchmark/run_benchmark.py # Generate results.json
|
|
28
|
+
python benchmark/plot_results.py # Generate plots
|
|
29
|
+
```
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Benchmark full body model: NumPy vs Numba vs Cython."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def benchmark(func, inputs, n_warmup=3, n_iter=50):
|
|
8
|
+
"""Run benchmark and return mean time in ms."""
|
|
9
|
+
# Warmup
|
|
10
|
+
for _ in range(n_warmup):
|
|
11
|
+
func(**inputs)
|
|
12
|
+
|
|
13
|
+
# Timed runs
|
|
14
|
+
start = time.perf_counter()
|
|
15
|
+
for _ in range(n_iter):
|
|
16
|
+
func(**inputs)
|
|
17
|
+
elapsed = time.perf_counter() - start
|
|
18
|
+
return elapsed / n_iter * 1000 # ms
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def main():
|
|
22
|
+
import smplfitter.np as smpl_np
|
|
23
|
+
import smplfitter.nb as smpl_nb
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
import smplfitter.cy.bodymodel as smpl_cy
|
|
27
|
+
|
|
28
|
+
has_cython = True
|
|
29
|
+
except ImportError as e:
|
|
30
|
+
print(f'Cython not built: {e}')
|
|
31
|
+
print('Run: python setup_cy.py build_ext --inplace')
|
|
32
|
+
has_cython = False
|
|
33
|
+
|
|
34
|
+
print('Benchmarking BodyModel forward pass')
|
|
35
|
+
print('=' * 70)
|
|
36
|
+
|
|
37
|
+
for model_name in ['smpl']:
|
|
38
|
+
print(f'\nModel: {model_name.upper()}')
|
|
39
|
+
|
|
40
|
+
model_np = smpl_np.BodyModel(model_name=model_name, num_betas=10)
|
|
41
|
+
model_nb = smpl_nb.BodyModel(model_name=model_name, num_betas=10)
|
|
42
|
+
if has_cython:
|
|
43
|
+
model_cy = smpl_cy.BodyModel(model_name=model_name, num_betas=10)
|
|
44
|
+
|
|
45
|
+
num_joints = model_np.num_joints
|
|
46
|
+
|
|
47
|
+
for return_vertices in [False, True]:
|
|
48
|
+
mode = 'with_vertices' if return_vertices else 'joints_only'
|
|
49
|
+
print(f'\n Mode: {mode}')
|
|
50
|
+
|
|
51
|
+
for batch_size in [1, 8, 32, 128, 512]:
|
|
52
|
+
pose = np.random.randn(batch_size, num_joints * 3).astype(np.float32) * 0.1
|
|
53
|
+
shape = np.random.randn(batch_size, 10).astype(np.float32) * 0.5
|
|
54
|
+
trans = np.random.randn(batch_size, 3).astype(np.float32)
|
|
55
|
+
|
|
56
|
+
inputs = dict(
|
|
57
|
+
pose_rotvecs=pose,
|
|
58
|
+
shape_betas=shape,
|
|
59
|
+
trans=trans,
|
|
60
|
+
return_vertices=return_vertices,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
time_np = benchmark(model_np, inputs)
|
|
64
|
+
time_nb = benchmark(model_nb, inputs)
|
|
65
|
+
|
|
66
|
+
print(f'\n batch={batch_size:3d}')
|
|
67
|
+
print(
|
|
68
|
+
f' NumPy: {time_np:8.3f} ms ({batch_size/time_np*1000:8.0f} items/sec)'
|
|
69
|
+
)
|
|
70
|
+
print(
|
|
71
|
+
f' Numba: {time_nb:8.3f} ms ({batch_size/time_nb*1000:8.0f} items/sec) {time_np/time_nb:5.1f}x vs NumPy'
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
if has_cython:
|
|
75
|
+
time_cy = benchmark(model_cy, inputs)
|
|
76
|
+
print(
|
|
77
|
+
f' Cython: {time_cy:8.3f} ms ({batch_size/time_cy*1000:8.0f} items/sec) {time_np/time_cy:5.1f}x vs NumPy, {time_nb/time_cy:5.2f}x vs Numba'
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Verify correctness
|
|
81
|
+
result_np = model_np(**inputs)
|
|
82
|
+
result_nb = model_nb(**inputs)
|
|
83
|
+
|
|
84
|
+
if not np.allclose(result_np['joints'], result_nb['joints'], atol=1e-4):
|
|
85
|
+
print(' WARNING: Numba joints differ!')
|
|
86
|
+
if return_vertices and not np.allclose(
|
|
87
|
+
result_np['vertices'], result_nb['vertices'], atol=1e-4
|
|
88
|
+
):
|
|
89
|
+
print(' WARNING: Numba vertices differ!')
|
|
90
|
+
|
|
91
|
+
if has_cython:
|
|
92
|
+
result_cy = model_cy(**inputs)
|
|
93
|
+
if not np.allclose(result_np['joints'], result_cy['joints'], atol=1e-4):
|
|
94
|
+
print(' WARNING: Cython joints differ!')
|
|
95
|
+
diff = np.abs(result_np['joints'] - result_cy['joints']).max()
|
|
96
|
+
print(f' Max diff: {diff}')
|
|
97
|
+
if return_vertices and not np.allclose(
|
|
98
|
+
result_np['vertices'], result_cy['vertices'], atol=1e-4
|
|
99
|
+
):
|
|
100
|
+
print(' WARNING: Cython vertices differ!')
|
|
101
|
+
diff = np.abs(result_np['vertices'] - result_cy['vertices']).max()
|
|
102
|
+
print(f' Max diff: {diff}')
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
if __name__ == '__main__':
|
|
106
|
+
main()
|