dungntdz commited on
Commit
8d5568e
·
verified ·
1 Parent(s): 621bc67

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +156 -0
  2. GPT_eval_multi.py +121 -0
  3. LICENSE +201 -0
  4. README.md +8 -0
  5. VQ_eval.py +95 -0
  6. app.py +379 -0
  7. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/.gitattributes +34 -0
  8. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/README.md +15 -0
  9. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualization/plot_3d_global.py +129 -0
  10. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/joints2smpl/src/config.py +40 -0
  11. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/joints2smpl/src/customloss.py +222 -0
  12. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/joints2smpl/src/prior.py +230 -0
  13. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/joints2smpl/src/smplify.py +279 -0
  14. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/render_mesh.py +33 -0
  15. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/simplify_loc2rot.py +131 -0
  16. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/vis_utils.py +66 -0
  17. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/app.py +329 -0
  18. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/packages.txt +4 -0
  19. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/.coveragerc +5 -0
  20. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/.flake8 +8 -0
  21. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/.gitignore +106 -0
  22. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/.pre-commit-config.yaml +6 -0
  23. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/.travis.yml +43 -0
  24. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/LICENSE +21 -0
  25. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/MANIFEST.in +5 -0
  26. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/README.md +92 -0
  27. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/Makefile +23 -0
  28. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/make.bat +35 -0
  29. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/api/index.rst +59 -0
  30. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/conf.py +352 -0
  31. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/examples/cameras.rst +26 -0
  32. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/examples/index.rst +20 -0
  33. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/examples/lighting.rst +21 -0
  34. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/examples/models.rst +143 -0
  35. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/examples/offscreen.rst +87 -0
  36. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/index.rst +41 -0
  37. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/requirements.txt +14 -0
  38. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/setup.py +76 -0
  39. c125d6fbf8bda65345b6edda6e04f79faf4d67cd/requirements.txt +27 -0
  40. checkpoints/kit/kit/Comp_v6_KLD005/opt.txt +54 -0
  41. checkpoints/kit/kit/text_mot_match/eval/E005.txt +4 -0
  42. checkpoints/kit/kit/text_mot_match/eval/E010.txt +4 -0
  43. checkpoints/kit/kit/text_mot_match/eval/E015.txt +4 -0
  44. checkpoints/kit/kit/text_mot_match/eval/E020.txt +4 -0
  45. checkpoints/kit/kit/text_mot_match/eval/E025.txt +4 -0
  46. checkpoints/kit/kit/text_mot_match/eval/E030.txt +4 -0
  47. checkpoints/kit/kit/text_mot_match/eval/E035.txt +4 -0
  48. checkpoints/kit/kit/text_mot_match/eval/E040.txt +4 -0
  49. checkpoints/kit/kit/text_mot_match/eval/E045.txt +4 -0
  50. checkpoints/kit/kit/text_mot_match/eval/E050.txt +4 -0
