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.
Files changed (139) hide show
  1. smplfitter-0.3.2.dev0/.editorconfig +18 -0
  2. smplfitter-0.3.2.dev0/.github/dependabot.yml +11 -0
  3. smplfitter-0.3.2.dev0/.github/workflows/ci.yml +27 -0
  4. smplfitter-0.3.2.dev0/.github/workflows/python-publish.yml +80 -0
  5. smplfitter-0.3.2.dev0/.pre-commit-config.yaml +17 -0
  6. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/.readthedocs.yaml +1 -2
  7. smplfitter-0.3.2.dev0/Makefile +22 -0
  8. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/PKG-INFO +51 -29
  9. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/README.md +8 -10
  10. smplfitter-0.3.2.dev0/benchmark/README.md +29 -0
  11. smplfitter-0.3.2.dev0/benchmark/bench_bodymodel.py +106 -0
  12. smplfitter-0.3.2.dev0/benchmark/bench_converter.py +354 -0
  13. smplfitter-0.3.2.dev0/benchmark/bench_rotvec.py +66 -0
  14. smplfitter-0.3.2.dev0/benchmark/benchmark.png +0 -0
  15. smplfitter-0.3.2.dev0/benchmark/benchmark_smpl.png +0 -0
  16. smplfitter-0.3.2.dev0/benchmark/benchmark_smplx.png +0 -0
  17. smplfitter-0.3.2.dev0/benchmark/benchmark_vs_smplx.png +0 -0
  18. smplfitter-0.3.2.dev0/benchmark/benchmark_vs_smplx_smpl.png +0 -0
  19. smplfitter-0.3.2.dev0/benchmark/benchmark_vs_smplx_smplx.png +0 -0
  20. smplfitter-0.3.2.dev0/benchmark/plot_results.py +136 -0
  21. smplfitter-0.3.2.dev0/benchmark/run_benchmark.py +558 -0
  22. smplfitter-0.3.2.dev0/docs/Makefile +20 -0
  23. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/conf.py +60 -43
  24. smplfitter-0.3.2.dev0/docs/howto.rst +422 -0
  25. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/index.rst +3 -2
  26. smplfitter-0.3.2.dev0/docs/make.bat +35 -0
  27. smplfitter-0.3.2.dev0/docs/smpl_to_smplx.rst +133 -0
  28. smplfitter-0.3.2.dev0/pyproject.toml +110 -0
  29. smplfitter-0.3.2.dev0/src/smplfitter/__init__.py +20 -0
  30. smplfitter-0.3.2.dev0/src/smplfitter/_version.py +34 -0
  31. smplfitter-0.3.2.dev0/src/smplfitter/common.py +250 -0
  32. smplfitter-0.3.2.dev0/src/smplfitter/decimation/__init__.py +1 -0
  33. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/decimation/decimate_body_models.py +3 -2
  34. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/decimation/make_post_lbs_joint_regressors.py +6 -5
  35. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/decimation/make_post_lbs_joint_regressors_tf.py +8 -5
  36. smplfitter-0.3.2.dev0/src/smplfitter/download.py +412 -0
  37. smplfitter-0.3.2.dev0/src/smplfitter/jax/__init__.py +25 -0
  38. smplfitter-0.3.2.dev0/src/smplfitter/jax/bodyconverter.py +156 -0
  39. smplfitter-0.3.2.dev0/src/smplfitter/jax/bodyfitter.py +1004 -0
  40. smplfitter-0.3.2.dev0/src/smplfitter/jax/bodymodel.py +189 -0
  41. smplfitter-0.3.2.dev0/src/smplfitter/jax/lstsq.py +119 -0
  42. smplfitter-0.3.2.dev0/src/smplfitter/jax/rotation.py +98 -0
  43. smplfitter-0.3.2.dev0/src/smplfitter/nb/__init__.py +25 -0
  44. smplfitter-0.3.2.dev0/src/smplfitter/nb/bodyconverter.py +153 -0
  45. smplfitter-0.3.2.dev0/src/smplfitter/nb/bodyfitter.py +1321 -0
  46. smplfitter-0.3.2.dev0/src/smplfitter/nb/bodymodel.py +443 -0
  47. smplfitter-0.3.2.dev0/src/smplfitter/nb/lstsq.py +315 -0
  48. smplfitter-0.3.2.dev0/src/smplfitter/nb/precompile.py +109 -0
  49. smplfitter-0.3.2.dev0/src/smplfitter/nb/rotation.py +120 -0
  50. smplfitter-0.3.2.dev0/src/smplfitter/nb/util.py +58 -0
  51. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/__init__.py +7 -3
  52. smplfitter-0.3.2.dev0/src/smplfitter/np/bodyconverter.py +153 -0
  53. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/bodyfitter.py +430 -89
  54. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/bodymodel.py +54 -26
  55. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/lstsq.py +11 -4
  56. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/rotation.py +2 -1
  57. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/np/util.py +1 -0
  58. smplfitter-0.3.2.dev0/src/smplfitter/pt/__init__.py +158 -0
  59. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/bodyconverter.py +4 -2
  60. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/bodyfitter.py +93 -87
  61. smplfitter-0.3.2.dev0/src/smplfitter/pt/bodyfitter_opt.py +255 -0
  62. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/bodyflipper.py +8 -8
  63. smplfitter-0.3.2.dev0/src/smplfitter/pt/bodyflipper_opt.py +181 -0
  64. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/bodymodel.py +41 -24
  65. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/handreplacer.py +4 -3
  66. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/lstsq.py +6 -4
  67. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/pt/rotation.py +9 -2
  68. smplfitter-0.3.2.dev0/src/smplfitter/tf/__init__.py +188 -0
  69. smplfitter-0.3.2.dev0/src/smplfitter/tf/bodyconverter.py +168 -0
  70. smplfitter-0.3.2.dev0/src/smplfitter/tf/bodyfitter.py +1074 -0
  71. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/tf/bodymodel.py +50 -24
  72. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/tf/lstsq.py +28 -4
  73. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/tf/rotation.py +1 -0
  74. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter/tf/util.py +1 -0
  75. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter.egg-info/PKG-INFO +51 -29
  76. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter.egg-info/SOURCES.txt +43 -3
  77. smplfitter-0.3.2.dev0/src/smplfitter.egg-info/requires.txt +38 -0
  78. smplfitter-0.3.2.dev0/tests/conftest.py +200 -0
  79. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/tests/np/test_bodymodel.py +1 -2
  80. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/tests/pt/test_bodymodel.py +1 -8
  81. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/tests/pt/test_converter.py +9 -9
  82. smplfitter-0.3.2.dev0/tests/pt/test_flipper.py +74 -0
  83. smplfitter-0.3.2.dev0/tests/test_converter_common.py +120 -0
  84. smplfitter-0.3.2.dev0/tests/test_fitter_common.py +331 -0
  85. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/tests/test_forward.py +2 -6
  86. smplfitter-0.2.10/.github/workflows/python-publish.yml +0 -35
  87. smplfitter-0.2.10/docs/modules.rst +0 -10
  88. smplfitter-0.2.10/pyproject.toml +0 -69
  89. smplfitter-0.2.10/src/smplfitter/__init__.py +0 -7
  90. smplfitter-0.2.10/src/smplfitter/_version.py +0 -21
  91. smplfitter-0.2.10/src/smplfitter/common.py +0 -166
  92. smplfitter-0.2.10/src/smplfitter/pt/__init__.py +0 -94
  93. smplfitter-0.2.10/src/smplfitter/tf/__init__.py +0 -107
  94. smplfitter-0.2.10/src/smplfitter/tf/bodyfitter.py +0 -655
  95. smplfitter-0.2.10/src/smplfitter.egg-info/requires.txt +0 -26
  96. smplfitter-0.2.10/tests/np/test_fitter.py +0 -29
  97. smplfitter-0.2.10/tests/pt/__init__.py +0 -0
  98. smplfitter-0.2.10/tests/pt/test_fitter.py +0 -36
  99. smplfitter-0.2.10/tests/pt/test_flipper.py +0 -36
  100. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/.gitignore +0 -0
  101. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/LICENSE +0 -0
  102. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/example.gif +0 -0
  103. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/image.png +0 -0
  104. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/image_example.jpg +0 -0
  105. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/on_image.png +0 -0
  106. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/on_image_fit.png +0 -0
  107. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/overlay_after_rot1.png +0 -0
  108. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/overlay_after_rot1_shape.png +0 -0
  109. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/overlay_after_rot2.png +0 -0
  110. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/overlay_after_rot2_shape.png +0 -0
  111. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/overlay_after_rot3.png +0 -0
  112. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/parts_overlay1.png +0 -0
  113. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/parts_overlay1_rot.png +0 -0
  114. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/parts_overlay2.png +0 -0
  115. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/parts_overlay2_rot.png +0 -0
  116. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/pose3d.png +0 -0
  117. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/pose3d_parts_color.png +0 -0
  118. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/pose3d_parts_color_blown.png +0 -0
  119. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/tmean_parts.png +0 -0
  120. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/images/tmean_parts_blown.png +0 -0
  121. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_static/styles/my_theme.css +0 -0
  122. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/index.rst +0 -0
  123. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/attribute.rst +0 -0
  124. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/class.rst +0 -0
  125. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/data.rst +0 -0
  126. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/exception.rst +0 -0
  127. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/function.rst +0 -0
  128. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/method.rst +0 -0
  129. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/module.rst +0 -0
  130. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/package.rst +0 -0
  131. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/autoapi/python/property.rst +0 -0
  132. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/_templates/copyright.html +0 -0
  133. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/abbrev_long.bib +0 -0
  134. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/docs/references.bib +0 -0
  135. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/setup.cfg +0 -0
  136. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter.egg-info/dependency_links.txt +0 -0
  137. {smplfitter-0.2.10 → smplfitter-0.3.2.dev0}/src/smplfitter.egg-info/top_level.txt +0 -0
  138. {smplfitter-0.2.10/src/smplfitter/decimation → smplfitter-0.3.2.dev0/tests/np}/__init__.py +0 -0
  139. {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,11 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+
8
+ - package-ecosystem: "github-actions"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
@@ -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
@@ -5,8 +5,7 @@ build:
5
5
  tools:
6
6
  python: "3.10"
7
7
  commands:
8
- - python -m pip install .
9
- - python -m pip install --no-cache-dir -r docs/requirements.txt
8
+ - python -m pip install ".[docs]"
10
9
  - python -m sphinx -E -b html docs $READTHEDOCS_OUTPUT/html
11
10
 
12
11
  sphinx:
@@ -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.10
4
- Summary: Fast inverse kinematics and shape fitting for SMPL-family models in NumPy, PyTorch, and TensorFlow
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
- Requires-Python: >=3.6
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: keywords
43
- Requires-Dist: smpl; extra == "keywords"
44
- Requires-Dist: smplx; extra == "keywords"
45
- Requires-Dist: smplh; extra == "keywords"
46
- Requires-Dist: 3d-human; extra == "keywords"
47
- Requires-Dist: body-model; extra == "keywords"
48
- Requires-Dist: ik; extra == "keywords"
49
- Requires-Dist: inverse-kinematics; extra == "keywords"
50
- Requires-Dist: parametric-model; extra == "keywords"
51
- Requires-Dist: pose-estimation; extra == "keywords"
52
- Requires-Dist: differentiable; extra == "keywords"
53
- Requires-Dist: gpu; extra == "keywords"
54
- Requires-Dist: tensorflow; extra == "keywords"
55
- Requires-Dist: pytorch; extra == "keywords"
56
- Requires-Dist: numpy; extra == "keywords"
57
- Requires-Dist: batch-processing; extra == "keywords"
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 git+https://github.com/isarandi/smplfitter.git
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/PosePile/tree/main/posepile/get_body_models.sh) in the PosePile repo about how to download these files.
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, num_betas=10).cuda() # create the fitter
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, n_iter=3, beta_regularizer=1)
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. SMPLfit approximates the **inverse operation**: it takes vertex and joint locations as inputs and yields orientations $\theta$ and shape $\beta$ 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://virtualhumans.mpi-inf.mpg.de/nlf) to obtain nonparametric vertex and joint locations as follows:
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 git+https://github.com/isarandi/smplfitter.git
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/PosePile/tree/main/posepile/get_body_models.sh) in the PosePile repo about how to download these files.
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, num_betas=10).cuda() # create the fitter
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, n_iter=3, beta_regularizer=1)
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. SMPLfit approximates the **inverse operation**: it takes vertex and joint locations as inputs and yields orientations $\theta$ and shape $\beta$ 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://virtualhumans.mpi-inf.mpg.de/nlf) to obtain nonparametric vertex and joint locations as follows:
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
+ ![Benchmark](benchmark.png)
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()