.gitignore ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
90
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
91
+ # install all needed dependencies.
92
+ #Pipfile.lock
93
+
94
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95
+ __pypackages__/
96
+
97
+ # Celery stuff
98
+ celerybeat-schedule
99
+ celerybeat.pid
100
+
101
+ # SageMath parsed files
102
+ *.sage.py
103
+
104
+ # Environments
105
+ .env
106
+ .venv
107
+ env/
108
+ venv/
109
+ ENV/
110
+ env.bak/
111
+ venv.bak/
112
+
113
+ # Spyder project settings
114
+ .spyderproject
115
+ .spyproject
116
+
117
+ # Rope project settings
118
+ .ropeproject
119
+
120
+ # mkdocs documentation
121
+ /site
122
+
123
+ # mypy
124
+ .mypy_cache/
125
+ .dmypy.json
126
+ dmypy.json
127
+
128
+ # Pyre type checker
129
+ .pyre/
130
+
131
+ .vscode
132
+ dataset/dataset_TM_train_cb1_temp.py
133
+ train_gpt_cnn_temp.py
134
+ train_gpt_cnn_mask.py
135
+ start.sh
136
+ start_eval.sh
137
+ config.json
138
+ output_GPT_Final
139
+ output_vqfinal
140
+ output_transformer
141
+ glove
142
+ checkpoints
143
+ dataset/HumanML3D
144
+ dataset/KIT-ML
145
+ output
146
+ matrix_multi.py
147
+ body_models
148
+ render_final_diffuse.py
149
+ render_final_mdm.py
150
+ pretrained
151
+ MDM
152
+ Motiondiffusion
153
+ Visualize_temp.py
154
+ new.sh
155
+ T2M_render
156
+ render_final_t2m.py
GPT_eval_multi.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import numpy as np
4
+ from torch.utils.tensorboard import SummaryWriter
5
+ import json
6
+ import clip
7
+
8
+ import options.option_transformer as option_trans
9
+ import models.vqvae as vqvae
10
+ import utils.utils_model as utils_model
11
+ import utils.eval_trans as eval_trans
12
+ from dataset import dataset_TM_eval
13
+ import models.t2m_trans as trans
14
+ from options.get_eval_option import get_opt
15
+ from models.evaluator_wrapper import EvaluatorModelWrapper
16
+ import warnings
17
+ warnings.filterwarnings('ignore')
18
+
19
+ ##### ---- Exp dirs ---- #####
20
+ args = option_trans.get_args_parser()
21
+ torch.manual_seed(args.seed)
22
+
23
+ args.out_dir = os.path.join(args.out_dir, f'{args.exp_name}')
24
+ os.makedirs(args.out_dir, exist_ok = True)
25
+
26
+ ##### ---- Logger ---- #####
27
+ logger = utils_model.get_logger(args.out_dir)
28
+ writer = SummaryWriter(args.out_dir)
29
+ logger.info(json.dumps(vars(args), indent=4, sort_keys=True))
30
+
31
+ from utils.word_vectorizer import WordVectorizer
32
+ w_vectorizer = WordVectorizer('./glove', 'our_vab')
33
+ val_loader = dataset_TM_eval.DATALoader(args.dataname, True, 32, w_vectorizer)
34
+
35
+ dataset_opt_path = 'checkpoints/kit/Comp_v6_KLD005/opt.txt' if args.dataname == 'kit' else 'checkpoints/t2m/Comp_v6_KLD005/opt.txt'
36
+
37
+ wrapper_opt = get_opt(dataset_opt_path, torch.device('cuda'))
38
+ eval_wrapper = EvaluatorModelWrapper(wrapper_opt)
39
+
40
+ ##### ---- Network ---- #####
41
+
42
+ ## load clip model and datasets
43
+ clip_model, clip_preprocess = clip.load("ViT-B/32", device=torch.device('cuda'), jit=False) # Must set jit=False for training
44
+ clip.model.convert_weights(clip_model) # Actually this line is unnecessary since clip by default already on float16
45
+ clip_model.eval()
46
+ for p in clip_model.parameters():
47
+ p.requires_grad = False
48
+
49
+ net = vqvae.HumanVQVAE(args, ## use args to define different parameters in different quantizers
50
+ args.nb_code,
51
+ args.code_dim,
52
+ args.output_emb_width,
53
+ args.down_t,
54
+ args.stride_t,
55
+ args.width,
56
+ args.depth,
57
+ args.dilation_growth_rate)
58
+
59
+
60
+ trans_encoder = trans.Text2Motion_Transformer(num_vq=args.nb_code,
61
+ embed_dim=args.embed_dim_gpt,
62
+ clip_dim=args.clip_dim,
63
+ block_size=args.block_size,
64
+ num_layers=args.num_layers,
65
+ n_head=args.n_head_gpt,
66
+ drop_out_rate=args.drop_out_rate,
67
+ fc_rate=args.ff_rate)
68
+
69
+
70
+ print ('loading checkpoint from {}'.format(args.resume_pth))
71
+ ckpt = torch.load(args.resume_pth, map_location='cpu')
72
+ net.load_state_dict(ckpt['net'], strict=True)
73
+ net.eval()
74
+ net.cuda()
75
+
76
+ if args.resume_trans is not None:
77
+ print ('loading transformer checkpoint from {}'.format(args.resume_trans))
78
+ ckpt = torch.load(args.resume_trans, map_location='cpu')
79
+ trans_encoder.load_state_dict(ckpt['trans'], strict=True)
80
+ trans_encoder.train()
81
+ trans_encoder.cuda()
82
+
83
+
84
+ fid = []
85
+ div = []
86
+ top1 = []
87
+ top2 = []
88
+ top3 = []
89
+ matching = []
90
+ multi = []
91
+ repeat_time = 20
92
+
93
+
94
+ for i in range(repeat_time):
95
+ best_fid, best_iter, best_div, best_top1, best_top2, best_top3, best_matching, best_multi, writer, logger = eval_trans.evaluation_transformer_test(args.out_dir, val_loader, net, trans_encoder, logger, writer, 0, best_fid=1000, best_iter=0, best_div=100, best_top1=0, best_top2=0, best_top3=0, best_matching=100, best_multi=0, clip_model=clip_model, eval_wrapper=eval_wrapper, draw=False, savegif=False, save=False, savenpy=(i==0))
96
+ fid.append(best_fid)
97
+ div.append(best_div)
98
+ top1.append(best_top1)
99
+ top2.append(best_top2)
100
+ top3.append(best_top3)
101
+ matching.append(best_matching)
102
+ multi.append(best_multi)
103
+
104
+ print('final result:')
105
+ print('fid: ', sum(fid)/repeat_time)
106
+ print('div: ', sum(div)/repeat_time)
107
+ print('top1: ', sum(top1)/repeat_time)
108
+ print('top2: ', sum(top2)/repeat_time)
109
+ print('top3: ', sum(top3)/repeat_time)
110
+ print('matching: ', sum(matching)/repeat_time)
111
+ print('multi: ', sum(multi)/repeat_time)
112
+
113
+ fid = np.array(fid)
114
+ div = np.array(div)
115
+ top1 = np.array(top1)
116
+ top2 = np.array(top2)
117
+ top3 = np.array(top3)
118
+ matching = np.array(matching)
119
+ multi = np.array(multi)
120
+ msg_final = f"FID. {np.mean(fid):.3f}, conf. {np.std(fid)*1.96/np.sqrt(repeat_time):.3f}, Diversity. {np.mean(div):.3f}, conf. {np.std(div)*1.96/np.sqrt(repeat_time):.3f}, TOP1. {np.mean(top1):.3f}, conf. {np.std(top1)*1.96/np.sqrt(repeat_time):.3f}, TOP2. {np.mean(top2):.3f}, conf. {np.std(top2)*1.96/np.sqrt(repeat_time):.3f}, TOP3. {np.mean(top3):.3f}, conf. {np.std(top3)*1.96/np.sqrt(repeat_time):.3f}, Matching. {np.mean(matching):.3f}, conf. {np.std(matching)*1.96/np.sqrt(repeat_time):.3f}, Multi. {np.mean(multi):.3f}, conf. {np.std(multi)*1.96/np.sqrt(repeat_time):.3f}"
121
+ logger.info(msg_final)
LICENSE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2023 tencent
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
README.md ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: T2M-GPT
3
+ app_file: app.py
4
+ sdk: gradio
5
+ sdk_version: 3.50.2
6
+ ---
7
+
8
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
VQ_eval.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+
4
+ import torch
5
+ from torch.utils.tensorboard import SummaryWriter
6
+ import numpy as np
7
+ import models.vqvae as vqvae
8
+ import options.option_vq as option_vq
9
+ import utils.utils_model as utils_model
10
+ from dataset import dataset_TM_eval
11
+ import utils.eval_trans as eval_trans
12
+ from options.get_eval_option import get_opt
13
+ from models.evaluator_wrapper import EvaluatorModelWrapper
14
+ import warnings
15
+ warnings.filterwarnings('ignore')
16
+ import numpy as np
17
+ ##### ---- Exp dirs ---- #####
18
+ args = option_vq.get_args_parser()
19
+ torch.manual_seed(args.seed)
20
+
21
+ args.out_dir = os.path.join(args.out_dir, f'{args.exp_name}')
22
+ os.makedirs(args.out_dir, exist_ok = True)
23
+
24
+ ##### ---- Logger ---- #####
25
+ logger = utils_model.get_logger(args.out_dir)
26
+ writer = SummaryWriter(args.out_dir)
27
+ logger.info(json.dumps(vars(args), indent=4, sort_keys=True))
28
+
29
+
30
+ from utils.word_vectorizer import WordVectorizer
31
+ w_vectorizer = WordVectorizer('./glove', 'our_vab')
32
+
33
+
34
+ dataset_opt_path = 'checkpoints/kit/Comp_v6_KLD005/opt.txt' if args.dataname == 'kit' else 'checkpoints/t2m/Comp_v6_KLD005/opt.txt'
35
+
36
+ wrapper_opt = get_opt(dataset_opt_path, torch.device('cuda'))
37
+ eval_wrapper = EvaluatorModelWrapper(wrapper_opt)
38
+
39
+
40
+ ##### ---- Dataloader ---- #####
41
+ args.nb_joints = 21 if args.dataname == 'kit' else 22
42
+
43
+ val_loader = dataset_TM_eval.DATALoader(args.dataname, True, 32, w_vectorizer, unit_length=2**args.down_t)
44
+
45
+ ##### ---- Network ---- #####
46
+ net = vqvae.HumanVQVAE(args, ## use args to define different parameters in different quantizers
47
+ args.nb_code,
48
+ args.code_dim,
49
+ args.output_emb_width,
50
+ args.down_t,
51
+ args.stride_t,
52
+ args.width,
53
+ args.depth,
54
+ args.dilation_growth_rate,
55
+ args.vq_act,
56
+ args.vq_norm)
57
+
58
+ if args.resume_pth :
59
+ logger.info('loading checkpoint from {}'.format(args.resume_pth))
60
+ ckpt = torch.load(args.resume_pth, map_location='cpu')
61
+ net.load_state_dict(ckpt['net'], strict=True)
62
+ net.train()
63
+ net.cuda()
64
+
65
+ fid = []
66
+ div = []
67
+ top1 = []
68
+ top2 = []
69
+ top3 = []
70
+ matching = []
71
+ repeat_time = 20
72
+ for i in range(repeat_time):
73
+ best_fid, best_iter, best_div, best_top1, best_top2, best_top3, best_matching, writer, logger = eval_trans.evaluation_vqvae(args.out_dir, val_loader, net, logger, writer, 0, best_fid=1000, best_iter=0, best_div=100, best_top1=0, best_top2=0, best_top3=0, best_matching=100, eval_wrapper=eval_wrapper, draw=False, save=False, savenpy=(i==0))
74
+ fid.append(best_fid)
75
+ div.append(best_div)
76
+ top1.append(best_top1)
77
+ top2.append(best_top2)
78
+ top3.append(best_top3)
79
+ matching.append(best_matching)
80
+ print('final result:')
81
+ print('fid: ', sum(fid)/repeat_time)
82
+ print('div: ', sum(div)/repeat_time)
83
+ print('top1: ', sum(top1)/repeat_time)
84
+ print('top2: ', sum(top2)/repeat_time)
85
+ print('top3: ', sum(top3)/repeat_time)
86
+ print('matching: ', sum(matching)/repeat_time)
87
+
88
+ fid = np.array(fid)
89
+ div = np.array(div)
90
+ top1 = np.array(top1)
91
+ top2 = np.array(top2)
92
+ top3 = np.array(top3)
93
+ matching = np.array(matching)
94
+ msg_final = f"FID. {np.mean(fid):.3f}, conf. {np.std(fid)*1.96/np.sqrt(repeat_time):.3f}, Diversity. {np.mean(div):.3f}, conf. {np.std(div)*1.96/np.sqrt(repeat_time):.3f}, TOP1. {np.mean(top1):.3f}, conf. {np.std(top1)*1.96/np.sqrt(repeat_time):.3f}, TOP2. {np.mean(top2):.3f}, conf. {np.std(top2)*1.96/np.sqrt(repeat_time):.3f}, TOP3. {np.mean(top3):.3f}, conf. {np.std(top3)*1.96/np.sqrt(repeat_time):.3f}, Matching. {np.mean(matching):.3f}, conf. {np.std(matching)*1.96/np.sqrt(repeat_time):.3f}"
95
+ logger.info(msg_final)
app.py ADDED
@@ -0,0 +1,379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import os
3
+ import OpenGL.GL as gl
4
+ # os.environ["PYOPENGL_PLATFORM"] = "egl"
5
+ os.environ["MESA_GL_VERSION_OVERRIDE"] = "4.1"
6
+ # os.system('pip install /home/user/app/pyrender')
7
+
8
+ sys.argv = ['VQ-Trans/GPT_eval_multi.py']
9
+ os.chdir('VQ-Trans')
10
+
11
+ sys.path.append('./VQ-Trans')
12
+ sys.path.append('./pyrender')
13
+
14
+ import options.option_transformer as option_trans
15
+ from huggingface_hub import snapshot_download
16
+ model_path = snapshot_download(repo_id="vumichien/T2M-GPT")
17
+
18
+ args = option_trans.get_args_parser()
19
+
20
+ args.dataname = 't2m'
21
+ args.resume_pth = f'{model_path}/VQVAE/net_last.pth'
22
+ args.resume_trans = f'{model_path}/VQTransformer_corruption05/net_best_fid.pth'
23
+ args.down_t = 2
24
+ args.depth = 3
25
+ args.block_size = 51
26
+
27
+ import clip
28
+ import torch
29
+ import numpy as np
30
+ import models.vqvae as vqvae
31
+ import models.t2m_trans as trans
32
+ from utils.motion_process import recover_from_ric
33
+ import visualization.plot_3d_global as plot_3d
34
+ from models.rotation2xyz import Rotation2xyz
35
+ import numpy as np
36
+ from trimesh import Trimesh
37
+ import gc
38
+
39
+ import torch
40
+ from visualize.simplify_loc2rot import joints2smpl
41
+ import pyrender
42
+ # import matplotlib.pyplot as plt
43
+
44
+ import io
45
+ import imageio
46
+ from shapely import geometry
47
+ import trimesh
48
+ from pyrender.constants import RenderFlags
49
+ import math
50
+ # import ffmpeg
51
+ # from PIL import Image
52
+ import hashlib
53
+ import gradio as gr
54
+ import moviepy.editor as mp
55
+ from datetime import datetime
56
+
57
+ ## load clip model and datasets
58
+ is_cuda = torch.cuda.is_available()
59
+ device = torch.device("cuda" if is_cuda else "cpu")
60
+ print(device)
61
+ clip_model, clip_preprocess = clip.load("ViT-B/32", device=device, jit=False, download_root='./') # Must set jit=False for training
62
+
63
+ if is_cuda:
64
+ clip.model.convert_weights(clip_model)
65
+
66
+ clip_model.eval()
67
+ for p in clip_model.parameters():
68
+ p.requires_grad = False
69
+
70
+ net = vqvae.HumanVQVAE(args, ## use args to define different parameters in different quantizers
71
+ args.nb_code,
72
+ args.code_dim,
73
+ args.output_emb_width,
74
+ args.down_t,
75
+ args.stride_t,
76
+ args.width,
77
+ args.depth,
78
+ args.dilation_growth_rate)
79
+
80
+
81
+ trans_encoder = trans.Text2Motion_Transformer(num_vq=args.nb_code,
82
+ embed_dim=1024,
83
+ clip_dim=args.clip_dim,
84
+ block_size=args.block_size,
85
+ num_layers=9,
86
+ n_head=16,
87
+ drop_out_rate=args.drop_out_rate,
88
+ fc_rate=args.ff_rate)
89
+
90
+
91
+ print('loading checkpoint from {}'.format(args.resume_pth))
92
+ ckpt = torch.load(args.resume_pth, map_location='cpu')
93
+ net.load_state_dict(ckpt['net'], strict=True)
94
+ net.eval()
95
+
96
+ print('loading transformer checkpoint from {}'.format(args.resume_trans))
97
+ ckpt = torch.load(args.resume_trans, map_location='cpu')
98
+ trans_encoder.load_state_dict(ckpt['trans'], strict=True)
99
+ trans_encoder.eval()
100
+
101
+ mean = torch.from_numpy(np.load(f'{model_path}/meta/mean.npy'))
102
+ std = torch.from_numpy(np.load(f'{model_path}/meta/std.npy'))
103
+
104
+ if is_cuda:
105
+ net.cuda()
106
+ trans_encoder.cuda()
107
+ mean = mean.cuda()
108
+ std = std.cuda()
109
+
110
+ def ensure_directory(path):
111
+ """Tạo thư mục nếu chưa tồn tại"""
112
+ if not os.path.exists(path):
113
+ os.makedirs(path)
114
+ print(f"Created directory: {path}")
115
+
116
+ def get_output_path(output_dir, filename, extension):
117
+ """Tạo đường dẫn đầy đủ cho file output"""
118
+ ensure_directory(output_dir)
119
+ if not filename.endswith(extension):
120
+ filename += extension
121
+ return os.path.join(output_dir, filename)
122
+
123
+ def render(motions, output_dir='output', filename='results', device_id=0):
124
+ """
125
+ Render motion với tùy chọn thư mục và tên file
126
+
127
+ Args:
128
+ motions: Motion data
129
+ output_dir: Thư mục lưu kết quả (mặc định: 'output')
130
+ filename: Tên file không có extension (mặc định: 'results')
131
+ device_id: GPU device ID
132
+ """
133
+ frames, njoints, nfeats = motions.shape
134
+ MINS = motions.min(axis=0).min(axis=0)
135
+ MAXS = motions.max(axis=0).max(axis=0)
136
+
137
+ height_offset = MINS[1]
138
+ motions[:, :, 1] -= height_offset
139
+ trajec = motions[:, 0, [0, 2]]
140
+ is_cuda = torch.cuda.is_available()
141
+ j2s = joints2smpl(num_frames=frames, device_id=0, cuda=is_cuda)
142
+ rot2xyz = Rotation2xyz(device=device)
143
+ faces = rot2xyz.smpl_model.faces
144
+
145
+ # Tạo đường dẫn cho file .pt
146
+ pt_path = get_output_path(output_dir, f'{filename}_pred', '.pt')
147
+
148
+ if not os.path.exists(pt_path):
149
+ print(f'Running SMPLify, it may take a few minutes.')
150
+ motion_tensor, opt_dict = j2s.joint2smpl(motions)
151
+
152
+ vertices = rot2xyz(torch.tensor(motion_tensor).clone(), mask=None,
153
+ pose_rep='rot6d', translation=True, glob=True,
154
+ jointstype='vertices',
155
+ vertstrans=True)
156
+ vertices = vertices.detach().cpu()
157
+ torch.save(vertices, pt_path)
158
+ else:
159
+ vertices = torch.load(pt_path)
160
+
161
+ frames = vertices.shape[3]
162
+ print(vertices.shape)
163
+ MINS = torch.min(torch.min(vertices[0], axis=0)[0], axis=1)[0]
164
+ MAXS = torch.max(torch.max(vertices[0], axis=0)[0], axis=1)[0]
165
+
166
+ out_list = []
167
+
168
+ minx = MINS[0] - 0.5
169
+ maxx = MAXS[0] + 0.5
170
+ minz = MINS[2] - 0.5
171
+ maxz = MAXS[2] + 0.5
172
+ polygon = geometry.Polygon([[minx, minz], [minx, maxz], [maxx, maxz], [maxx, minz]])
173
+ polygon_mesh = trimesh.creation.extrude_polygon(polygon, 1e-5)
174
+
175
+ vid = []
176
+ for i in range(frames):
177
+ if i % 10 == 0:
178
+ print(f"Processing frame {i}/{frames}")
179
+
180
+ mesh = Trimesh(vertices=vertices[0, :, :, i].squeeze().tolist(), faces=faces)
181
+
182
+ base_color = (0.11, 0.53, 0.8, 0.5)
183
+ material = pyrender.MetallicRoughnessMaterial(
184
+ metallicFactor=0.7,
185
+ alphaMode='OPAQUE',
186
+ baseColorFactor=base_color
187
+ )
188
+
189
+ mesh = pyrender.Mesh.from_trimesh(mesh, material=material)
190
+
191
+ polygon_mesh.visual.face_colors = [0, 0, 0, 0.21]
192
+ polygon_render = pyrender.Mesh.from_trimesh(polygon_mesh, smooth=False)
193
+
194
+ bg_color = [1, 1, 1, 0.8]
195
+ scene = pyrender.Scene(bg_color=bg_color, ambient_light=(0.4, 0.4, 0.4))
196
+
197
+ sx, sy, tx, ty = [0.75, 0.75, 0, 0.10]
198
+
199
+ camera = pyrender.PerspectiveCamera(yfov=(np.pi / 3.0))
200
+ light = pyrender.DirectionalLight(color=[1,1,1], intensity=300)
201
+
202
+ scene.add(mesh)
203
+
204
+ c = np.pi / 2
205
+ scene.add(polygon_render, pose=np.array([[ 1, 0, 0, 0],
206
+ [ 0, np.cos(c), -np.sin(c), MINS[1].cpu().numpy()],
207
+ [ 0, np.sin(c), np.cos(c), 0],
208
+ [ 0, 0, 0, 1]]))
209
+
210
+ light_pose = np.eye(4)
211
+ light_pose[:3, 3] = [0, -1, 1]
212
+ scene.add(light, pose=light_pose.copy())
213
+
214
+ light_pose[:3, 3] = [0, 1, 1]
215
+ scene.add(light, pose=light_pose.copy())
216
+
217
+ light_pose[:3, 3] = [1, 1, 2]
218
+ scene.add(light, pose=light_pose.copy())
219
+
220
+ c = -np.pi / 6
221
+ scene.add(camera, pose=[[ 1, 0, 0, (minx+maxx).cpu().numpy()/2],
222
+ [ 0, np.cos(c), -np.sin(c), 1.5],
223
+ [ 0, np.sin(c), np.cos(c), max(4, minz.cpu().numpy()+(1.5-MINS[1].cpu().numpy())*2, (maxx-minx).cpu().numpy())],
224
+ [ 0, 0, 0, 1]
225
+ ])
226
+
227
+ r = pyrender.OffscreenRenderer(960, 960)
228
+ color, _ = r.render(scene, flags=RenderFlags.RGBA)
229
+ vid.append(color)
230
+ r.delete()
231
+
232
+ out = np.stack(vid, axis=0)
233
+
234
+ # Tạo đường dẫn cho file GIF và MP4
235
+ gif_path = get_output_path(output_dir, filename, '.gif')
236
+ mp4_path = get_output_path(output_dir, filename, '.mp4')
237
+
238
+ imageio.mimwrite(gif_path, out, duration=50)
239
+ out_video = mp.VideoFileClip(gif_path)
240
+ out_video.write_videofile(mp4_path)
241
+
242
+ print(f"Results saved to: {mp4_path}")
243
+
244
+ del out, vertices
245
+ return mp4_path
246
+
247
+ def predict(clip_text, method='fast', output_dir='output', filename=''):
248
+ """
249
+ Predict motion with custom output settings
250
+
251
+ Args:
252
+ clip_text: Text prompt
253
+ method: 'fast' or 'slow'
254
+ output_dir: Output directory
255
+ filename: Custom filename (if empty, will use hash or timestamp)
256
+ """
257
+ gc.collect()
258
+ print('prompt text instruction: {}'.format(clip_text))
259
+
260
+ # Tạo tên file nếu không được cung cấp
261
+ if not filename.strip():
262
+ if method == 'fast':
263
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
264
+ filename = f"motion_{timestamp}"
265
+ else:
266
+ filename = hashlib.md5(clip_text.encode()).hexdigest()
267
+
268
+ # Xử lý text với CLIP
269
+ if torch.cuda.is_available():
270
+ text = clip.tokenize([clip_text], truncate=True).cuda()
271
+ else:
272
+ text = clip.tokenize([clip_text], truncate=True)
273
+
274
+ feat_clip_text = clip_model.encode_text(text).float()
275
+ index_motion = trans_encoder.sample(feat_clip_text[0:1], False)
276
+ pred_pose = net.forward_decoder(index_motion)
277
+ pred_xyz = recover_from_ric((pred_pose*std+mean).float(), 22)
278
+
279
+ if method == 'fast':
280
+ xyz = pred_xyz.reshape(1, -1, 22, 3)
281
+
282
+ # Tạo đường dẫn cho fast method
283
+ gif_path = get_output_path(output_dir, filename, '.gif')
284
+ mp4_path = get_output_path(output_dir, filename, '.mp4')
285
+
286
+ pose_vis = plot_3d.draw_to_batch(xyz.detach().cpu().numpy(), title_batch=None, outname=[gif_path])
287
+ out_video = mp.VideoFileClip(gif_path)
288
+ out_video.write_videofile(mp4_path)
289
+
290
+ print(f"Fast render results saved to: {mp4_path}")
291
+ return mp4_path
292
+
293
+ elif method == 'slow':
294
+ output_path = render(pred_xyz.detach().cpu().numpy().squeeze(axis=0),
295
+ output_dir=output_dir,
296
+ filename=filename,
297
+ device_id=0)
298
+ return output_path
299
+
300
+ # ---- Gradio Layout -----
301
+ video_out = gr.Video(label="Motion", mirror_webcam=False, interactive=False)
302
+ demo = gr.Blocks()
303
+ demo.encrypt = False
304
+
305
+ with demo:
306
+ gr.Markdown('''
307
+ <div>
308
+ <h1 style='text-align: center'>Generating Human Motion from Textual Descriptions (T2M-GPT)</h1>
309
+ This space uses <a href='https://mael-zys.github.io/T2M-GPT/' target='_blank'><b>T2M-GPT models</b></a> based on Vector Quantised-Variational AutoEncoder (VQ-VAE) and Generative Pre-trained Transformer (GPT) for human motion generation from textural descriptions🤗
310
+ </div>
311
+ ''')
312
+ with gr.Row():
313
+ with gr.Column():
314
+ gr.Markdown('''
315
+ <figure>
316
+ <img src="https://huggingface.co/vumichien/T2M-GPT/resolve/main/demo_slow1.gif" alt="Demo Slow", width="425", height=480/>
317
+ <figcaption> a man starts off in an up right position with botg arms extended out by his sides, he then brings his arms down to his body and claps his hands together. after this he wals down amd the the left where he proceeds to sit on a seat
318
+ </figcaption>
319
+ </figure>
320
+ ''')
321
+ with gr.Column():
322
+ gr.Markdown('''
323
+ <figure>
324
+ <img src="https://huggingface.co/vumichien/T2M-GPT/resolve/main/demo_slow2.gif" alt="Demo Slow 2", width="425", height=480/>
325
+ <figcaption> a person puts their hands together, leans forwards slightly then swings the arms from right to left
326
+ </figcaption>
327
+ </figure>
328
+ ''')
329
+ with gr.Column():
330
+ gr.Markdown('''
331
+ <figure>
332
+ <img src="https://huggingface.co/vumichien/T2M-GPT/resolve/main/demo_slow3.gif" alt="Demo Slow 3", width="425", height=480/>
333
+ <figcaption> a man is practicing the waltz with a partner
334
+ </figcaption>
335
+ </figure>
336
+ ''')
337
+ with gr.Row():
338
+ with gr.Column():
339
+ gr.Markdown('''
340
+ ### Generate human motion by **T2M-GPT**
341
+ ##### Step 1. Give prompt text describing human motion
342
+ ##### Step 2. Choose method to render output (Fast: Sketch skeleton; Slow: SMPL mesh)
343
+ ##### Step 3. Specify output directory and filename (optional)
344
+ ##### Step 4. Generate output and enjoy
345
+ ''')
346
+ with gr.Column():
347
+ with gr.Row():
348
+ text_prompt = gr.Textbox(label="Text prompt", lines=1, interactive=True)
349
+ method = gr.Dropdown(["slow", "fast"], label="Method", value="slow")
350
+ with gr.Row():
351
+ output_dir = gr.Textbox(label="Output Directory", value="output", interactive=True)
352
+ filename = gr.Textbox(label="Filename (without extension)", placeholder="Leave empty for auto-generated name", interactive=True)
353
+ with gr.Row():
354
+ generate_btn = gr.Button("Generate")
355
+ generate_btn.click(predict, [text_prompt, method, output_dir, filename], [video_out], api_name="generate")
356
+ with gr.Row():
357
+ video_out.render()
358
+ with gr.Row():
359
+ gr.Markdown('''
360
+ ### You can test by following examples:
361
+ ''')
362
+ examples = gr.Examples(
363
+ examples=[
364
+ ["a person jogs in place, slowly at first, then increases speed. they then back up and squat down.", "slow", "output", "jogging_motion"],
365
+ ["a man steps forward and does a handstand", "slow", "output", "handstand_motion"],
366
+ ["a man rises from the ground, walks in a circle and sits back down on the ground", "slow", "output", "circle_walk"],
367
+ ["a man starts off in an up right position with botg arms extended out by his sides, he then brings his arms down to his body and claps his hands together. after this he wals down amd the the left where he proceeds to sit on a seat", "slow", "output", "clap_and_sit"],
368
+ ["a person puts their hands together, leans forwards slightly then swings the arms from right to left","slow", "output", "swing_arms"],
369
+ ["a man is practicing the waltz with a partner","slow", "output", "waltz_dance"],
370
+ ],
371
+ label="Examples",
372
+ inputs=[text_prompt, method, output_dir, filename],
373
+ outputs=[video_out],
374
+ fn=predict,
375
+ cache_examples=True,
376
+ )
377
+
378
+
379
+ demo.launch(debug=True, server_name="0.0.0.0", server_port=8000, inbrowser=True, share=True)
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/.gitattributes ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tflite filter=lfs diff=lfs merge=lfs -text
29
+ *.tgz filter=lfs diff=lfs merge=lfs -text
30
+ *.wasm filter=lfs diff=lfs merge=lfs -text
31
+ *.xz filter=lfs diff=lfs merge=lfs -text
32
+ *.zip filter=lfs diff=lfs merge=lfs -text
33
+ *.zst filter=lfs diff=lfs merge=lfs -text
34
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/README.md ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Generate Human Motion
3
+ emoji: 🏃
4
+ colorFrom: green
5
+ colorTo: yellow
6
+ sdk: gradio
7
+ sdk_version: 4.36.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: apache-2.0
11
+ tags:
12
+ - making-demos
13
+ ---
14
+
15
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualization/plot_3d_global.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import matplotlib.pyplot as plt
3
+ import numpy as np
4
+ import io
5
+ import matplotlib
6
+ from mpl_toolkits.mplot3d.art3d import Poly3DCollection
7
+ import mpl_toolkits.mplot3d.axes3d as p3
8
+ from textwrap import wrap
9
+ import imageio
10
+
11
+ def plot_3d_motion(args, figsize=(10, 10), fps=120, radius=4):
12
+ matplotlib.use('Agg')
13
+
14
+
15
+ joints, out_name, title = args
16
+
17
+ data = joints.copy().reshape(len(joints), -1, 3)
18
+
19
+ nb_joints = joints.shape[1]
20
+ smpl_kinetic_chain = [[0, 11, 12, 13, 14, 15], [0, 16, 17, 18, 19, 20], [0, 1, 2, 3, 4], [3, 5, 6, 7], [3, 8, 9, 10]] if nb_joints == 21 else [[0, 2, 5, 8, 11], [0, 1, 4, 7, 10], [0, 3, 6, 9, 12, 15], [9, 14, 17, 19, 21], [9, 13, 16, 18, 20]]
21
+ limits = 1000 if nb_joints == 21 else 2
22
+ MINS = data.min(axis=0).min(axis=0)
23
+ MAXS = data.max(axis=0).max(axis=0)
24
+ colors = ['red', 'blue', 'black', 'red', 'blue',
25
+ 'darkblue', 'darkblue', 'darkblue', 'darkblue', 'darkblue',
26
+ 'darkred', 'darkred', 'darkred', 'darkred', 'darkred']
27
+ frame_number = data.shape[0]
28
+ # print(data.shape)
29
+
30
+ height_offset = MINS[1]
31
+ data[:, :, 1] -= height_offset
32
+ trajec = data[:, 0, [0, 2]]
33
+
34
+ data[..., 0] -= data[:, 0:1, 0]
35
+ data[..., 2] -= data[:, 0:1, 2]
36
+
37
+ def update(index):
38
+
39
+ def init():
40
+ ax.set_xlim(-limits, limits)
41
+ ax.set_ylim(-limits, limits)
42
+ ax.set_zlim(0, limits)
43
+ ax.grid(b=False)
44
+ def plot_xzPlane(minx, maxx, miny, minz, maxz):
45
+ ## Plot a plane XZ
46
+ verts = [
47
+ [minx, miny, minz],
48
+ [minx, miny, maxz],
49
+ [maxx, miny, maxz],
50
+ [maxx, miny, minz]
51
+ ]
52
+ xz_plane = Poly3DCollection([verts])
53
+ xz_plane.set_facecolor((0.5, 0.5, 0.5, 0.5))
54
+ ax.add_collection3d(xz_plane)
55
+ fig = plt.figure(figsize=(480/96., 320/96.), dpi=96) if nb_joints == 21 else plt.figure(figsize=(10, 10), dpi=96)
56
+ if title is not None :
57
+ wraped_title = '\n'.join(wrap(title, 40))
58
+ fig.suptitle(wraped_title, fontsize=16)
59
+ ax = p3.Axes3D(fig)
60
+
61
+ init()
62
+
63
+ ax.lines = []
64
+ ax.collections = []
65
+ ax.view_init(elev=110, azim=-90)
66
+ ax.dist = 7.5
67
+ # ax =
68
+ plot_xzPlane(MINS[0] - trajec[index, 0], MAXS[0] - trajec[index, 0], 0, MINS[2] - trajec[index, 1],
69
+ MAXS[2] - trajec[index, 1])
70
+ # ax.scatter(data[index, :22, 0], data[index, :22, 1], data[index, :22, 2], color='black', s=3)
71
+
72
+ if index > 1:
73
+ ax.plot3D(trajec[:index, 0] - trajec[index, 0], np.zeros_like(trajec[:index, 0]),
74
+ trajec[:index, 1] - trajec[index, 1], linewidth=1.0,
75
+ color='blue')
76
+ # ax = plot_xzPlane(ax, MINS[0], MAXS[0], 0, MINS[2], MAXS[2])
77
+
78
+ for i, (chain, color) in enumerate(zip(smpl_kinetic_chain, colors)):
79
+ # print(color)
80
+ if i < 5:
81
+ linewidth = 4.0
82
+ else:
83
+ linewidth = 2.0
84
+ ax.plot3D(data[index, chain, 0], data[index, chain, 1], data[index, chain, 2], linewidth=linewidth,
85
+ color=color)
86
+ # print(trajec[:index, 0].shape)
87
+
88
+ plt.axis('off')
89
+ ax.set_xticklabels([])
90
+ ax.set_yticklabels([])
91
+ ax.set_zticklabels([])
92
+
93
+ if out_name is not None :
94
+ plt.savefig(out_name, dpi=96)
95
+ plt.close()
96
+
97
+ else :
98
+ io_buf = io.BytesIO()
99
+ fig.savefig(io_buf, format='raw', dpi=96)
100
+ io_buf.seek(0)
101
+ # print(fig.bbox.bounds)
102
+ arr = np.reshape(np.frombuffer(io_buf.getvalue(), dtype=np.uint8),
103
+ newshape=(int(fig.bbox.bounds[3]), int(fig.bbox.bounds[2]), -1))
104
+ io_buf.close()
105
+ plt.close()
106
+ return arr
107
+
108
+ out = []
109
+ for i in range(frame_number) :
110
+ out.append(update(i))
111
+ out = np.stack(out, axis=0)
112
+ return torch.from_numpy(out)
113
+
114
+
115
+ def draw_to_batch(smpl_joints_batch, title_batch=None, outname=None) :
116
+
117
+ batch_size = len(smpl_joints_batch)
118
+ out = []
119
+ for i in range(batch_size) :
120
+ out.append(plot_3d_motion([smpl_joints_batch[i], None, title_batch[i] if title_batch is not None else None]))
121
+ if outname is not None:
122
+ imageio.mimsave(outname[i], np.array(out[-1]), fps=20)
123
+ out = torch.stack(out, axis=0)
124
+ return out
125
+
126
+
127
+
128
+
129
+
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/joints2smpl/src/config.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ # Map joints Name to SMPL joints idx
4
+ JOINT_MAP = {
5
+ 'MidHip': 0,
6
+ 'LHip': 1, 'LKnee': 4, 'LAnkle': 7, 'LFoot': 10,
7
+ 'RHip': 2, 'RKnee': 5, 'RAnkle': 8, 'RFoot': 11,
8
+ 'LShoulder': 16, 'LElbow': 18, 'LWrist': 20, 'LHand': 22,
9
+ 'RShoulder': 17, 'RElbow': 19, 'RWrist': 21, 'RHand': 23,
10
+ 'spine1': 3, 'spine2': 6, 'spine3': 9, 'Neck': 12, 'Head': 15,
11
+ 'LCollar':13, 'Rcollar' :14,
12
+ 'Nose':24, 'REye':26, 'LEye':26, 'REar':27, 'LEar':28,
13
+ 'LHeel': 31, 'RHeel': 34,
14
+ 'OP RShoulder': 17, 'OP LShoulder': 16,
15
+ 'OP RHip': 2, 'OP LHip': 1,
16
+ 'OP Neck': 12,
17
+ }
18
+
19
+ full_smpl_idx = range(24)
20
+ key_smpl_idx = [0, 1, 4, 7, 2, 5, 8, 17, 19, 21, 16, 18, 20]
21
+
22
+
23
+ AMASS_JOINT_MAP = {
24
+ 'MidHip': 0,
25
+ 'LHip': 1, 'LKnee': 4, 'LAnkle': 7, 'LFoot': 10,
26
+ 'RHip': 2, 'RKnee': 5, 'RAnkle': 8, 'RFoot': 11,
27
+ 'LShoulder': 16, 'LElbow': 18, 'LWrist': 20,
28
+ 'RShoulder': 17, 'RElbow': 19, 'RWrist': 21,
29
+ 'spine1': 3, 'spine2': 6, 'spine3': 9, 'Neck': 12, 'Head': 15,
30
+ 'LCollar':13, 'Rcollar' :14,
31
+ }
32
+ amass_idx = range(22)
33
+ amass_smpl_idx = range(22)
34
+
35
+
36
+ SMPL_MODEL_DIR = "./body_models/"
37
+ GMM_MODEL_DIR = "./visualize/joints2smpl/smpl_models/"
38
+ SMPL_MEAN_FILE = "./visualize/joints2smpl/smpl_models/neutral_smpl_mean_params.h5"
39
+ # for collsion
40
+ Part_Seg_DIR = "./visualize/joints2smpl/smpl_models/smplx_parts_segm.pkl"
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/joints2smpl/src/customloss.py ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn.functional as F
3
+ from visualize.joints2smpl.src import config
4
+
5
+ # Guassian
6
+ def gmof(x, sigma):
7
+ """
8
+ Geman-McClure error function
9
+ """
10
+ x_squared = x ** 2
11
+ sigma_squared = sigma ** 2
12
+ return (sigma_squared * x_squared) / (sigma_squared + x_squared)
13
+
14
+ # angle prior
15
+ def angle_prior(pose):
16
+ """
17
+ Angle prior that penalizes unnatural bending of the knees and elbows
18
+ """
19
+ # We subtract 3 because pose does not include the global rotation of the model
20
+ return torch.exp(
21
+ pose[:, [55 - 3, 58 - 3, 12 - 3, 15 - 3]] * torch.tensor([1., -1., -1, -1.], device=pose.device)) ** 2
22
+
23
+
24
+ def perspective_projection(points, rotation, translation,
25
+ focal_length, camera_center):
26
+ """
27
+ This function computes the perspective projection of a set of points.
28
+ Input:
29
+ points (bs, N, 3): 3D points
30
+ rotation (bs, 3, 3): Camera rotation
31
+ translation (bs, 3): Camera translation
32
+ focal_length (bs,) or scalar: Focal length
33
+ camera_center (bs, 2): Camera center
34
+ """
35
+ batch_size = points.shape[0]
36
+ K = torch.zeros([batch_size, 3, 3], device=points.device)
37
+ K[:, 0, 0] = focal_length
38
+ K[:, 1, 1] = focal_length
39
+ K[:, 2, 2] = 1.
40
+ K[:, :-1, -1] = camera_center
41
+
42
+ # Transform points
43
+ points = torch.einsum('bij,bkj->bki', rotation, points)
44
+ points = points + translation.unsqueeze(1)
45
+
46
+ # Apply perspective distortion
47
+ projected_points = points / points[:, :, -1].unsqueeze(-1)
48
+
49
+ # Apply camera intrinsics
50
+ projected_points = torch.einsum('bij,bkj->bki', K, projected_points)
51
+
52
+ return projected_points[:, :, :-1]
53
+
54
+
55
+ def body_fitting_loss(body_pose, betas, model_joints, camera_t, camera_center,
56
+ joints_2d, joints_conf, pose_prior,
57
+ focal_length=5000, sigma=100, pose_prior_weight=4.78,
58
+ shape_prior_weight=5, angle_prior_weight=15.2,
59
+ output='sum'):
60
+ """
61
+ Loss function for body fitting
62
+ """
63
+ batch_size = body_pose.shape[0]
64
+ rotation = torch.eye(3, device=body_pose.device).unsqueeze(0).expand(batch_size, -1, -1)
65
+
66
+ projected_joints = perspective_projection(model_joints, rotation, camera_t,
67
+ focal_length, camera_center)
68
+
69
+ # Weighted robust reprojection error
70
+ reprojection_error = gmof(projected_joints - joints_2d, sigma)
71
+ reprojection_loss = (joints_conf ** 2) * reprojection_error.sum(dim=-1)
72
+
73
+ # Pose prior loss
74
+ pose_prior_loss = (pose_prior_weight ** 2) * pose_prior(body_pose, betas)
75
+
76
+ # Angle prior for knees and elbows
77
+ angle_prior_loss = (angle_prior_weight ** 2) * angle_prior(body_pose).sum(dim=-1)
78
+
79
+ # Regularizer to prevent betas from taking large values
80
+ shape_prior_loss = (shape_prior_weight ** 2) * (betas ** 2).sum(dim=-1)
81
+
82
+ total_loss = reprojection_loss.sum(dim=-1) + pose_prior_loss + angle_prior_loss + shape_prior_loss
83
+
84
+ if output == 'sum':
85
+ return total_loss.sum()
86
+ elif output == 'reprojection':
87
+ return reprojection_loss
88
+
89
+
90
+ # --- get camera fitting loss -----
91
+ def camera_fitting_loss(model_joints, camera_t, camera_t_est, camera_center,
92
+ joints_2d, joints_conf,
93
+ focal_length=5000, depth_loss_weight=100):
94
+ """
95
+ Loss function for camera optimization.
96
+ """
97
+ # Project model joints
98
+ batch_size = model_joints.shape[0]
99
+ rotation = torch.eye(3, device=model_joints.device).unsqueeze(0).expand(batch_size, -1, -1)
100
+ projected_joints = perspective_projection(model_joints, rotation, camera_t,
101
+ focal_length, camera_center)
102
+
103
+ # get the indexed four
104
+ op_joints = ['OP RHip', 'OP LHip', 'OP RShoulder', 'OP LShoulder']
105
+ op_joints_ind = [config.JOINT_MAP[joint] for joint in op_joints]
106
+ gt_joints = ['RHip', 'LHip', 'RShoulder', 'LShoulder']
107
+ gt_joints_ind = [config.JOINT_MAP[joint] for joint in gt_joints]
108
+
109
+ reprojection_error_op = (joints_2d[:, op_joints_ind] -
110
+ projected_joints[:, op_joints_ind]) ** 2
111
+ reprojection_error_gt = (joints_2d[:, gt_joints_ind] -
112
+ projected_joints[:, gt_joints_ind]) ** 2
113
+
114
+ # Check if for each example in the batch all 4 OpenPose detections are valid, otherwise use the GT detections
115
+ # OpenPose joints are more reliable for this task, so we prefer to use them if possible
116
+ is_valid = (joints_conf[:, op_joints_ind].min(dim=-1)[0][:, None, None] > 0).float()
117
+ reprojection_loss = (is_valid * reprojection_error_op + (1 - is_valid) * reprojection_error_gt).sum(dim=(1, 2))
118
+
119
+ # Loss that penalizes deviation from depth estimate
120
+ depth_loss = (depth_loss_weight ** 2) * (camera_t[:, 2] - camera_t_est[:, 2]) ** 2
121
+
122
+ total_loss = reprojection_loss + depth_loss
123
+ return total_loss.sum()
124
+
125
+
126
+
127
+ # #####--- body fitiing loss -----
128
+ def body_fitting_loss_3d(body_pose, preserve_pose,
129
+ betas, model_joints, camera_translation,
130
+ j3d, pose_prior,
131
+ joints3d_conf,
132
+ sigma=100, pose_prior_weight=4.78*1.5,
133
+ shape_prior_weight=5.0, angle_prior_weight=15.2,
134
+ joint_loss_weight=500.0,
135
+ pose_preserve_weight=0.0,
136
+ use_collision=False,
137
+ model_vertices=None, model_faces=None,
138
+ search_tree=None, pen_distance=None, filter_faces=None,
139
+ collision_loss_weight=1000
140
+ ):
141
+ """
142
+ Loss function for body fitting
143
+ """
144
+ batch_size = body_pose.shape[0]
145
+
146
+ #joint3d_loss = (joint_loss_weight ** 2) * gmof((model_joints + camera_translation) - j3d, sigma).sum(dim=-1)
147
+
148
+ joint3d_error = gmof((model_joints + camera_translation) - j3d, sigma)
149
+
150
+ joint3d_loss_part = (joints3d_conf ** 2) * joint3d_error.sum(dim=-1)
151
+ joint3d_loss = ((joint_loss_weight ** 2) * joint3d_loss_part).sum(dim=-1)
152
+
153
+ # Pose prior loss
154
+ pose_prior_loss = (pose_prior_weight ** 2) * pose_prior(body_pose, betas)
155
+ # Angle prior for knees and elbows
156
+ angle_prior_loss = (angle_prior_weight ** 2) * angle_prior(body_pose).sum(dim=-1)
157
+ # Regularizer to prevent betas from taking large values
158
+ shape_prior_loss = (shape_prior_weight ** 2) * (betas ** 2).sum(dim=-1)
159
+
160
+ collision_loss = 0.0
161
+ # Calculate the loss due to interpenetration
162
+ if use_collision:
163
+ triangles = torch.index_select(
164
+ model_vertices, 1,
165
+ model_faces).view(batch_size, -1, 3, 3)
166
+
167
+ with torch.no_grad():
168
+ collision_idxs = search_tree(triangles)
169
+
170
+ # Remove unwanted collisions
171
+ if filter_faces is not None:
172
+ collision_idxs = filter_faces(collision_idxs)
173
+
174
+ if collision_idxs.ge(0).sum().item() > 0:
175
+ collision_loss = torch.sum(collision_loss_weight * pen_distance(triangles, collision_idxs))
176
+
177
+ pose_preserve_loss = (pose_preserve_weight ** 2) * ((body_pose - preserve_pose) ** 2).sum(dim=-1)
178
+
179
+ # print('joint3d_loss', joint3d_loss.shape)
180
+ # print('pose_prior_loss', pose_prior_loss.shape)
181
+ # print('angle_prior_loss', angle_prior_loss.shape)
182
+ # print('shape_prior_loss', shape_prior_loss.shape)
183
+ # print('collision_loss', collision_loss)
184
+ # print('pose_preserve_loss', pose_preserve_loss.shape)
185
+
186
+ total_loss = joint3d_loss + pose_prior_loss + angle_prior_loss + shape_prior_loss + collision_loss + pose_preserve_loss
187
+
188
+ return total_loss.sum()
189
+
190
+
191
+ # #####--- get camera fitting loss -----
192
+ def camera_fitting_loss_3d(model_joints, camera_t, camera_t_est,
193
+ j3d, joints_category="orig", depth_loss_weight=100.0):
194
+ """
195
+ Loss function for camera optimization.
196
+ """
197
+ model_joints = model_joints + camera_t
198
+ # # get the indexed four
199
+ # op_joints = ['OP RHip', 'OP LHip', 'OP RShoulder', 'OP LShoulder']
200
+ # op_joints_ind = [config.JOINT_MAP[joint] for joint in op_joints]
201
+ #
202
+ # j3d_error_loss = (j3d[:, op_joints_ind] -
203
+ # model_joints[:, op_joints_ind]) ** 2
204
+
205
+ gt_joints = ['RHip', 'LHip', 'RShoulder', 'LShoulder']
206
+ gt_joints_ind = [config.JOINT_MAP[joint] for joint in gt_joints]
207
+
208
+ if joints_category=="orig":
209
+ select_joints_ind = [config.JOINT_MAP[joint] for joint in gt_joints]
210
+ elif joints_category=="AMASS":
211
+ select_joints_ind = [config.AMASS_JOINT_MAP[joint] for joint in gt_joints]
212
+ else:
213
+ print("NO SUCH JOINTS CATEGORY!")
214
+
215
+ j3d_error_loss = (j3d[:, select_joints_ind] -
216
+ model_joints[:, gt_joints_ind]) ** 2
217
+
218
+ # Loss that penalizes deviation from depth estimate
219
+ depth_loss = (depth_loss_weight**2) * (camera_t - camera_t_est)**2
220
+
221
+ total_loss = j3d_error_loss + depth_loss
222
+ return total_loss.sum()
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/joints2smpl/src/prior.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. (MPG) is
4
+ # holder of all proprietary rights on this computer program.
5
+ # You can only use this computer program if you have closed
6
+ # a license agreement with MPG or you get the right to use the computer
7
+ # program from someone who is authorized to grant you that right.
8
+ # Any use of the computer program without a valid license is prohibited and
9
+ # liable to prosecution.
10
+ #
11
+ # Copyright©2019 Max-Planck-Gesellschaft zur Förderung
12
+ # der Wissenschaften e.V. (MPG). acting on behalf of its Max Planck Institute
13
+ # for Intelligent Systems. All rights reserved.
14
+ #
15
+ # Contact: ps-license@tuebingen.mpg.de
16
+
17
+ from __future__ import absolute_import
18
+ from __future__ import print_function
19
+ from __future__ import division
20
+
21
+ import sys
22
+ import os
23
+
24
+ import time
25
+ import pickle
26
+
27
+ import numpy as np
28
+
29
+ import torch
30
+ import torch.nn as nn
31
+
32
+ DEFAULT_DTYPE = torch.float32
33
+
34
+
35
+ def create_prior(prior_type, **kwargs):
36
+ if prior_type == 'gmm':
37
+ prior = MaxMixturePrior(**kwargs)
38
+ elif prior_type == 'l2':
39
+ return L2Prior(**kwargs)
40
+ elif prior_type == 'angle':
41
+ return SMPLifyAnglePrior(**kwargs)
42
+ elif prior_type == 'none' or prior_type is None:
43
+ # Don't use any pose prior
44
+ def no_prior(*args, **kwargs):
45
+ return 0.0
46
+ prior = no_prior
47
+ else:
48
+ raise ValueError('Prior {}'.format(prior_type) + ' is not implemented')
49
+ return prior
50
+
51
+
52
+ class SMPLifyAnglePrior(nn.Module):
53
+ def __init__(self, dtype=torch.float32, **kwargs):
54
+ super(SMPLifyAnglePrior, self).__init__()
55
+
56
+ # Indices for the roration angle of
57
+ # 55: left elbow, 90deg bend at -np.pi/2
58
+ # 58: right elbow, 90deg bend at np.pi/2
59
+ # 12: left knee, 90deg bend at np.pi/2
60
+ # 15: right knee, 90deg bend at np.pi/2
61
+ angle_prior_idxs = np.array([55, 58, 12, 15], dtype=np.int64)
62
+ angle_prior_idxs = torch.tensor(angle_prior_idxs, dtype=torch.long)
63
+ self.register_buffer('angle_prior_idxs', angle_prior_idxs)
64
+
65
+ angle_prior_signs = np.array([1, -1, -1, -1],
66
+ dtype=np.float32 if dtype == torch.float32
67
+ else np.float64)
68
+ angle_prior_signs = torch.tensor(angle_prior_signs,
69
+ dtype=dtype)
70
+ self.register_buffer('angle_prior_signs', angle_prior_signs)
71
+
72
+ def forward(self, pose, with_global_pose=False):
73
+ ''' Returns the angle prior loss for the given pose
74
+
75
+ Args:
76
+ pose: (Bx[23 + 1] * 3) torch tensor with the axis-angle
77
+ representation of the rotations of the joints of the SMPL model.
78
+ Kwargs:
79
+ with_global_pose: Whether the pose vector also contains the global
80
+ orientation of the SMPL model. If not then the indices must be
81
+ corrected.
82
+ Returns:
83
+ A sze (B) tensor containing the angle prior loss for each element
84
+ in the batch.
85
+ '''
86
+ angle_prior_idxs = self.angle_prior_idxs - (not with_global_pose) * 3
87
+ return torch.exp(pose[:, angle_prior_idxs] *
88
+ self.angle_prior_signs).pow(2)
89
+
90
+
91
+ class L2Prior(nn.Module):
92
+ def __init__(self, dtype=DEFAULT_DTYPE, reduction='sum', **kwargs):
93
+ super(L2Prior, self).__init__()
94
+
95
+ def forward(self, module_input, *args):
96
+ return torch.sum(module_input.pow(2))
97
+
98
+
99
+ class MaxMixturePrior(nn.Module):
100
+
101
+ def __init__(self, prior_folder='prior',
102
+ num_gaussians=6, dtype=DEFAULT_DTYPE, epsilon=1e-16,
103
+ use_merged=True,
104
+ **kwargs):
105
+ super(MaxMixturePrior, self).__init__()
106
+
107
+ if dtype == DEFAULT_DTYPE:
108
+ np_dtype = np.float32
109
+ elif dtype == torch.float64:
110
+ np_dtype = np.float64
111
+ else:
112
+ print('Unknown float type {}, exiting!'.format(dtype))
113
+ sys.exit(-1)
114
+
115
+ self.num_gaussians = num_gaussians
116
+ self.epsilon = epsilon
117
+ self.use_merged = use_merged
118
+ gmm_fn = 'gmm_{:02d}.pkl'.format(num_gaussians)
119
+
120
+ full_gmm_fn = os.path.join(prior_folder, gmm_fn)
121
+ if not os.path.exists(full_gmm_fn):
122
+ print('The path to the mixture prior "{}"'.format(full_gmm_fn) +
123
+ ' does not exist, exiting!')
124
+ sys.exit(-1)
125
+
126
+ with open(full_gmm_fn, 'rb') as f:
127
+ gmm = pickle.load(f, encoding='latin1')
128
+
129
+ if type(gmm) == dict:
130
+ means = gmm['means'].astype(np_dtype)
131
+ covs = gmm['covars'].astype(np_dtype)
132
+ weights = gmm['weights'].astype(np_dtype)
133
+ elif 'sklearn.mixture.gmm.GMM' in str(type(gmm)):
134
+ means = gmm.means_.astype(np_dtype)
135
+ covs = gmm.covars_.astype(np_dtype)
136
+ weights = gmm.weights_.astype(np_dtype)
137
+ else:
138
+ print('Unknown type for the prior: {}, exiting!'.format(type(gmm)))
139
+ sys.exit(-1)
140
+
141
+ self.register_buffer('means', torch.tensor(means, dtype=dtype))
142
+
143
+ self.register_buffer('covs', torch.tensor(covs, dtype=dtype))
144
+
145
+ precisions = [np.linalg.inv(cov) for cov in covs]
146
+ precisions = np.stack(precisions).astype(np_dtype)
147
+
148
+ self.register_buffer('precisions',
149
+ torch.tensor(precisions, dtype=dtype))
150
+
151
+ # The constant term:
152
+ sqrdets = np.array([(np.sqrt(np.linalg.det(c)))
153
+ for c in gmm['covars']])
154
+ const = (2 * np.pi)**(69 / 2.)
155
+
156
+ nll_weights = np.asarray(gmm['weights'] / (const *
157
+ (sqrdets / sqrdets.min())))
158
+ nll_weights = torch.tensor(nll_weights, dtype=dtype).unsqueeze(dim=0)
159
+ self.register_buffer('nll_weights', nll_weights)
160
+
161
+ weights = torch.tensor(gmm['weights'], dtype=dtype).unsqueeze(dim=0)
162
+ self.register_buffer('weights', weights)
163
+
164
+ self.register_buffer('pi_term',
165
+ torch.log(torch.tensor(2 * np.pi, dtype=dtype)))
166
+
167
+ cov_dets = [np.log(np.linalg.det(cov.astype(np_dtype)) + epsilon)
168
+ for cov in covs]
169
+ self.register_buffer('cov_dets',
170
+ torch.tensor(cov_dets, dtype=dtype))
171
+
172
+ # The dimensionality of the random variable
173
+ self.random_var_dim = self.means.shape[1]
174
+
175
+ def get_mean(self):
176
+ ''' Returns the mean of the mixture '''
177
+ mean_pose = torch.matmul(self.weights, self.means)
178
+ return mean_pose
179
+
180
+ def merged_log_likelihood(self, pose, betas):
181
+ diff_from_mean = pose.unsqueeze(dim=1) - self.means
182
+
183
+ prec_diff_prod = torch.einsum('mij,bmj->bmi',
184
+ [self.precisions, diff_from_mean])
185
+ diff_prec_quadratic = (prec_diff_prod * diff_from_mean).sum(dim=-1)
186
+
187
+ curr_loglikelihood = 0.5 * diff_prec_quadratic - \
188
+ torch.log(self.nll_weights)
189
+ # curr_loglikelihood = 0.5 * (self.cov_dets.unsqueeze(dim=0) +
190
+ # self.random_var_dim * self.pi_term +
191
+ # diff_prec_quadratic
192
+ # ) - torch.log(self.weights)
193
+
194
+ min_likelihood, _ = torch.min(curr_loglikelihood, dim=1)
195
+ return min_likelihood
196
+
197
+ def log_likelihood(self, pose, betas, *args, **kwargs):
198
+ ''' Create graph operation for negative log-likelihood calculation
199
+ '''
200
+ likelihoods = []
201
+
202
+ for idx in range(self.num_gaussians):
203
+ mean = self.means[idx]
204
+ prec = self.precisions[idx]
205
+ cov = self.covs[idx]
206
+ diff_from_mean = pose - mean
207
+
208
+ curr_loglikelihood = torch.einsum('bj,ji->bi',
209
+ [diff_from_mean, prec])
210
+ curr_loglikelihood = torch.einsum('bi,bi->b',
211
+ [curr_loglikelihood,
212
+ diff_from_mean])
213
+ cov_term = torch.log(torch.det(cov) + self.epsilon)
214
+ curr_loglikelihood += 0.5 * (cov_term +
215
+ self.random_var_dim *
216
+ self.pi_term)
217
+ likelihoods.append(curr_loglikelihood)
218
+
219
+ log_likelihoods = torch.stack(likelihoods, dim=1)
220
+ min_idx = torch.argmin(log_likelihoods, dim=1)
221
+ weight_component = self.nll_weights[:, min_idx]
222
+ weight_component = -torch.log(weight_component)
223
+
224
+ return weight_component + log_likelihoods[:, min_idx]
225
+
226
+ def forward(self, pose, betas):
227
+ if self.use_merged:
228
+ return self.merged_log_likelihood(pose, betas)
229
+ else:
230
+ return self.log_likelihood(pose, betas)
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/joints2smpl/src/smplify.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import os, sys
3
+ import pickle
4
+ import smplx
5
+ import numpy as np
6
+
7
+ sys.path.append(os.path.dirname(__file__))
8
+ from customloss import (camera_fitting_loss,
9
+ body_fitting_loss,
10
+ camera_fitting_loss_3d,
11
+ body_fitting_loss_3d,
12
+ )
13
+ from prior import MaxMixturePrior
14
+ from visualize.joints2smpl.src import config
15
+
16
+
17
+
18
+ @torch.no_grad()
19
+ def guess_init_3d(model_joints,
20
+ j3d,
21
+ joints_category="orig"):
22
+ """Initialize the camera translation via triangle similarity, by using the torso joints .
23
+ :param model_joints: SMPL model with pre joints
24
+ :param j3d: 25x3 array of Kinect Joints
25
+ :returns: 3D vector corresponding to the estimated camera translation
26
+ """
27
+ # get the indexed four
28
+ gt_joints = ['RHip', 'LHip', 'RShoulder', 'LShoulder']
29
+ gt_joints_ind = [config.JOINT_MAP[joint] for joint in gt_joints]
30
+
31
+ if joints_category=="orig":
32
+ joints_ind_category = [config.JOINT_MAP[joint] for joint in gt_joints]
33
+ elif joints_category=="AMASS":
34
+ joints_ind_category = [config.AMASS_JOINT_MAP[joint] for joint in gt_joints]
35
+ else:
36
+ print("NO SUCH JOINTS CATEGORY!")
37
+
38
+ sum_init_t = (j3d[:, joints_ind_category] - model_joints[:, gt_joints_ind]).sum(dim=1)
39
+ init_t = sum_init_t / 4.0
40
+ return init_t
41
+
42
+
43
+ # SMPLIfy 3D
44
+ class SMPLify3D():
45
+ """Implementation of SMPLify, use 3D joints."""
46
+
47
+ def __init__(self,
48
+ smplxmodel,
49
+ step_size=1e-2,
50
+ batch_size=1,
51
+ num_iters=100,
52
+ use_collision=False,
53
+ use_lbfgs=True,
54
+ joints_category="orig",
55
+ device=torch.device('cuda:0'),
56
+ ):
57
+
58
+ # Store options
59
+ self.batch_size = batch_size
60
+ self.device = device
61
+ self.step_size = step_size
62
+
63
+ self.num_iters = num_iters
64
+ # --- choose optimizer
65
+ self.use_lbfgs = use_lbfgs
66
+ # GMM pose prior
67
+ self.pose_prior = MaxMixturePrior(prior_folder=config.GMM_MODEL_DIR,
68
+ num_gaussians=8,
69
+ dtype=torch.float32).to(device)
70
+ # collision part
71
+ self.use_collision = use_collision
72
+ if self.use_collision:
73
+ self.part_segm_fn = config.Part_Seg_DIR
74
+
75
+ # reLoad SMPL-X model
76
+ self.smpl = smplxmodel
77
+
78
+ self.model_faces = smplxmodel.faces_tensor.view(-1)
79
+
80
+ # select joint joint_category
81
+ self.joints_category = joints_category
82
+
83
+ if joints_category=="orig":
84
+ self.smpl_index = config.full_smpl_idx
85
+ self.corr_index = config.full_smpl_idx
86
+ elif joints_category=="AMASS":
87
+ self.smpl_index = config.amass_smpl_idx
88
+ self.corr_index = config.amass_idx
89
+ else:
90
+ self.smpl_index = None
91
+ self.corr_index = None
92
+ print("NO SUCH JOINTS CATEGORY!")
93
+
94
+ # ---- get the man function here ------
95
+ def __call__(self, init_pose, init_betas, init_cam_t, j3d, conf_3d=1.0, seq_ind=0):
96
+ """Perform body fitting.
97
+ Input:
98
+ init_pose: SMPL pose estimate
99
+ init_betas: SMPL betas estimate
100
+ init_cam_t: Camera translation estimate
101
+ j3d: joints 3d aka keypoints
102
+ conf_3d: confidence for 3d joints
103
+ seq_ind: index of the sequence
104
+ Returns:
105
+ vertices: Vertices of optimized shape
106
+ joints: 3D joints of optimized shape
107
+ pose: SMPL pose parameters of optimized shape
108
+ betas: SMPL beta parameters of optimized shape
109
+ camera_translation: Camera translation
110
+ """
111
+
112
+ # # # add the mesh inter-section to avoid
113
+ search_tree = None
114
+ pen_distance = None
115
+ filter_faces = None
116
+
117
+ if self.use_collision:
118
+ from mesh_intersection.bvh_search_tree import BVH
119
+ import mesh_intersection.loss as collisions_loss
120
+ from mesh_intersection.filter_faces import FilterFaces
121
+
122
+ search_tree = BVH(max_collisions=8)
123
+
124
+ pen_distance = collisions_loss.DistanceFieldPenetrationLoss(
125
+ sigma=0.5, point2plane=False, vectorized=True, penalize_outside=True)
126
+
127
+ if self.part_segm_fn:
128
+ # Read the part segmentation
129
+ part_segm_fn = os.path.expandvars(self.part_segm_fn)
130
+ with open(part_segm_fn, 'rb') as faces_parents_file:
131
+ face_segm_data = pickle.load(faces_parents_file, encoding='latin1')
132
+ faces_segm = face_segm_data['segm']
133
+ faces_parents = face_segm_data['parents']
134
+ # Create the module used to filter invalid collision pairs
135
+ filter_faces = FilterFaces(
136
+ faces_segm=faces_segm, faces_parents=faces_parents,
137
+ ign_part_pairs=None).to(device=self.device)
138
+
139
+
140
+ # Split SMPL pose to body pose and global orientation
141
+ body_pose = init_pose[:, 3:].detach().clone()
142
+ global_orient = init_pose[:, :3].detach().clone()
143
+ betas = init_betas.detach().clone()
144
+
145
+ # use guess 3d to get the initial
146
+ smpl_output = self.smpl(global_orient=global_orient,
147
+ body_pose=body_pose,
148
+ betas=betas)
149
+ model_joints = smpl_output.joints
150
+
151
+ init_cam_t = guess_init_3d(model_joints, j3d, self.joints_category).unsqueeze(1).detach()
152
+ camera_translation = init_cam_t.clone()
153
+
154
+ preserve_pose = init_pose[:, 3:].detach().clone()
155
+ # -------------Step 1: Optimize camera translation and body orientation--------
156
+ # Optimize only camera translation and body orientation
157
+ body_pose.requires_grad = False
158
+ betas.requires_grad = False
159
+ global_orient.requires_grad = True
160
+ camera_translation.requires_grad = True
161
+
162
+ camera_opt_params = [global_orient, camera_translation]
163
+
164
+ if self.use_lbfgs:
165
+ camera_optimizer = torch.optim.LBFGS(camera_opt_params, max_iter=self.num_iters,
166
+ lr=self.step_size, line_search_fn='strong_wolfe')
167
+ for i in range(10):
168
+ def closure():
169
+ camera_optimizer.zero_grad()
170
+ smpl_output = self.smpl(global_orient=global_orient,
171
+ body_pose=body_pose,
172
+ betas=betas)
173
+ model_joints = smpl_output.joints
174
+ # print('model_joints', model_joints.shape)
175
+ # print('camera_translation', camera_translation.shape)
176
+ # print('init_cam_t', init_cam_t.shape)
177
+ # print('j3d', j3d.shape)
178
+ loss = camera_fitting_loss_3d(model_joints, camera_translation,
179
+ init_cam_t, j3d, self.joints_category)
180
+ loss.backward()
181
+ return loss
182
+
183
+ camera_optimizer.step(closure)
184
+ else:
185
+ camera_optimizer = torch.optim.Adam(camera_opt_params, lr=self.step_size, betas=(0.9, 0.999))
186
+
187
+ for i in range(20):
188
+ smpl_output = self.smpl(global_orient=global_orient,
189
+ body_pose=body_pose,
190
+ betas=betas)
191
+ model_joints = smpl_output.joints
192
+
193
+ loss = camera_fitting_loss_3d(model_joints[:, self.smpl_index], camera_translation,
194
+ init_cam_t, j3d[:, self.corr_index], self.joints_category)
195
+ camera_optimizer.zero_grad()
196
+ loss.backward()
197
+ camera_optimizer.step()
198
+
199
+ # Fix camera translation after optimizing camera
200
+ # --------Step 2: Optimize body joints --------------------------
201
+ # Optimize only the body pose and global orientation of the body
202
+ body_pose.requires_grad = True
203
+ global_orient.requires_grad = True
204
+ camera_translation.requires_grad = True
205
+
206
+ # --- if we use the sequence, fix the shape
207
+ if seq_ind == 0:
208
+ betas.requires_grad = True
209
+ body_opt_params = [body_pose, betas, global_orient, camera_translation]
210
+ else:
211
+ betas.requires_grad = False
212
+ body_opt_params = [body_pose, global_orient, camera_translation]
213
+
214
+ if self.use_lbfgs:
215
+ body_optimizer = torch.optim.LBFGS(body_opt_params, max_iter=self.num_iters,
216
+ lr=self.step_size, line_search_fn='strong_wolfe')
217
+ for i in range(self.num_iters):
218
+ def closure():
219
+ body_optimizer.zero_grad()
220
+ smpl_output = self.smpl(global_orient=global_orient,
221
+ body_pose=body_pose,
222
+ betas=betas)
223
+ model_joints = smpl_output.joints
224
+ model_vertices = smpl_output.vertices
225
+
226
+ loss = body_fitting_loss_3d(body_pose, preserve_pose, betas, model_joints[:, self.smpl_index], camera_translation,
227
+ j3d[:, self.corr_index], self.pose_prior,
228
+ joints3d_conf=conf_3d,
229
+ joint_loss_weight=600.0,
230
+ pose_preserve_weight=5.0,
231
+ use_collision=self.use_collision,
232
+ model_vertices=model_vertices, model_faces=self.model_faces,
233
+ search_tree=search_tree, pen_distance=pen_distance, filter_faces=filter_faces)
234
+ loss.backward()
235
+ return loss
236
+
237
+ body_optimizer.step(closure)
238
+ else:
239
+ body_optimizer = torch.optim.Adam(body_opt_params, lr=self.step_size, betas=(0.9, 0.999))
240
+
241
+ for i in range(self.num_iters):
242
+ smpl_output = self.smpl(global_orient=global_orient,
243
+ body_pose=body_pose,
244
+ betas=betas)
245
+ model_joints = smpl_output.joints
246
+ model_vertices = smpl_output.vertices
247
+
248
+ loss = body_fitting_loss_3d(body_pose, preserve_pose, betas, model_joints[:, self.smpl_index], camera_translation,
249
+ j3d[:, self.corr_index], self.pose_prior,
250
+ joints3d_conf=conf_3d,
251
+ joint_loss_weight=600.0,
252
+ use_collision=self.use_collision,
253
+ model_vertices=model_vertices, model_faces=self.model_faces,
254
+ search_tree=search_tree, pen_distance=pen_distance, filter_faces=filter_faces)
255
+ body_optimizer.zero_grad()
256
+ loss.backward()
257
+ body_optimizer.step()
258
+
259
+ # Get final loss value
260
+ with torch.no_grad():
261
+ smpl_output = self.smpl(global_orient=global_orient,
262
+ body_pose=body_pose,
263
+ betas=betas, return_full_pose=True)
264
+ model_joints = smpl_output.joints
265
+ model_vertices = smpl_output.vertices
266
+
267
+ final_loss = body_fitting_loss_3d(body_pose, preserve_pose, betas, model_joints[:, self.smpl_index], camera_translation,
268
+ j3d[:, self.corr_index], self.pose_prior,
269
+ joints3d_conf=conf_3d,
270
+ joint_loss_weight=600.0,
271
+ use_collision=self.use_collision, model_vertices=model_vertices, model_faces=self.model_faces,
272
+ search_tree=search_tree, pen_distance=pen_distance, filter_faces=filter_faces)
273
+
274
+ vertices = smpl_output.vertices.detach()
275
+ joints = smpl_output.joints.detach()
276
+ pose = torch.cat([global_orient, body_pose], dim=-1).detach()
277
+ betas = betas.detach()
278
+
279
+ return vertices, joints, pose, betas, camera_translation, final_loss
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/render_mesh.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import os
3
+ from visualize import vis_utils
4
+ import shutil
5
+ from tqdm import tqdm
6
+
7
+ if __name__ == '__main__':
8
+ parser = argparse.ArgumentParser()
9
+ parser.add_argument("--input_path", type=str, required=True, help='stick figure mp4 file to be rendered.')
10
+ parser.add_argument("--cuda", type=bool, default=True, help='')
11
+ parser.add_argument("--device", type=int, default=0, help='')
12
+ params = parser.parse_args()
13
+
14
+ assert params.input_path.endswith('.mp4')
15
+ parsed_name = os.path.basename(params.input_path).replace('.mp4', '').replace('sample', '').replace('rep', '')
16
+ sample_i, rep_i = [int(e) for e in parsed_name.split('_')]
17
+ npy_path = os.path.join(os.path.dirname(params.input_path), 'results.npy')
18
+ out_npy_path = params.input_path.replace('.mp4', '_smpl_params.npy')
19
+ assert os.path.exists(npy_path)
20
+ results_dir = params.input_path.replace('.mp4', '_obj')
21
+ if os.path.exists(results_dir):
22
+ shutil.rmtree(results_dir)
23
+ os.makedirs(results_dir)
24
+
25
+ npy2obj = vis_utils.npy2obj(npy_path, sample_i, rep_i,
26
+ device=params.device, cuda=params.cuda)
27
+
28
+ print('Saving obj files to [{}]'.format(os.path.abspath(results_dir)))
29
+ for frame_i in tqdm(range(npy2obj.real_num_frames)):
30
+ npy2obj.save_obj(os.path.join(results_dir, 'frame{:03d}.obj'.format(frame_i)), frame_i)
31
+
32
+ print('Saving SMPL params to [{}]'.format(os.path.abspath(out_npy_path)))
33
+ npy2obj.save_npy(out_npy_path)
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/simplify_loc2rot.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import os
3
+ import torch
4
+ from visualize.joints2smpl.src import config
5
+ import smplx
6
+ import h5py
7
+ from visualize.joints2smpl.src.smplify import SMPLify3D
8
+ from tqdm import tqdm
9
+ import utils.rotation_conversions as geometry
10
+ import argparse
11
+
12
+
13
+ class joints2smpl:
14
+
15
+ def __init__(self, num_frames, device_id, cuda=True):
16
+ self.device = torch.device("cuda:" + str(device_id) if cuda else "cpu")
17
+ # self.device = torch.device("cpu")
18
+ self.batch_size = num_frames
19
+ self.num_joints = 22 # for HumanML3D
20
+ self.joint_category = "AMASS"
21
+ self.num_smplify_iters = 150
22
+ self.fix_foot = False
23
+ print(config.SMPL_MODEL_DIR)
24
+ smplmodel = smplx.create(config.SMPL_MODEL_DIR,
25
+ model_type="smpl", gender="neutral", ext="pkl",
26
+ batch_size=self.batch_size).to(self.device)
27
+
28
+ # ## --- load the mean pose as original ----
29
+ smpl_mean_file = config.SMPL_MEAN_FILE
30
+
31
+ file = h5py.File(smpl_mean_file, 'r')
32
+ self.init_mean_pose = torch.from_numpy(file['pose'][:]).unsqueeze(0).repeat(self.batch_size, 1).float().to(self.device)
33
+ self.init_mean_shape = torch.from_numpy(file['shape'][:]).unsqueeze(0).repeat(self.batch_size, 1).float().to(self.device)
34
+ self.cam_trans_zero = torch.Tensor([0.0, 0.0, 0.0]).unsqueeze(0).to(self.device)
35
+ #
36
+
37
+ # # #-------------initialize SMPLify
38
+ self.smplify = SMPLify3D(smplxmodel=smplmodel,
39
+ batch_size=self.batch_size,
40
+ joints_category=self.joint_category,
41
+ num_iters=self.num_smplify_iters,
42
+ device=self.device)
43
+
44
+
45
+ def npy2smpl(self, npy_path):
46
+ out_path = npy_path.replace('.npy', '_rot.npy')
47
+ motions = np.load(npy_path, allow_pickle=True)[None][0]
48
+ # print_batch('', motions)
49
+ n_samples = motions['motion'].shape[0]
50
+ all_thetas = []
51
+ for sample_i in tqdm(range(n_samples)):
52
+ thetas, _ = self.joint2smpl(motions['motion'][sample_i].transpose(2, 0, 1)) # [nframes, njoints, 3]
53
+ all_thetas.append(thetas.cpu().numpy())
54
+ motions['motion'] = np.concatenate(all_thetas, axis=0)
55
+ print('motions', motions['motion'].shape)
56
+
57
+ print(f'Saving [{out_path}]')
58
+ np.save(out_path, motions)
59
+ exit()
60
+
61
+
62
+
63
+ def joint2smpl(self, input_joints, init_params=None):
64
+ _smplify = self.smplify # if init_params is None else self.smplify_fast
65
+ pred_pose = torch.zeros(self.batch_size, 72).to(self.device)
66
+ pred_betas = torch.zeros(self.batch_size, 10).to(self.device)
67
+ pred_cam_t = torch.zeros(self.batch_size, 3).to(self.device)
68
+ keypoints_3d = torch.zeros(self.batch_size, self.num_joints, 3).to(self.device)
69
+
70
+ # run the whole seqs
71
+ num_seqs = input_joints.shape[0]
72
+
73
+
74
+ # joints3d = input_joints[idx] # *1.2 #scale problem [check first]
75
+ keypoints_3d = torch.Tensor(input_joints).to(self.device).float()
76
+
77
+ # if idx == 0:
78
+ if init_params is None:
79
+ pred_betas = self.init_mean_shape
80
+ pred_pose = self.init_mean_pose
81
+ pred_cam_t = self.cam_trans_zero
82
+ else:
83
+ pred_betas = init_params['betas']
84
+ pred_pose = init_params['pose']
85
+ pred_cam_t = init_params['cam']
86
+
87
+ if self.joint_category == "AMASS":
88
+ confidence_input = torch.ones(self.num_joints)
89
+ # make sure the foot and ankle
90
+ if self.fix_foot == True:
91
+ confidence_input[7] = 1.5
92
+ confidence_input[8] = 1.5
93
+ confidence_input[10] = 1.5
94
+ confidence_input[11] = 1.5
95
+ else:
96
+ print("Such category not settle down!")
97
+
98
+ new_opt_vertices, new_opt_joints, new_opt_pose, new_opt_betas, \
99
+ new_opt_cam_t, new_opt_joint_loss = _smplify(
100
+ pred_pose.detach(),
101
+ pred_betas.detach(),
102
+ pred_cam_t.detach(),
103
+ keypoints_3d,
104
+ conf_3d=confidence_input.to(self.device),
105
+ # seq_ind=idx
106
+ )
107
+
108
+ thetas = new_opt_pose.reshape(self.batch_size, 24, 3)
109
+ thetas = geometry.matrix_to_rotation_6d(geometry.axis_angle_to_matrix(thetas)) # [bs, 24, 6]
110
+ root_loc = torch.tensor(keypoints_3d[:, 0]) # [bs, 3]
111
+ root_loc = torch.cat([root_loc, torch.zeros_like(root_loc)], dim=-1).unsqueeze(1) # [bs, 1, 6]
112
+ thetas = torch.cat([thetas, root_loc], dim=1).unsqueeze(0).permute(0, 2, 3, 1) # [1, 25, 6, 196]
113
+
114
+ return thetas.clone().detach(), {'pose': new_opt_joints[0, :24].flatten().clone().detach(), 'betas': new_opt_betas.clone().detach(), 'cam': new_opt_cam_t.clone().detach()}
115
+
116
+
117
+ if __name__ == '__main__':
118
+ parser = argparse.ArgumentParser()
119
+ parser.add_argument("--input_path", type=str, required=True, help='Blender file or dir with blender files')
120
+ parser.add_argument("--cuda", type=bool, default=True, help='')
121
+ parser.add_argument("--device", type=int, default=0, help='')
122
+ params = parser.parse_args()
123
+
124
+ simplify = joints2smpl(device_id=params.device, cuda=params.cuda)
125
+
126
+ if os.path.isfile(params.input_path) and params.input_path.endswith('.npy'):
127
+ simplify.npy2smpl(params.input_path)
128
+ elif os.path.isdir(params.input_path):
129
+ files = [os.path.join(params.input_path, f) for f in os.listdir(params.input_path) if f.endswith('.npy')]
130
+ for f in files:
131
+ simplify.npy2smpl(f)
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/VQ-Trans/visualize/vis_utils.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from model.rotation2xyz import Rotation2xyz
2
+ import numpy as np
3
+ from trimesh import Trimesh
4
+ import os
5
+ import torch
6
+ from visualize.simplify_loc2rot import joints2smpl
7
+
8
+ class npy2obj:
9
+ def __init__(self, npy_path, sample_idx, rep_idx, device=0, cuda=True):
10
+ self.npy_path = npy_path
11
+ self.motions = np.load(self.npy_path, allow_pickle=True)
12
+ if self.npy_path.endswith('.npz'):
13
+ self.motions = self.motions['arr_0']
14
+ self.motions = self.motions[None][0]
15
+ self.rot2xyz = Rotation2xyz(device='cpu')
16
+ self.faces = self.rot2xyz.smpl_model.faces
17
+ self.bs, self.njoints, self.nfeats, self.nframes = self.motions['motion'].shape
18
+ self.opt_cache = {}
19
+ self.sample_idx = sample_idx
20
+ self.total_num_samples = self.motions['num_samples']
21
+ self.rep_idx = rep_idx
22
+ self.absl_idx = self.rep_idx*self.total_num_samples + self.sample_idx
23
+ self.num_frames = self.motions['motion'][self.absl_idx].shape[-1]
24
+ self.j2s = joints2smpl(num_frames=self.num_frames, device_id=device, cuda=cuda)
25
+
26
+ if self.nfeats == 3:
27
+ print(f'Running SMPLify For sample [{sample_idx}], repetition [{rep_idx}], it may take a few minutes.')
28
+ motion_tensor, opt_dict = self.j2s.joint2smpl(self.motions['motion'][self.absl_idx].transpose(2, 0, 1)) # [nframes, njoints, 3]
29
+ self.motions['motion'] = motion_tensor.cpu().numpy()
30
+ elif self.nfeats == 6:
31
+ self.motions['motion'] = self.motions['motion'][[self.absl_idx]]
32
+ self.bs, self.njoints, self.nfeats, self.nframes = self.motions['motion'].shape
33
+ self.real_num_frames = self.motions['lengths'][self.absl_idx]
34
+
35
+ self.vertices = self.rot2xyz(torch.tensor(self.motions['motion']), mask=None,
36
+ pose_rep='rot6d', translation=True, glob=True,
37
+ jointstype='vertices',
38
+ # jointstype='smpl', # for joint locations
39
+ vertstrans=True)
40
+ self.root_loc = self.motions['motion'][:, -1, :3, :].reshape(1, 1, 3, -1)
41
+ self.vertices += self.root_loc
42
+
43
+ def get_vertices(self, sample_i, frame_i):
44
+ return self.vertices[sample_i, :, :, frame_i].squeeze().tolist()
45
+
46
+ def get_trimesh(self, sample_i, frame_i):
47
+ return Trimesh(vertices=self.get_vertices(sample_i, frame_i),
48
+ faces=self.faces)
49
+
50
+ def save_obj(self, save_path, frame_i):
51
+ mesh = self.get_trimesh(0, frame_i)
52
+ with open(save_path, 'w') as fw:
53
+ mesh.export(fw, 'obj')
54
+ return save_path
55
+
56
+ def save_npy(self, save_path):
57
+ data_dict = {
58
+ 'motion': self.motions['motion'][0, :, :, :self.real_num_frames],
59
+ 'thetas': self.motions['motion'][0, :-1, :, :self.real_num_frames],
60
+ 'root_translation': self.motions['motion'][0, -1, :3, :self.real_num_frames],
61
+ 'faces': self.faces,
62
+ 'vertices': self.vertices[0, :, :, :self.real_num_frames],
63
+ 'text': self.motions['text'][0],
64
+ 'length': self.real_num_frames,
65
+ }
66
+ np.save(save_path, data_dict)
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/app.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import os
3
+ import OpenGL.GL as gl
4
+ os.environ["PYOPENGL_PLATFORM"] = "egl"
5
+ os.environ["MESA_GL_VERSION_OVERRIDE"] = "4.1"
6
+ os.system('pip install /home/user/app/pyrender')
7
+
8
+ sys.argv = ['VQ-Trans/GPT_eval_multi.py']
9
+ os.chdir('VQ-Trans')
10
+
11
+ sys.path.append('/home/user/app/VQ-Trans')
12
+ sys.path.append('/home/user/app/pyrender')
13
+
14
+ import options.option_transformer as option_trans
15
+ from huggingface_hub import snapshot_download
16
+ model_path = snapshot_download(repo_id="vumichien/T2M-GPT")
17
+
18
+ args = option_trans.get_args_parser()
19
+
20
+ args.dataname = 't2m'
21
+ args.resume_pth = f'{model_path}/VQVAE/net_last.pth'
22
+ args.resume_trans = f'{model_path}/VQTransformer_corruption05/net_best_fid.pth'
23
+ args.down_t = 2
24
+ args.depth = 3
25
+ args.block_size = 51
26
+
27
+ import clip
28
+ import torch
29
+ import numpy as np
30
+ import models.vqvae as vqvae
31
+ import models.t2m_trans as trans
32
+ from utils.motion_process import recover_from_ric
33
+ import visualization.plot_3d_global as plot_3d
34
+ from models.rotation2xyz import Rotation2xyz
35
+ import numpy as np
36
+ from trimesh import Trimesh
37
+ import gc
38
+
39
+ import torch
40
+ from visualize.simplify_loc2rot import joints2smpl
41
+ import pyrender
42
+ # import matplotlib.pyplot as plt
43
+
44
+ import io
45
+ import imageio
46
+ from shapely import geometry
47
+ import trimesh
48
+ from pyrender.constants import RenderFlags
49
+ import math
50
+ # import ffmpeg
51
+ # from PIL import Image
52
+ import hashlib
53
+ import gradio as gr
54
+ import moviepy.editor as mp
55
+
56
+ ## load clip model and datasets
57
+ is_cuda = torch.cuda.is_available()
58
+ device = torch.device("cuda" if is_cuda else "cpu")
59
+ print(device)
60
+ clip_model, clip_preprocess = clip.load("ViT-B/32", device=device, jit=False, download_root='./') # Must set jit=False for training
61
+
62
+ if is_cuda:
63
+ clip.model.convert_weights(clip_model)
64
+
65
+ clip_model.eval()
66
+ for p in clip_model.parameters():
67
+ p.requires_grad = False
68
+
69
+ net = vqvae.HumanVQVAE(args, ## use args to define different parameters in different quantizers
70
+ args.nb_code,
71
+ args.code_dim,
72
+ args.output_emb_width,
73
+ args.down_t,
74
+ args.stride_t,
75
+ args.width,
76
+ args.depth,
77
+ args.dilation_growth_rate)
78
+
79
+
80
+ trans_encoder = trans.Text2Motion_Transformer(num_vq=args.nb_code,
81
+ embed_dim=1024,
82
+ clip_dim=args.clip_dim,
83
+ block_size=args.block_size,
84
+ num_layers=9,
85
+ n_head=16,
86
+ drop_out_rate=args.drop_out_rate,
87
+ fc_rate=args.ff_rate)
88
+
89
+
90
+ print('loading checkpoint from {}'.format(args.resume_pth))
91
+ ckpt = torch.load(args.resume_pth, map_location='cpu')
92
+ net.load_state_dict(ckpt['net'], strict=True)
93
+ net.eval()
94
+
95
+ print('loading transformer checkpoint from {}'.format(args.resume_trans))
96
+ ckpt = torch.load(args.resume_trans, map_location='cpu')
97
+ trans_encoder.load_state_dict(ckpt['trans'], strict=True)
98
+ trans_encoder.eval()
99
+
100
+ mean = torch.from_numpy(np.load(f'{model_path}/meta/mean.npy'))
101
+ std = torch.from_numpy(np.load(f'{model_path}/meta/std.npy'))
102
+
103
+ if is_cuda:
104
+ net.cuda()
105
+ trans_encoder.cuda()
106
+ mean = mean.cuda()
107
+ std = std.cuda()
108
+
109
+ def render(motions, device_id=0, name='test_vis'):
110
+ frames, njoints, nfeats = motions.shape
111
+ MINS = motions.min(axis=0).min(axis=0)
112
+ MAXS = motions.max(axis=0).max(axis=0)
113
+
114
+ height_offset = MINS[1]
115
+ motions[:, :, 1] -= height_offset
116
+ trajec = motions[:, 0, [0, 2]]
117
+ is_cuda = torch.cuda.is_available()
118
+ # device = torch.device("cuda" if is_cuda else "cpu")
119
+ j2s = joints2smpl(num_frames=frames, device_id=0, cuda=is_cuda)
120
+ rot2xyz = Rotation2xyz(device=device)
121
+ faces = rot2xyz.smpl_model.faces
122
+
123
+ if not os.path.exists(f'output/{name}_pred.pt'):
124
+ print(f'Running SMPLify, it may take a few minutes.')
125
+ motion_tensor, opt_dict = j2s.joint2smpl(motions) # [nframes, njoints, 3]
126
+
127
+ vertices = rot2xyz(torch.tensor(motion_tensor).clone(), mask=None,
128
+ pose_rep='rot6d', translation=True, glob=True,
129
+ jointstype='vertices',
130
+ vertstrans=True)
131
+ vertices = vertices.detach().cpu()
132
+ torch.save(vertices, f'output/{name}_pred.pt')
133
+ else:
134
+ vertices = torch.load(f'output/{name}_pred.pt')
135
+ frames = vertices.shape[3] # shape: 1, nb_frames, 3, nb_joints
136
+ print(vertices.shape)
137
+ MINS = torch.min(torch.min(vertices[0], axis=0)[0], axis=1)[0]
138
+ MAXS = torch.max(torch.max(vertices[0], axis=0)[0], axis=1)[0]
139
+
140
+ out_list = []
141
+
142
+ minx = MINS[0] - 0.5
143
+ maxx = MAXS[0] + 0.5
144
+ minz = MINS[2] - 0.5
145
+ maxz = MAXS[2] + 0.5
146
+ polygon = geometry.Polygon([[minx, minz], [minx, maxz], [maxx, maxz], [maxx, minz]])
147
+ polygon_mesh = trimesh.creation.extrude_polygon(polygon, 1e-5)
148
+
149
+ vid = []
150
+ for i in range(frames):
151
+ if i % 10 == 0:
152
+ print(i)
153
+
154
+ mesh = Trimesh(vertices=vertices[0, :, :, i].squeeze().tolist(), faces=faces)
155
+
156
+ base_color = (0.11, 0.53, 0.8, 0.5)
157
+ ## OPAQUE rendering without alpha
158
+ ## BLEND rendering consider alpha
159
+ material = pyrender.MetallicRoughnessMaterial(
160
+ metallicFactor=0.7,
161
+ alphaMode='OPAQUE',
162
+ baseColorFactor=base_color
163
+ )
164
+
165
+
166
+ mesh = pyrender.Mesh.from_trimesh(mesh, material=material)
167
+
168
+ polygon_mesh.visual.face_colors = [0, 0, 0, 0.21]
169
+ polygon_render = pyrender.Mesh.from_trimesh(polygon_mesh, smooth=False)
170
+
171
+ bg_color = [1, 1, 1, 0.8]
172
+ scene = pyrender.Scene(bg_color=bg_color, ambient_light=(0.4, 0.4, 0.4))
173
+
174
+ sx, sy, tx, ty = [0.75, 0.75, 0, 0.10]
175
+
176
+ camera = pyrender.PerspectiveCamera(yfov=(np.pi / 3.0))
177
+
178
+ light = pyrender.DirectionalLight(color=[1,1,1], intensity=300)
179
+
180
+ scene.add(mesh)
181
+
182
+ c = np.pi / 2
183
+
184
+ scene.add(polygon_render, pose=np.array([[ 1, 0, 0, 0],
185
+
186
+ [ 0, np.cos(c), -np.sin(c), MINS[1].cpu().numpy()],
187
+
188
+ [ 0, np.sin(c), np.cos(c), 0],
189
+
190
+ [ 0, 0, 0, 1]]))
191
+
192
+ light_pose = np.eye(4)
193
+ light_pose[:3, 3] = [0, -1, 1]
194
+ scene.add(light, pose=light_pose.copy())
195
+
196
+ light_pose[:3, 3] = [0, 1, 1]
197
+ scene.add(light, pose=light_pose.copy())
198
+
199
+ light_pose[:3, 3] = [1, 1, 2]
200
+ scene.add(light, pose=light_pose.copy())
201
+
202
+
203
+ c = -np.pi / 6
204
+
205
+ scene.add(camera, pose=[[ 1, 0, 0, (minx+maxx).cpu().numpy()/2],
206
+
207
+ [ 0, np.cos(c), -np.sin(c), 1.5],
208
+
209
+ [ 0, np.sin(c), np.cos(c), max(4, minz.cpu().numpy()+(1.5-MINS[1].cpu().numpy())*2, (maxx-minx).cpu().numpy())],
210
+
211
+ [ 0, 0, 0, 1]
212
+ ])
213
+
214
+ # render scene
215
+ r = pyrender.OffscreenRenderer(960, 960)
216
+
217
+ color, _ = r.render(scene, flags=RenderFlags.RGBA)
218
+ # Image.fromarray(color).save(outdir+'/'+name+'_'+str(i)+'.png')
219
+
220
+ vid.append(color)
221
+
222
+ r.delete()
223
+
224
+ out = np.stack(vid, axis=0)
225
+ imageio.mimwrite(f'output/results.gif', out, duration=50)
226
+ out_video = mp.VideoFileClip(f'output/results.gif')
227
+ out_video.write_videofile("output/results.mp4")
228
+ del out, vertices
229
+ return f'output/results.mp4'
230
+
231
+ def predict(clip_text, method='fast'):
232
+ gc.collect()
233
+ print('prompt text instruction: {}'.format(clip_text))
234
+ if torch.cuda.is_available():
235
+ text = clip.tokenize([clip_text], truncate=True).cuda()
236
+ else:
237
+ text = clip.tokenize([clip_text], truncate=True)
238
+ feat_clip_text = clip_model.encode_text(text).float()
239
+ index_motion = trans_encoder.sample(feat_clip_text[0:1], False)
240
+ pred_pose = net.forward_decoder(index_motion)
241
+ pred_xyz = recover_from_ric((pred_pose*std+mean).float(), 22)
242
+ output_name = hashlib.md5(clip_text.encode()).hexdigest()
243
+ if method == 'fast':
244
+ xyz = pred_xyz.reshape(1, -1, 22, 3)
245
+ pose_vis = plot_3d.draw_to_batch(xyz.detach().cpu().numpy(), title_batch=None, outname=[f'output/results.gif'])
246
+ out_video = mp.VideoFileClip("output/results.gif")
247
+ out_video.write_videofile("output/results.mp4")
248
+ return f'output/results.mp4'
249
+ elif method == 'slow':
250
+ output_path = render(pred_xyz.detach().cpu().numpy().squeeze(axis=0), device_id=0, name=output_name)
251
+ return output_path
252
+
253
+
254
+ # ---- Gradio Layout -----
255
+ video_out = gr.Video(label="Motion", mirror_webcam=False, interactive=False)
256
+ demo = gr.Blocks()
257
+ demo.encrypt = False
258
+
259
+ with demo:
260
+ gr.Markdown('''
261
+ <div>
262
+ <h1 style='text-align: center'>Generating Human Motion from Textual Descriptions (T2M-GPT)</h1>
263
+ This space uses <a href='https://mael-zys.github.io/T2M-GPT/' target='_blank'><b>T2M-GPT models</b></a> based on Vector Quantised-Variational AutoEncoder (VQ-VAE) and Generative Pre-trained Transformer (GPT) for human motion generation from textural descriptions🤗
264
+ </div>
265
+ ''')
266
+ with gr.Row():
267
+ with gr.Column():
268
+ gr.Markdown('''
269
+ <figure>
270
+ <img src="https://huggingface.co/vumichien/T2M-GPT/resolve/main/demo_slow1.gif" alt="Demo Slow", width="425", height=480/>
271
+ <figcaption> a man starts off in an up right position with botg arms extended out by his sides, he then brings his arms down to his body and claps his hands together. after this he wals down amd the the left where he proceeds to sit on a seat
272
+ </figcaption>
273
+ </figure>
274
+ ''')
275
+ with gr.Column():
276
+ gr.Markdown('''
277
+ <figure>
278
+ <img src="https://huggingface.co/vumichien/T2M-GPT/resolve/main/demo_slow2.gif" alt="Demo Slow 2", width="425", height=480/>
279
+ <figcaption> a person puts their hands together, leans forwards slightly then swings the arms from right to left
280
+ </figcaption>
281
+ </figure>
282
+ ''')
283
+ with gr.Column():
284
+ gr.Markdown('''
285
+ <figure>
286
+ <img src="https://huggingface.co/vumichien/T2M-GPT/resolve/main/demo_slow3.gif" alt="Demo Slow 3", width="425", height=480/>
287
+ <figcaption> a man is practicing the waltz with a partner
288
+ </figcaption>
289
+ </figure>
290
+ ''')
291
+ with gr.Row():
292
+ with gr.Column():
293
+ gr.Markdown('''
294
+ ### Generate human motion by **T2M-GPT**
295
+ ##### Step 1. Give prompt text describing human motion
296
+ ##### Step 2. Choice method to render output (Fast: Sketch skeleton; Slow: SMPL mesh, only work with GPU and running time around 2 mins)
297
+ ##### Step 3. Generate output and enjoy
298
+ ''')
299
+ with gr.Column():
300
+ with gr.Row():
301
+ text_prompt = gr.Textbox(label="Text prompt", lines=1, interactive=True)
302
+ method = gr.Dropdown(["slow", "fast"], label="Method", value="slow")
303
+ with gr.Row():
304
+ generate_btn = gr.Button("Generate")
305
+ generate_btn.click(predict, [text_prompt, method], [video_out], api_name="generate")
306
+ with gr.Row():
307
+ video_out.render()
308
+ with gr.Row():
309
+ gr.Markdown('''
310
+ ### You can test by following examples:
311
+ ''')
312
+ examples = gr.Examples(
313
+ examples=[
314
+ ["a person jogs in place, slowly at first, then increases speed. they then back up and squat down.", "slow"],
315
+ ["a man steps forward and does a handstand", "slow"],
316
+ ["a man rises from the ground, walks in a circle and sits back down on the ground", "slow"],
317
+ ["a man starts off in an up right position with botg arms extended out by his sides, he then brings his arms down to his body and claps his hands together. after this he wals down amd the the left where he proceeds to sit on a seat", "slow"],
318
+ ["a person puts their hands together, leans forwards slightly then swings the arms from right to left","slow"],
319
+ ["a man is practicing the waltz with a partner","slow"],
320
+ ],
321
+ label="Examples",
322
+ inputs=[text_prompt, method],
323
+ outputs=[video_out],
324
+ fn=predict,
325
+ cache_examples=True,
326
+ )
327
+
328
+
329
+ demo.launch(debug=True)
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/packages.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ libgl1-mesa-dev
2
+ libglu1-mesa-dev
3
+ freeglut3-dev
4
+ mesa-common-dev
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/.coveragerc ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ [report]
2
+ exclude_lines =
3
+ def __repr__
4
+ def __str__
5
+ @abc.abstractmethod
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/.flake8 ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ [flake8]
2
+ ignore = E231,W504,F405,F403
3
+ max-line-length = 79
4
+ select = B,C,E,F,W,T4,B9
5
+ exclude =
6
+ docs/source/conf.py,
7
+ __pycache__,
8
+ examples/*
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/.gitignore ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ docs/**/generated/**
7
+
8
+ # C extensions
9
+ *.so
10
+
11
+ # Distribution / packaging
12
+ .Python
13
+ build/
14
+ develop-eggs/
15
+ dist/
16
+ downloads/
17
+ eggs/
18
+ .eggs/
19
+ lib/
20
+ lib64/
21
+ parts/
22
+ sdist/
23
+ var/
24
+ wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ .hypothesis/
50
+ .pytest_cache/
51
+
52
+ # Translations
53
+ *.mo
54
+ *.pot
55
+
56
+ # Django stuff:
57
+ *.log
58
+ local_settings.py
59
+ db.sqlite3
60
+
61
+ # Flask stuff:
62
+ instance/
63
+ .webassets-cache
64
+
65
+ # Scrapy stuff:
66
+ .scrapy
67
+
68
+ # Sphinx documentation
69
+ docs/_build/
70
+
71
+ # PyBuilder
72
+ target/
73
+
74
+ # Jupyter Notebook
75
+ .ipynb_checkpoints
76
+
77
+ # pyenv
78
+ .python-version
79
+
80
+ # celery beat schedule file
81
+ celerybeat-schedule
82
+
83
+ # SageMath parsed files
84
+ *.sage.py
85
+
86
+ # Environments
87
+ .env
88
+ .venv
89
+ env/
90
+ venv/
91
+ ENV/
92
+ env.bak/
93
+ venv.bak/
94
+
95
+ # Spyder project settings
96
+ .spyderproject
97
+ .spyproject
98
+
99
+ # Rope project settings
100
+ .ropeproject
101
+
102
+ # mkdocs documentation
103
+ /site
104
+
105
+ # mypy
106
+ .mypy_cache/
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/.pre-commit-config.yaml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ repos:
2
+ - repo: https://gitlab.com/pycqa/flake8
3
+ rev: 3.7.1
4
+ hooks:
5
+ - id: flake8
6
+ exclude: ^setup.py
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/.travis.yml ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: python
2
+ sudo: required
3
+ dist: xenial
4
+
5
+ python:
6
+ - '3.6'
7
+ - '3.7'
8
+
9
+ before_install:
10
+ # Pre-install osmesa
11
+ - sudo apt update
12
+ - sudo wget https://github.com/mmatl/travis_debs/raw/master/xenial/mesa_18.3.3-0.deb
13
+ - sudo dpkg -i ./mesa_18.3.3-0.deb || true
14
+ - sudo apt install -f
15
+ - git clone https://github.com/mmatl/pyopengl.git
16
+ - cd pyopengl
17
+ - pip install .
18
+ - cd ..
19
+
20
+ install:
21
+ - pip install .
22
+ # - pip install -q pytest pytest-cov coveralls
23
+ - pip install pytest pytest-cov coveralls
24
+ - pip install ./pyopengl
25
+
26
+ script:
27
+ - PYOPENGL_PLATFORM=osmesa pytest --cov=pyrender tests
28
+
29
+ after_success:
30
+ - coveralls || true
31
+
32
+ deploy:
33
+ provider: pypi
34
+ skip_existing: true
35
+ user: mmatl
36
+ on:
37
+ tags: true
38
+ branch: master
39
+ password:
40
+ secure: O4WWMbTYb2eVYIO4mMOVa6/xyhX7mPvJpd96cxfNvJdyuqho8VapOhzqsI5kahMB1hFjWWr61yR4+Ru5hoDYf3XA6BQVk8eCY9+0H7qRfvoxex71lahKAqfHLMoE1xNdiVTgl+QN9hYjOnopLod24rx8I8eXfpHu/mfCpuTYGyLlNcDP5St3bXpXLPB5wg8Jo1YRRv6W/7fKoXyuWjewk9cJAS0KrEgnDnSkdwm6Pb+80B2tcbgdGvpGaByw5frndwKiMUMgVUownepDU5POQq2p29wwn9lCvRucULxjEgO+63jdbZRj5fNutLarFa2nISfYnrd72LOyDfbJubwAzzAIsy2JbFORyeHvCgloiuE9oE7a9oOQt/1QHBoIV0seiawMWn55Yp70wQ7HlJs4xSGJWCGa5+9883QRNsvj420atkb3cgO8P+PXwiwTi78Dq7Z/xHqccsU0b8poqBneQoA+pUGgNnF6V7Z8e9RsCcse2gAWSZWuOK3ua+9xCgH7I7MeL3afykr2aJ+yFCoYJMFrUjJeodMX2RbL0q+3FzIPZeGW3WdhTEAL9TSKRcJBSQTskaQlZx/OcpobxS7t3d2S68CCLG9uMTqOTYws55WZ1etalA75sRk9K2MR7ZGjZW3jdtvMViISc/t6Rrjea1GE8ZHGJC6/IeLIWA2c7nc=
41
+ distributions: sdist bdist_wheel
42
+ notifications:
43
+ email: false
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Matthew Matl
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/MANIFEST.in ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Include the license
2
+ include LICENSE
3
+ include README.rst
4
+ include pyrender/fonts/*
5
+ include pyrender/shaders/*
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/README.md ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Pyrender
2
+
3
+ [![Build Status](https://travis-ci.org/mmatl/pyrender.svg?branch=master)](https://travis-ci.org/mmatl/pyrender)
4
+ [![Documentation Status](https://readthedocs.org/projects/pyrender/badge/?version=latest)](https://pyrender.readthedocs.io/en/latest/?badge=latest)
5
+ [![Coverage Status](https://coveralls.io/repos/github/mmatl/pyrender/badge.svg?branch=master)](https://coveralls.io/github/mmatl/pyrender?branch=master)
6
+ [![PyPI version](https://badge.fury.io/py/pyrender.svg)](https://badge.fury.io/py/pyrender)
7
+ [![Downloads](https://pepy.tech/badge/pyrender)](https://pepy.tech/project/pyrender)
8
+
9
+ Pyrender is a pure Python (2.7, 3.4, 3.5, 3.6) library for physically-based
10
+ rendering and visualization.
11
+ It is designed to meet the [glTF 2.0 specification from Khronos](https://www.khronos.org/gltf/).
12
+
13
+ Pyrender is lightweight, easy to install, and simple to use.
14
+ It comes packaged with both an intuitive scene viewer and a headache-free
15
+ offscreen renderer with support for GPU-accelerated rendering on headless
16
+ servers, which makes it perfect for machine learning applications.
17
+
18
+ Extensive documentation, including a quickstart guide, is provided [here](https://pyrender.readthedocs.io/en/latest/).
19
+
20
+ For a minimal working example of GPU-accelerated offscreen rendering using EGL,
21
+ check out the [EGL Google CoLab Notebook](https://colab.research.google.com/drive/1pcndwqeY8vker3bLKQNJKr3B-7-SYenE?usp=sharing).
22
+
23
+
24
+ <p align="center">
25
+ <img width="48%" src="https://github.com/mmatl/pyrender/blob/master/docs/source/_static/rotation.gif?raw=true" alt="GIF of Viewer"/>
26
+ <img width="48%" src="https://github.com/mmatl/pyrender/blob/master/docs/source/_static/damaged_helmet.png?raw=true" alt="Damaged Helmet"/>
27
+ </p>
28
+
29
+ ## Installation
30
+ You can install pyrender directly from pip.
31
+
32
+ ```bash
33
+ pip install pyrender
34
+ ```
35
+
36
+ ## Features
37
+
38
+ Despite being lightweight, pyrender has lots of features, including:
39
+
40
+ * Simple interoperation with the amazing [trimesh](https://github.com/mikedh/trimesh) project,
41
+ which enables out-of-the-box support for dozens of mesh types, including OBJ,
42
+ STL, DAE, OFF, PLY, and GLB.
43
+ * An easy-to-use scene viewer with support for animation, showing face and vertex
44
+ normals, toggling lighting conditions, and saving images and GIFs.
45
+ * An offscreen rendering module that supports OSMesa and EGL backends.
46
+ * Shadow mapping for directional and spot lights.
47
+ * Metallic-roughness materials for physically-based rendering, including several
48
+ types of texture and normal mapping.
49
+ * Transparency.
50
+ * Depth and color image generation.
51
+
52
+ ## Sample Usage
53
+
54
+ For sample usage, check out the [quickstart
55
+ guide](https://pyrender.readthedocs.io/en/latest/examples/index.html) or one of
56
+ the Google CoLab Notebooks:
57
+
58
+ * [EGL Google CoLab Notebook](https://colab.research.google.com/drive/1pcndwqeY8vker3bLKQNJKr3B-7-SYenE?usp=sharing)
59
+
60
+ ## Viewer Keyboard and Mouse Controls
61
+
62
+ When using the viewer, the basic controls for moving about the scene are as follows:
63
+
64
+ * To rotate the camera about the center of the scene, hold the left mouse button and drag the cursor.
65
+ * To rotate the camera about its viewing axis, hold `CTRL` left mouse button and drag the cursor.
66
+ * To pan the camera, do one of the following:
67
+ * Hold `SHIFT`, then hold the left mouse button and drag the cursor.
68
+ * Hold the middle mouse button and drag the cursor.
69
+ * To zoom the camera in or out, do one of the following:
70
+ * Scroll the mouse wheel.
71
+ * Hold the right mouse button and drag the cursor.
72
+
73
+ The available keyboard commands are as follows:
74
+
75
+ * `a`: Toggles rotational animation mode.
76
+ * `c`: Toggles backface culling.
77
+ * `f`: Toggles fullscreen mode.
78
+ * `h`: Toggles shadow rendering.
79
+ * `i`: Toggles axis display mode (no axes, world axis, mesh axes, all axes).
80
+ * `l`: Toggles lighting mode (scene lighting, Raymond lighting, or direct lighting).
81
+ * `m`: Toggles face normal visualization.
82
+ * `n`: Toggles vertex normal visualization.
83
+ * `o`: Toggles orthographic camera mode.
84
+ * `q`: Quits the viewer.
85
+ * `r`: Starts recording a GIF, and pressing again stops recording and opens a file dialog.
86
+ * `s`: Opens a file dialog to save the current view as an image.
87
+ * `w`: Toggles wireframe mode (scene default, flip wireframes, all wireframe, or all solid).
88
+ * `z`: Resets the camera to the default view.
89
+
90
+ As a note, displaying shadows significantly slows down rendering, so if you're
91
+ experiencing low framerates, just kill shadows or reduce the number of lights in
92
+ your scene.
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/Makefile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Minimal makefile for Sphinx documentation
2
+ #
3
+
4
+ # You can set these variables from the command line.
5
+ SPHINXOPTS =
6
+ SPHINXBUILD = sphinx-build
7
+ SOURCEDIR = source
8
+ BUILDDIR = build
9
+
10
+ # Put it first so that "make" without argument is like "make help".
11
+ help:
12
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
13
+
14
+ .PHONY: help Makefile
15
+
16
+ clean:
17
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
18
+ rm -rf ./source/generated/*
19
+
20
+ # Catch-all target: route all unknown targets to Sphinx using the new
21
+ # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
22
+ %: Makefile
23
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/make.bat ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @ECHO OFF
2
+
3
+ pushd %~dp0
4
+
5
+ REM Command file for Sphinx documentation
6
+
7
+ if "%SPHINXBUILD%" == "" (
8
+ set SPHINXBUILD=sphinx-build
9
+ )
10
+ set SOURCEDIR=source
11
+ set BUILDDIR=build
12
+
13
+ if "%1" == "" goto help
14
+
15
+ %SPHINXBUILD% >NUL 2>NUL
16
+ if errorlevel 9009 (
17
+ echo.
18
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19
+ echo.installed, then set the SPHINXBUILD environment variable to point
20
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
21
+ echo.may add the Sphinx directory to PATH.
22
+ echo.
23
+ echo.If you don't have Sphinx installed, grab it from
24
+ echo.http://sphinx-doc.org/
25
+ exit /b 1
26
+ )
27
+
28
+ %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
29
+ goto end
30
+
31
+ :help
32
+ %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
33
+
34
+ :end
35
+ popd
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/api/index.rst ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Pyrender API Documentation
2
+ ==========================
3
+
4
+ Constants
5
+ ---------
6
+ .. automodapi:: pyrender.constants
7
+ :no-inheritance-diagram:
8
+ :no-main-docstr:
9
+ :no-heading:
10
+
11
+ Cameras
12
+ -------
13
+ .. automodapi:: pyrender.camera
14
+ :no-inheritance-diagram:
15
+ :no-main-docstr:
16
+ :no-heading:
17
+
18
+ Lighting
19
+ --------
20
+ .. automodapi:: pyrender.light
21
+ :no-inheritance-diagram:
22
+ :no-main-docstr:
23
+ :no-heading:
24
+
25
+ Objects
26
+ -------
27
+ .. automodapi:: pyrender
28
+ :no-inheritance-diagram:
29
+ :no-main-docstr:
30
+ :no-heading:
31
+ :skip: Camera, DirectionalLight, Light, OffscreenRenderer, Node
32
+ :skip: OrthographicCamera, PerspectiveCamera, PointLight, RenderFlags
33
+ :skip: Renderer, Scene, SpotLight, TextAlign, Viewer, GLTF
34
+
35
+ Scenes
36
+ ------
37
+ .. automodapi:: pyrender
38
+ :no-inheritance-diagram:
39
+ :no-main-docstr:
40
+ :no-heading:
41
+ :skip: Camera, DirectionalLight, Light, OffscreenRenderer
42
+ :skip: OrthographicCamera, PerspectiveCamera, PointLight, RenderFlags
43
+ :skip: Renderer, SpotLight, TextAlign, Viewer, Sampler, Texture, Material
44
+ :skip: MetallicRoughnessMaterial, Primitive, Mesh, GLTF
45
+
46
+ On-Screen Viewer
47
+ ----------------
48
+ .. automodapi:: pyrender.viewer
49
+ :no-inheritance-diagram:
50
+ :no-inherited-members:
51
+ :no-main-docstr:
52
+ :no-heading:
53
+
54
+ Off-Screen Rendering
55
+ --------------------
56
+ .. automodapi:: pyrender.offscreen
57
+ :no-inheritance-diagram:
58
+ :no-main-docstr:
59
+ :no-heading:
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/conf.py ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # core documentation build configuration file, created by
4
+ # sphinx-quickstart on Sun Oct 16 14:33:48 2016.
5
+ #
6
+ # This file is execfile()d with the current directory set to its
7
+ # containing dir.
8
+ #
9
+ # Note that not all possible configuration values are present in this
10
+ # autogenerated file.
11
+ #
12
+ # All configuration values have a default; values that are commented out
13
+ # serve to show the default.
14
+
15
+ import sys
16
+ import os
17
+ from pyrender import __version__
18
+ from sphinx.domains.python import PythonDomain
19
+
20
+ # If extensions (or modules to document with autodoc) are in another directory,
21
+ # add these directories to sys.path here. If the directory is relative to the
22
+ # documentation root, use os.path.abspath to make it absolute, like shown here.
23
+ sys.path.insert(0, os.path.abspath('../../'))
24
+
25
+ # -- General configuration ------------------------------------------------
26
+
27
+ # If your documentation needs a minimal Sphinx version, state it here.
28
+ #needs_sphinx = '1.0'
29
+
30
+ # Add any Sphinx extension module names here, as strings. They can be
31
+ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
32
+ # ones.
33
+ extensions = [
34
+ 'sphinx.ext.autodoc',
35
+ 'sphinx.ext.autosummary',
36
+ 'sphinx.ext.coverage',
37
+ 'sphinx.ext.githubpages',
38
+ 'sphinx.ext.intersphinx',
39
+ 'sphinx.ext.napoleon',
40
+ 'sphinx.ext.viewcode',
41
+ 'sphinx_automodapi.automodapi',
42
+ 'sphinx_automodapi.smart_resolver'
43
+ ]
44
+ numpydoc_class_members_toctree = False
45
+ automodapi_toctreedirnm = 'generated'
46
+ automodsumm_inherited_members = True
47
+
48
+ # Add any paths that contain templates here, relative to this directory.
49
+ templates_path = ['_templates']
50
+
51
+ # The suffix(es) of source filenames.
52
+ # You can specify multiple suffix as a list of string:
53
+ # source_suffix = ['.rst', '.md']
54
+ source_suffix = '.rst'
55
+
56
+ # The encoding of source files.
57
+ #source_encoding = 'utf-8-sig'
58
+
59
+ # The master toctree document.
60
+ master_doc = 'index'
61
+
62
+ # General information about the project.
63
+ project = u'pyrender'
64
+ copyright = u'2018, Matthew Matl'
65
+ author = u'Matthew Matl'
66
+
67
+ # The version info for the project you're documenting, acts as replacement for
68
+ # |version| and |release|, also used in various other places throughout the
69
+ # built documents.
70
+ #
71
+ # The short X.Y version.
72
+ version = __version__
73
+ # The full version, including alpha/beta/rc tags.
74
+ release = __version__
75
+
76
+ # The language for content autogenerated by Sphinx. Refer to documentation
77
+ # for a list of supported languages.
78
+ #
79
+ # This is also used if you do content translation via gettext catalogs.
80
+ # Usually you set "language" from the command line for these cases.
81
+ language = None
82
+
83
+ # There are two options for replacing |today|: either, you set today to some
84
+ # non-false value, then it is used:
85
+ #today = ''
86
+ # Else, today_fmt is used as the format for a strftime call.
87
+ #today_fmt = '%B %d, %Y'
88
+
89
+ # List of patterns, relative to source directory, that match files and
90
+ # directories to ignore when looking for source files.
91
+ exclude_patterns = []
92
+
93
+ # The reST default role (used for this markup: `text`) to use for all
94
+ # documents.
95
+ #default_role = None
96
+
97
+ # If true, '()' will be appended to :func: etc. cross-reference text.
98
+ #add_function_parentheses = True
99
+
100
+ # If true, the current module name will be prepended to all description
101
+ # unit titles (such as .. function::).
102
+ #add_module_names = True
103
+
104
+ # If true, sectionauthor and moduleauthor directives will be shown in the
105
+ # output. They are ignored by default.
106
+ #show_authors = False
107
+
108
+ # The name of the Pygments (syntax highlighting) style to use.
109
+ pygments_style = 'sphinx'
110
+
111
+ # A list of ignored prefixes for module index sorting.
112
+ #modindex_common_prefix = []
113
+
114
+ # If true, keep warnings as "system message" paragraphs in the built documents.
115
+ #keep_warnings = False
116
+
117
+ # If true, `todo` and `todoList` produce output, else they produce nothing.
118
+ todo_include_todos = False
119
+
120
+
121
+ # -- Options for HTML output ----------------------------------------------
122
+
123
+ # The theme to use for HTML and HTML Help pages. See the documentation for
124
+ # a list of builtin themes.
125
+ import sphinx_rtd_theme
126
+ html_theme = 'sphinx_rtd_theme'
127
+ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
128
+
129
+ # Theme options are theme-specific and customize the look and feel of a theme
130
+ # further. For a list of options available for each theme, see the
131
+ # documentation.
132
+ #html_theme_options = {}
133
+
134
+ # Add any paths that contain custom themes here, relative to this directory.
135
+ #html_theme_path = []
136
+
137
+ # The name for this set of Sphinx documents. If None, it defaults to
138
+ # "<project> v<release> documentation".
139
+ #html_title = None
140
+
141
+ # A shorter title for the navigation bar. Default is the same as html_title.
142
+ #html_short_title = None
143
+
144
+ # The name of an image file (relative to this directory) to place at the top
145
+ # of the sidebar.
146
+ #html_logo = None
147
+
148
+ # The name of an image file (relative to this directory) to use as a favicon of
149
+ # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
150
+ # pixels large.
151
+ #html_favicon = None
152
+
153
+ # Add any paths that contain custom static files (such as style sheets) here,
154
+ # relative to this directory. They are copied after the builtin static files,
155
+ # so a file named "default.css" will overwrite the builtin "default.css".
156
+ html_static_path = ['_static']
157
+
158
+ # Add any extra paths that contain custom files (such as robots.txt or
159
+ # .htaccess) here, relative to this directory. These files are copied
160
+ # directly to the root of the documentation.
161
+ #html_extra_path = []
162
+
163
+ # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
164
+ # using the given strftime format.
165
+ #html_last_updated_fmt = '%b %d, %Y'
166
+
167
+ # If true, SmartyPants will be used to convert quotes and dashes to
168
+ # typographically correct entities.
169
+ #html_use_smartypants = True
170
+
171
+ # Custom sidebar templates, maps document names to template names.
172
+ #html_sidebars = {}
173
+
174
+ # Additional templates that should be rendered to pages, maps page names to
175
+ # template names.
176
+ #html_additional_pages = {}
177
+
178
+ # If false, no module index is generated.
179
+ #html_domain_indices = True
180
+
181
+ # If false, no index is generated.
182
+ #html_use_index = True
183
+
184
+ # If true, the index is split into individual pages for each letter.
185
+ #html_split_index = False
186
+
187
+ # If true, links to the reST sources are added to the pages.
188
+ #html_show_sourcelink = True
189
+
190
+ # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
191
+ #html_show_sphinx = True
192
+
193
+ # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
194
+ #html_show_copyright = True
195
+
196
+ # If true, an OpenSearch description file will be output, and all pages will
197
+ # contain a <link> tag referring to it. The value of this option must be the
198
+ # base URL from which the finished HTML is served.
199
+ #html_use_opensearch = ''
200
+
201
+ # This is the file name suffix for HTML files (e.g. ".xhtml").
202
+ #html_file_suffix = None
203
+
204
+ # Language to be used for generating the HTML full-text search index.
205
+ # Sphinx supports the following languages:
206
+ # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
207
+ # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
208
+ #html_search_language = 'en'
209
+
210
+ # A dictionary with options for the search language support, empty by default.
211
+ # Now only 'ja' uses this config value
212
+ #html_search_options = {'type': 'default'}
213
+
214
+ # The name of a javascript file (relative to the configuration directory) that
215
+ # implements a search results scorer. If empty, the default will be used.
216
+ #html_search_scorer = 'scorer.js'
217
+
218
+ # Output file base name for HTML help builder.
219
+ htmlhelp_basename = 'coredoc'
220
+
221
+ # -- Options for LaTeX output ---------------------------------------------
222
+
223
+ latex_elements = {
224
+ # The paper size ('letterpaper' or 'a4paper').
225
+ #'papersize': 'letterpaper',
226
+
227
+ # The font size ('10pt', '11pt' or '12pt').
228
+ #'pointsize': '10pt',
229
+
230
+ # Additional stuff for the LaTeX preamble.
231
+ #'preamble': '',
232
+
233
+ # Latex figure (float) alignment
234
+ #'figure_align': 'htbp',
235
+ }
236
+
237
+ # Grouping the document tree into LaTeX files. List of tuples
238
+ # (source start file, target name, title,
239
+ # author, documentclass [howto, manual, or own class]).
240
+ latex_documents = [
241
+ (master_doc, 'pyrender.tex', u'pyrender Documentation',
242
+ u'Matthew Matl', 'manual'),
243
+ ]
244
+
245
+ # The name of an image file (relative to this directory) to place at the top of
246
+ # the title page.
247
+ #latex_logo = None
248
+
249
+ # For "manual" documents, if this is true, then toplevel headings are parts,
250
+ # not chapters.
251
+ #latex_use_parts = False
252
+
253
+ # If true, show page references after internal links.
254
+ #latex_show_pagerefs = False
255
+
256
+ # If true, show URL addresses after external links.
257
+ #latex_show_urls = False
258
+
259
+ # Documents to append as an appendix to all manuals.
260
+ #latex_appendices = []
261
+
262
+ # If false, no module index is generated.
263
+ #latex_domain_indices = True
264
+
265
+
266
+ # -- Options for manual page output ---------------------------------------
267
+
268
+ # One entry per manual page. List of tuples
269
+ # (source start file, name, description, authors, manual section).
270
+ man_pages = [
271
+ (master_doc, 'pyrender', u'pyrender Documentation',
272
+ [author], 1)
273
+ ]
274
+
275
+ # If true, show URL addresses after external links.
276
+ #man_show_urls = False
277
+
278
+
279
+ # -- Options for Texinfo output -------------------------------------------
280
+
281
+ # Grouping the document tree into Texinfo files. List of tuples
282
+ # (source start file, target name, title, author,
283
+ # dir menu entry, description, category)
284
+ texinfo_documents = [
285
+ (master_doc, 'pyrender', u'pyrender Documentation',
286
+ author, 'pyrender', 'One line description of project.',
287
+ 'Miscellaneous'),
288
+ ]
289
+
290
+ # Documents to append as an appendix to all manuals.
291
+ #texinfo_appendices = []
292
+
293
+ # If false, no module index is generated.
294
+ #texinfo_domain_indices = True
295
+
296
+ # How to display URL addresses: 'footnote', 'no', or 'inline'.
297
+ #texinfo_show_urls = 'footnote'
298
+
299
+ # If true, do not generate a @detailmenu in the "Top" node's menu.
300
+ #texinfo_no_detailmenu = False
301
+
302
+ intersphinx_mapping = {
303
+ 'python' : ('https://docs.python.org/', None),
304
+ 'pyrender' : ('https://pyrender.readthedocs.io/en/latest/', None),
305
+ }
306
+
307
+ # Autosummary fix
308
+ autosummary_generate = True
309
+
310
+ # Try to suppress multiple-definition warnings by always taking the shorter
311
+ # path when two or more paths have the same base module
312
+
313
+ class MyPythonDomain(PythonDomain):
314
+
315
+ def find_obj(self, env, modname, classname, name, type, searchmode=0):
316
+ """Ensures an object always resolves to the desired module
317
+ if defined there."""
318
+ orig_matches = PythonDomain.find_obj(
319
+ self, env, modname, classname, name, type, searchmode
320
+ )
321
+
322
+ if len(orig_matches) <= 1:
323
+ return orig_matches
324
+
325
+ # If multiple matches, try to take the shortest if all the modules are
326
+ # the same
327
+ first_match_name_sp = orig_matches[0][0].split('.')
328
+ base_name = first_match_name_sp[0]
329
+ min_len = len(first_match_name_sp)
330
+ best_match = orig_matches[0]
331
+
332
+ for match in orig_matches[1:]:
333
+ match_name = match[0]
334
+ match_name_sp = match_name.split('.')
335
+ match_base = match_name_sp[0]
336
+
337
+ # If we have mismatched bases, return them all to trigger warnings
338
+ if match_base != base_name:
339
+ return orig_matches
340
+
341
+ # Otherwise, check and see if it's shorter
342
+ if len(match_name_sp) < min_len:
343
+ min_len = len(match_name_sp)
344
+ best_match = match
345
+
346
+ return (best_match,)
347
+
348
+
349
+ def setup(sphinx):
350
+ """Use MyPythonDomain in place of PythonDomain"""
351
+ sphinx.override_domain(MyPythonDomain)
352
+
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/examples/cameras.rst ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .. _camera_guide:
2
+
3
+ Creating Cameras
4
+ ================
5
+
6
+ Pyrender supports three camera types -- :class:`.PerspectiveCamera` and
7
+ :class:`.IntrinsicsCamera` types,
8
+ which render scenes as a human would see them, and
9
+ :class:`.OrthographicCamera` types, which preserve distances between points.
10
+
11
+ Creating cameras is easy -- just specify their basic attributes:
12
+
13
+ >>> pc = pyrender.PerspectiveCamera(yfov=np.pi / 3.0, aspectRatio=1.414)
14
+ >>> oc = pyrender.OrthographicCamera(xmag=1.0, ymag=1.0)
15
+
16
+ For more information, see the Khronos group's documentation here_:
17
+
18
+ .. _here: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#projection-matrices
19
+
20
+ When you add cameras to the scene, make sure that you're using OpenGL camera
21
+ coordinates to specify their pose. See the illustration below for details.
22
+ Basically, the camera z-axis points away from the scene, the x-axis points
23
+ right in image space, and the y-axis points up in image space.
24
+
25
+ .. image:: /_static/camera_coords.png
26
+
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/examples/index.rst ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .. _guide:
2
+
3
+ User Guide
4
+ ==========
5
+
6
+ This section contains guides on how to use Pyrender to quickly visualize
7
+ your 3D data, including a quickstart guide and more detailed descriptions
8
+ of each part of the rendering pipeline.
9
+
10
+
11
+ .. toctree::
12
+ :maxdepth: 2
13
+
14
+ quickstart.rst
15
+ models.rst
16
+ lighting.rst
17
+ cameras.rst
18
+ scenes.rst
19
+ offscreen.rst
20
+ viewer.rst
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/examples/lighting.rst ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .. _lighting_guide:
2
+
3
+ Creating Lights
4
+ ===============
5
+
6
+ Pyrender supports three types of punctual light:
7
+
8
+ - :class:`.PointLight`: Point-based light sources, such as light bulbs.
9
+ - :class:`.SpotLight`: A conical light source, like a flashlight.
10
+ - :class:`.DirectionalLight`: A general light that does not attenuate with
11
+ distance.
12
+
13
+ Creating lights is easy -- just specify their basic attributes:
14
+
15
+ >>> pl = pyrender.PointLight(color=[1.0, 1.0, 1.0], intensity=2.0)
16
+ >>> sl = pyrender.SpotLight(color=[1.0, 1.0, 1.0], intensity=2.0,
17
+ ... innerConeAngle=0.05, outerConeAngle=0.5)
18
+ >>> dl = pyrender.DirectionalLight(color=[1.0, 1.0, 1.0], intensity=2.0)
19
+
20
+ For more information about how these lighting models are implemented,
21
+ see their class documentation.
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/examples/models.rst ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .. _model_guide:
2
+
3
+ Loading and Configuring Models
4
+ ==============================
5
+ The first step to any rendering application is loading your models.
6
+ Pyrender implements the GLTF 2.0 specification, which means that all
7
+ models are composed of a hierarchy of objects.
8
+
9
+ At the top level, we have a :class:`.Mesh`. The :class:`.Mesh` is
10
+ basically a wrapper of any number of :class:`.Primitive` types,
11
+ which actually represent geometry that can be drawn to the screen.
12
+
13
+ Primitives are composed of a variety of parameters, including
14
+ vertex positions, vertex normals, color and texture information,
15
+ and triangle indices if smooth rendering is desired.
16
+ They can implement point clouds, triangular meshes, or lines
17
+ depending on how you configure their data and set their
18
+ :attr:`.Primitive.mode` parameter.
19
+
20
+ Although you can create primitives yourself if you want to,
21
+ it's probably easier to just use the utility functions provided
22
+ in the :class:`.Mesh` class.
23
+
24
+ Creating Triangular Meshes
25
+ --------------------------
26
+
27
+ Simple Construction
28
+ ~~~~~~~~~~~~~~~~~~~
29
+ Pyrender allows you to create a :class:`.Mesh` containing a
30
+ triangular mesh model directly from a :class:`~trimesh.base.Trimesh` object
31
+ using the :meth:`.Mesh.from_trimesh` static method.
32
+
33
+ >>> import trimesh
34
+ >>> import pyrender
35
+ >>> import numpy as np
36
+ >>> tm = trimesh.load('examples/models/fuze.obj')
37
+ >>> m = pyrender.Mesh.from_trimesh(tm)
38
+ >>> m.primitives
39
+ [<pyrender.primitive.Primitive at 0x7fbb0af60e50>]
40
+
41
+ You can also create a single :class:`.Mesh` from a list of
42
+ :class:`~trimesh.base.Trimesh` objects:
43
+
44
+ >>> tms = [trimesh.creation.icosahedron(), trimesh.creation.cylinder()]
45
+ >>> m = pyrender.Mesh.from_trimesh(tms)
46
+ [<pyrender.primitive.Primitive at 0x7fbb0c2b74d0>,
47
+ <pyrender.primitive.Primitive at 0x7fbb0c2b7550>]
48
+
49
+ Vertex Smoothing
50
+ ~~~~~~~~~~~~~~~~
51
+
52
+ The :meth:`.Mesh.from_trimesh` method has a few additional optional parameters.
53
+ If you want to render the mesh without interpolating face normals, which can
54
+ be useful for meshes that are supposed to be angular (e.g. a cube), you
55
+ can specify ``smooth=False``.
56
+
57
+ >>> m = pyrender.Mesh.from_trimesh(tm, smooth=False)
58
+
59
+ Per-Face or Per-Vertex Coloration
60
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
61
+
62
+ If you have an untextured trimesh, you can color it in with per-face or
63
+ per-vertex colors:
64
+
65
+ >>> tm.visual.vertex_colors = np.random.uniform(size=tm.vertices.shape)
66
+ >>> tm.visual.face_colors = np.random.uniform(size=tm.faces.shape)
67
+ >>> m = pyrender.Mesh.from_trimesh(tm)
68
+
69
+ Instancing
70
+ ~~~~~~~~~~
71
+
72
+ If you want to render many copies of the same mesh at different poses,
73
+ you can statically create a vast array of them in an efficient manner.
74
+ Simply specify the ``poses`` parameter to be a list of ``N`` 4x4 homogenous
75
+ transformation matrics that position the meshes relative to their common
76
+ base frame:
77
+
78
+ >>> tfs = np.tile(np.eye(4), (3,1,1))
79
+ >>> tfs[1,:3,3] = [0.1, 0.0, 0.0]
80
+ >>> tfs[2,:3,3] = [0.2, 0.0, 0.0]
81
+ >>> tfs
82
+ array([[[1. , 0. , 0. , 0. ],
83
+ [0. , 1. , 0. , 0. ],
84
+ [0. , 0. , 1. , 0. ],
85
+ [0. , 0. , 0. , 1. ]],
86
+ [[1. , 0. , 0. , 0.1],
87
+ [0. , 1. , 0. , 0. ],
88
+ [0. , 0. , 1. , 0. ],
89
+ [0. , 0. , 0. , 1. ]],
90
+ [[1. , 0. , 0. , 0.2],
91
+ [0. , 1. , 0. , 0. ],
92
+ [0. , 0. , 1. , 0. ],
93
+ [0. , 0. , 0. , 1. ]]])
94
+
95
+ >>> m = pyrender.Mesh.from_trimesh(tm, poses=tfs)
96
+
97
+ Custom Materials
98
+ ~~~~~~~~~~~~~~~~
99
+
100
+ You can also specify a custom material for any triangular mesh you create
101
+ in the ``material`` parameter of :meth:`.Mesh.from_trimesh`.
102
+ The main material supported by Pyrender is the
103
+ :class:`.MetallicRoughnessMaterial`.
104
+ The metallic-roughness model supports rendering highly-realistic objects across
105
+ a wide gamut of materials.
106
+
107
+ For more information, see the documentation of the
108
+ :class:`.MetallicRoughnessMaterial` constructor or look at the Khronos_
109
+ documentation for more information.
110
+
111
+ .. _Khronos: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materials
112
+
113
+ Creating Point Clouds
114
+ ---------------------
115
+
116
+ Point Sprites
117
+ ~~~~~~~~~~~~~
118
+ Pyrender also allows you to create a :class:`.Mesh` containing a
119
+ point cloud directly from :class:`numpy.ndarray` instances
120
+ using the :meth:`.Mesh.from_points` static method.
121
+
122
+ Simply provide a list of points and optional per-point colors and normals.
123
+
124
+ >>> pts = tm.vertices.copy()
125
+ >>> colors = np.random.uniform(size=pts.shape)
126
+ >>> m = pyrender.Mesh.from_points(pts, colors=colors)
127
+
128
+ Point clouds created in this way will be rendered as square point sprites.
129
+
130
+ .. image:: /_static/points.png
131
+
132
+ Point Spheres
133
+ ~~~~~~~~~~~~~
134
+ If you have a monochromatic point cloud and would like to render it with
135
+ spheres, you can render it by instancing a spherical trimesh:
136
+
137
+ >>> sm = trimesh.creation.uv_sphere(radius=0.1)
138
+ >>> sm.visual.vertex_colors = [1.0, 0.0, 0.0]
139
+ >>> tfs = np.tile(np.eye(4), (len(pts), 1, 1))
140
+ >>> tfs[:,:3,3] = pts
141
+ >>> m = pyrender.Mesh.from_trimesh(sm, poses=tfs)
142
+
143
+ .. image:: /_static/points2.png
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/examples/offscreen.rst ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .. _offscreen_guide:
2
+
3
+ Offscreen Rendering
4
+ ===================
5
+
6
+ .. note::
7
+ If you're using a headless server, you'll need to use either EGL (for
8
+ GPU-accelerated rendering) or OSMesa (for CPU-only software rendering).
9
+ If you're using OSMesa, be sure that you've installed it properly. See
10
+ :ref:`osmesa` for details.
11
+
12
+ Choosing a Backend
13
+ ------------------
14
+
15
+ Once you have a scene set up with its geometry, cameras, and lights,
16
+ you can render it using the :class:`.OffscreenRenderer`. Pyrender supports
17
+ three backends for offscreen rendering:
18
+
19
+ - Pyglet, the same engine that runs the viewer. This requires an active
20
+ display manager, so you can't run it on a headless server. This is the
21
+ default option.
22
+ - OSMesa, a software renderer.
23
+ - EGL, which allows for GPU-accelerated rendering without a display manager.
24
+
25
+ If you want to use OSMesa or EGL, you need to set the ``PYOPENGL_PLATFORM``
26
+ environment variable before importing pyrender or any other OpenGL library.
27
+ You can do this at the command line:
28
+
29
+ .. code-block:: bash
30
+
31
+ PYOPENGL_PLATFORM=osmesa python render.py
32
+
33
+ or at the top of your Python script:
34
+
35
+ .. code-block:: bash
36
+
37
+ # Top of main python script
38
+ import os
39
+ os.environ['PYOPENGL_PLATFORM'] = 'egl'
40
+
41
+ The handle for EGL is ``egl``, and the handle for OSMesa is ``osmesa``.
42
+
43
+ Running the Renderer
44
+ --------------------
45
+
46
+ Once you've set your environment variable appropriately, create your scene and
47
+ then configure the :class:`.OffscreenRenderer` object with a window width,
48
+ a window height, and a size for point-cloud points:
49
+
50
+ >>> r = pyrender.OffscreenRenderer(viewport_width=640,
51
+ ... viewport_height=480,
52
+ ... point_size=1.0)
53
+
54
+ Then, just call the :meth:`.OffscreenRenderer.render` function:
55
+
56
+ >>> color, depth = r.render(scene)
57
+
58
+ .. image:: /_static/scene.png
59
+
60
+ This will return a ``(w,h,3)`` channel floating-point color image and
61
+ a ``(w,h)`` floating-point depth image rendered from the scene's main camera.
62
+
63
+ You can customize the rendering process by using flag options from
64
+ :class:`.RenderFlags` and bitwise or-ing them together. For example,
65
+ the following code renders a color image with an alpha channel
66
+ and enables shadow mapping for all directional lights:
67
+
68
+ >>> flags = RenderFlags.RGBA | RenderFlags.SHADOWS_DIRECTIONAL
69
+ >>> color, depth = r.render(scene, flags=flags)
70
+
71
+ Once you're done with the offscreen renderer, you need to close it before you
72
+ can run a different renderer or open the viewer for the same scene:
73
+
74
+ >>> r.delete()
75
+
76
+ Google CoLab Examples
77
+ ---------------------
78
+
79
+ For a minimal working example of offscreen rendering using OSMesa,
80
+ see the `OSMesa Google CoLab notebook`_.
81
+
82
+ .. _OSMesa Google CoLab notebook: https://colab.research.google.com/drive/1Z71mHIc-Sqval92nK290vAsHZRUkCjUx
83
+
84
+ For a minimal working example of offscreen rendering using EGL,
85
+ see the `EGL Google CoLab notebook`_.
86
+
87
+ .. _EGL Google CoLab notebook: https://colab.research.google.com/drive/1rTLHk0qxh4dn8KNe-mCnN8HAWdd2_BEh
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/docs/source/index.rst ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .. core documentation master file, created by
2
+ sphinx-quickstart on Sun Oct 16 14:33:48 2016.
3
+ You can adapt this file completely to your liking, but it should at least
4
+ contain the root `toctree` directive.
5
+
6
+ Pyrender Documentation
7
+ ========================
8
+ Pyrender is a pure Python (2.7, 3.4, 3.5, 3.6) library for physically-based
9
+ rendering and visualization.
10
+ It is designed to meet the glTF 2.0 specification_ from Khronos
11
+
12
+ .. _specification: https://www.khronos.org/gltf/
13
+
14
+ Pyrender is lightweight, easy to install, and simple to use.
15
+ It comes packaged with both an intuitive scene viewer and a headache-free
16
+ offscreen renderer with support for GPU-accelerated rendering on headless
17
+ servers, which makes it perfect for machine learning applications.
18
+ Check out the :ref:`guide` for a full tutorial, or fork me on
19
+ Github_.
20
+
21
+ .. _Github: https://github.com/mmatl/pyrender
22
+
23
+ .. image:: _static/rotation.gif
24
+
25
+ .. image:: _static/damaged_helmet.png
26
+
27
+ .. toctree::
28
+ :maxdepth: 2
29
+
30
+ install/index.rst
31
+ examples/index.rst
32
+ api/index.rst
33
+
34
+
35
+ Indices and tables
36
+ ==================
37
+
38
+ * :ref:`genindex`
39
+ * :ref:`modindex`
40
+ * :ref:`search`
41
+
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ freetype-py
2
+ imageio
3
+ networkx
4
+ numpy
5
+ Pillow
6
+ pyglet==1.4.0a1
7
+ PyOpenGL
8
+ PyOpenGL_accelerate
9
+ six
10
+ trimesh
11
+ sphinx
12
+ sphinx_rtd_theme
13
+ sphinx-automodapi
14
+
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/pyrender/setup.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Setup of pyrender Python codebase.
3
+
4
+ Author: Matthew Matl
5
+ """
6
+ import sys
7
+ from setuptools import setup
8
+
9
+ # load __version__
10
+ exec(open('pyrender/version.py').read())
11
+
12
+ def get_imageio_dep():
13
+ if sys.version[0] == "2":
14
+ return 'imageio<=2.6.1'
15
+ return 'imageio'
16
+
17
+ requirements = [
18
+ 'freetype-py', # For font loading
19
+ get_imageio_dep(), # For Image I/O
20
+ 'networkx', # For the scene graph
21
+ 'numpy', # Numpy
22
+ 'Pillow', # For Trimesh texture conversions
23
+ 'pyglet>=1.4.10', # For the pyglet viewer
24
+ 'PyOpenGL~=3.1.0', # For OpenGL
25
+ # 'PyOpenGL_accelerate~=3.1.0', # For OpenGL
26
+ 'scipy', # Because of trimesh missing dep
27
+ 'six', # For Python 2/3 interop
28
+ 'trimesh', # For meshes
29
+ ]
30
+
31
+ dev_requirements = [
32
+ 'flake8', # Code formatting checker
33
+ 'pre-commit', # Pre-commit hooks
34
+ 'pytest', # Code testing
35
+ 'pytest-cov', # Coverage testing
36
+ 'tox', # Automatic virtualenv testing
37
+ ]
38
+
39
+ docs_requirements = [
40
+ 'sphinx', # General doc library
41
+ 'sphinx_rtd_theme', # RTD theme for sphinx
42
+ 'sphinx-automodapi' # For generating nice tables
43
+ ]
44
+
45
+
46
+ setup(
47
+ name = 'pyrender',
48
+ version=__version__,
49
+ description='Easy-to-use Python renderer for 3D visualization',
50
+ long_description='A simple implementation of Physically-Based Rendering '
51
+ '(PBR) in Python. Compliant with the glTF 2.0 standard.',
52
+ author='Matthew Matl',
53
+ author_email='matthewcmatl@gmail.com',
54
+ license='MIT License',
55
+ url = 'https://github.com/mmatl/pyrender',
56
+ classifiers = [
57
+ 'Development Status :: 4 - Beta',
58
+ 'License :: OSI Approved :: MIT License',
59
+ 'Operating System :: POSIX :: Linux',
60
+ 'Operating System :: MacOS :: MacOS X',
61
+ 'Programming Language :: Python :: 2.7',
62
+ 'Programming Language :: Python :: 3.5',
63
+ 'Programming Language :: Python :: 3.6',
64
+ 'Natural Language :: English',
65
+ 'Topic :: Scientific/Engineering'
66
+ ],
67
+ keywords = 'rendering graphics opengl 3d visualization pbr gltf',
68
+ packages = ['pyrender', 'pyrender.platforms'],
69
+ setup_requires = requirements,
70
+ install_requires = requirements,
71
+ extras_require={
72
+ 'dev': dev_requirements,
73
+ 'docs': docs_requirements,
74
+ },
75
+ include_package_data=True
76
+ )
c125d6fbf8bda65345b6edda6e04f79faf4d67cd/requirements.txt ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ git+https://github.com/openai/CLIP.git
2
+ numpy==1.23.3
3
+ matplotlib==3.4.3
4
+ matplotlib-inline==0.1.2
5
+ transformers
6
+ h5py
7
+ smplx
8
+ shapely
9
+ freetype-py
10
+ imageio
11
+ networkx
12
+ numpy
13
+ Pillow
14
+ pyglet==1.4.0a1
15
+ PyOpenGL==3.1.7
16
+ PyOpenGL_accelerate==3.1.7
17
+ six
18
+ trimesh
19
+ sphinx
20
+ sphinx_rtd_theme
21
+ sphinx-automodapi
22
+ mapbox_earcut
23
+ chumpy
24
+ gdown
25
+ MoviePy
26
+ ffmpeg
27
+ torch
checkpoints/kit/kit/Comp_v6_KLD005/opt.txt ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ------------ Options -------------
2
+ batch_size: 32
3
+ checkpoints_dir: ./checkpoints
4
+ dataset_name: kit
5
+ decomp_name: Decomp_SP001_SM001_H512
6
+ dim_att_vec: 512
7
+ dim_dec_hidden: 1024
8
+ dim_movement2_dec_hidden: 512
9
+ dim_movement_dec_hidden: 512
10
+ dim_movement_enc_hidden: 512
11
+ dim_movement_latent: 512
12
+ dim_msd_hidden: 512
13
+ dim_pos_hidden: 1024
14
+ dim_pri_hidden: 1024
15
+ dim_seq_de_hidden: 512
16
+ dim_seq_en_hidden: 512
17
+ dim_text_hidden: 512
18
+ dim_z: 128
19
+ early_stop_count: 3
20
+ estimator_mod: bigru
21
+ eval_every_e: 5
22
+ feat_bias: 5
23
+ fixed_steps: 5
24
+ gpu_id: 2
25
+ input_z: False
26
+ is_continue: True
27
+ is_train: True
28
+ lambda_fake: 10
29
+ lambda_gan_l: 0.1
30
+ lambda_gan_mt: 0.1
31
+ lambda_gan_mv: 0.1
32
+ lambda_kld: 0.005
33
+ lambda_rec: 1
34
+ lambda_rec_init: 1
35
+ lambda_rec_mot: 1
36
+ lambda_rec_mov: 1
37
+ log_every: 50
38
+ lr: 0.0002
39
+ max_sub_epoch: 50
40
+ max_text_len: 20
41
+ n_layers_dec: 1
42
+ n_layers_msd: 2
43
+ n_layers_pos: 1
44
+ n_layers_pri: 1
45
+ n_layers_seq_de: 2
46
+ n_layers_seq_en: 1
47
+ name: Comp_v6_KLD005
48
+ num_experts: 4
49
+ save_every_e: 10
50
+ save_latest: 500
51
+ text_enc_mod: bigru
52
+ tf_ratio: 0.4
53
+ unit_length: 4
54
+ -------------- End ----------------
checkpoints/kit/kit/text_mot_match/eval/E005.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Positive Pairs Distance
2
+ 3.134 2.099 3.881 3.921 2.285 3.744 2.655 1.721 1.946 2.250 2.924 6.876 3.502 1.861 5.818 3.507 8.488 1.692 1.776 4.583 1.980 2.727 3.955 3.607 5.916 3.186 3.832 1.700 1.664 2.896 3.318 2.128
3
+ Negative Pairs Distance
4
+ 4.801 7.064 6.329 6.437 3.465 6.363 8.897 6.655 10.889 6.358 8.022 8.131 3.472 9.457 10.489 3.636 9.595 9.930 12.090 6.514 10.054 2.828 11.206 9.073 6.163 10.645 7.251 7.684 13.491 3.869 8.233 5.459
checkpoints/kit/kit/text_mot_match/eval/E010.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Positive Pairs Distance
2
+ 1.908 2.165 2.165 3.126 1.697 1.459 2.442 1.858 1.139 1.622 2.096 2.478 4.929 3.777 4.985 2.417 1.533 2.688 4.114 2.632 3.061 2.188 5.152 2.518 3.600 4.669 8.488 2.839 3.971 2.343 3.527 3.871
3
+ Negative Pairs Distance
4
+ 11.756 2.332 11.629 8.415 1.482 5.168 9.379 10.146 11.044 11.025 11.965 5.885 10.289 5.902 8.258 11.976 8.073 7.024 9.437 4.496 3.879 7.686 4.651 4.576 2.901 14.143 2.428 8.259 5.828 7.087 12.836 13.889
checkpoints/kit/kit/text_mot_match/eval/E015.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Positive Pairs Distance
2
+ 3.850 4.731 5.109 2.265 1.610 2.926 2.168 2.637 2.084 1.510 2.175 2.338 1.857 5.098 1.801 2.207 2.303 1.409 2.606 1.605 2.917 1.752 3.372 2.717 3.066 2.843 2.329 2.640 2.341 4.156 3.331 8.131
3
+ Negative Pairs Distance
4
+ 6.084 8.782 9.299 5.081 10.574 12.375 6.629 3.773 12.802 17.637 15.346 12.001 11.877 8.885 5.704 7.574 10.524 11.066 13.124 9.736 2.497 16.383 10.255 14.209 15.128 12.731 10.557 15.367 11.058 11.331 2.683 9.325
checkpoints/kit/kit/text_mot_match/eval/E020.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Positive Pairs Distance
2
+ 1.720 2.590 1.074 3.083 2.166 2.835 6.362 2.816 2.871 1.793 3.421 6.261 1.957 5.514 2.695 2.254 1.668 1.689 4.970 2.880 1.581 4.509 2.255 3.921 2.240 2.384 2.844 2.736 4.322 3.335 3.728 2.677
3
+ Negative Pairs Distance
4
+ 11.181 11.564 13.729 7.366 12.419 12.882 8.641 18.567 7.485 7.284 11.086 8.577 5.952 4.970 14.443 13.611 11.813 10.937 13.638 11.140 14.285 8.947 13.830 14.733 11.218 3.280 2.429 11.807 11.222 9.967 10.158 10.779
checkpoints/kit/kit/text_mot_match/eval/E025.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Positive Pairs Distance
2
+ 3.553 1.793 2.145 1.160 1.568 0.923 2.591 7.707 2.747 12.233 5.216 1.305 1.507 2.035 1.736 2.155 1.751 1.618 2.041 2.239 2.825 2.352 3.072 2.020 1.761 5.428 2.252 1.604 2.319 2.266 3.278 3.328
3
+ Negative Pairs Distance
4
+ 11.462 3.411 1.404 11.581 3.764 11.409 14.073 4.259 12.997 3.549 7.593 12.030 12.991 7.647 12.337 12.592 14.496 14.496 13.530 13.371 12.775 14.828 11.200 17.627 9.128 9.617 9.297 6.782 14.615 2.304 9.306 10.946
checkpoints/kit/kit/text_mot_match/eval/E030.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Positive Pairs Distance
2
+ 7.378 4.702 10.228 2.154 7.611 0.943 1.770 1.255 5.552 3.161 2.180 2.252 3.278 1.767 1.787 1.450 1.546 2.051 1.476 1.828 1.829 1.423 1.150 2.198 9.395 1.748 2.700 2.304 3.917 4.163 2.811 2.562
3
+ Negative Pairs Distance
4
+ 3.884 11.919 5.835 6.898 5.753 19.333 10.732 16.049 10.197 11.546 13.682 12.106 12.993 11.981 13.373 13.464 11.788 11.267 16.719 9.747 4.581 14.785 13.978 9.505 7.465 11.392 11.481 9.757 11.077 16.272 15.701 12.256
checkpoints/kit/kit/text_mot_match/eval/E035.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Positive Pairs Distance
2
+ 2.095 9.020 2.176 1.030 1.653 1.306 1.963 4.513 1.906 1.186 2.731 1.678 1.395 2.232 1.394 4.946 1.057 4.450 3.671 2.931 3.655 1.374 1.361 6.001 5.699 1.579 10.237 2.940 1.622 2.032 7.194 1.069
3
+ Negative Pairs Distance
4
+ 13.345 14.638 14.061 19.142 8.843 12.152 15.600 7.368 15.635 13.863 15.644 3.686 13.388 15.807 20.432 11.571 13.876 8.513 13.236 19.330 8.771 14.880 13.005 10.810 12.430 10.102 4.440 18.083 3.135 13.201 5.465 8.700
checkpoints/kit/kit/text_mot_match/eval/E040.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Positive Pairs Distance
2
+ 2.531 1.118 4.384 1.787 1.595 2.184 1.371 1.264 2.086 1.477 1.123 1.240 1.040 11.428 3.469 1.511 1.782 2.528 6.645 1.197 1.967 1.188 3.484 5.019 1.024 1.892 3.185 1.017 2.682 1.116 1.047 1.691
3
+ Negative Pairs Distance
4
+ 12.010 18.700 16.704 10.839 15.398 8.070 9.340 14.570 8.946 18.806 4.114 12.699 11.821 4.733 15.875 14.064 17.230 16.277 14.135 22.007 18.454 13.210 8.825 8.937 9.880 16.306 13.555 13.649 5.738 12.752 12.994 1.158
checkpoints/kit/kit/text_mot_match/eval/E045.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Positive Pairs Distance
2
+ 1.412 2.614 2.471 0.842 2.629 7.116 7.275 5.793 1.034 8.645 4.851 2.357 1.155 1.208 1.168 1.698 1.550 1.132 7.423 2.531 1.147 2.240 1.575 1.232 1.455 2.134 1.421 3.723 2.887 1.759 3.806 4.387
3
+ Negative Pairs Distance
4
+ 10.150 13.459 14.645 13.875 8.746 12.398 13.303 16.393 22.565 9.265 13.325 9.629 18.867 15.043 18.596 19.413 17.903 8.695 4.948 13.620 14.171 19.699 15.496 11.753 12.914 17.017 7.990 14.401 11.768 8.648 13.926 13.402
checkpoints/kit/kit/text_mot_match/eval/E050.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Positive Pairs Distance
2
+ 5.304 2.162 1.767 7.675 1.446 5.696 2.277 0.717 1.477 12.431 3.673 1.286 2.633 1.883 2.555 1.399 11.572 1.303 3.411 1.521 3.885 0.984 1.210 1.038 5.024 5.886 1.283 1.026 2.056 1.738 3.654 2.659
3
+ Negative Pairs Distance
4
+ 17.692 17.993 15.431 10.788 22.819 16.591 23.417 13.203 7.453 17.521 19.102 17.595 7.883 20.475 11.371 17.178 5.380 4.884 17.968 18.298 13.822 19.112 11.842 10.838 14.131 14.906 16.252 14.499 13.878 2.300 11.417 21.558