atnikos commited on
Commit
08db8da
·
1 Parent(s): 78c7556

fix first version

Browse files
app.py CHANGED
@@ -3,12 +3,15 @@ from geometry_utils import diffout2motion
3
  import gradio as gr
4
  import spaces
5
  import torch
6
- import random
7
  import os
8
  from pathlib import Path
9
  import smplx
10
  from body_renderer import get_render
11
- import joblib
 
 
 
 
12
  # import cv2
13
  # import moderngl
14
  # ctx = moderngl.create_context(standalone=True)
@@ -21,60 +24,7 @@ print(zero.device) # <-- 'cuda:0' 🤗
21
 
22
  DEFAULT_TEXT = "do it slower "
23
 
24
- def get_smpl_models():
25
- REPO_ID = 'athn-nik/smpl_models'
26
- from huggingface_hub import snapshot_download
27
- return snapshot_download(repo_id=REPO_ID, allow_patterns="smplh*",
28
- token=access_token_smpl)
29
-
30
- WEBSITE = ("""<div class="embed_hidden" style="text-align: center;">
31
- <h1>MotionFix: Text-Driven 3D Human Motion Editing</h1>
32
- <h3>
33
- <a href="https://is.mpg.de/person/~nathanasiou" target="_blank" rel="noopener noreferrer">Nikos Athanasiou</a><sup>1</sup>,
34
- <a href="https://is.mpg.de/person/acseke" target="_blank" rel="noopener noreferrer">Alpar Cseke</a><sup>1</sup>,
35
- <br>
36
- <a href="https://ps.is.mpg.de/person/mdiomataris" target="_blank" rel="noopener noreferrer">Markos Diomataris</a><sup>1, 3</sup>,
37
- <a href="https://is.mpg.de/person/black" target="_blank" rel="noopener noreferrer">Michael J. Black</a><sup>1</sup>,
38
- <a href="https://imagine.enpc.fr/~varolg/" target="_blank" rel="noopener noreferrer">G&uuml;l Varol</a><sup>2</sup>
39
- </h3>
40
- <h3>
41
- <sup>1</sup>Max Planck Institute for Intelligent Systems, T&uuml;bingen, Germany;
42
- <sup>2</sup>LIGM, &Eacute;cole des Ponts, Univ Gustave Eiffel, CNRS, France,
43
- <sup>3</sup>ETH Z&uuml;rich, Switzerland
44
- </h3>
45
- </div>
46
- <div style="display:flex; gap: 0.3rem; justify-content: center; align-items: center;" align="center">
47
- <a href='https://arxiv.org/pdf/2408.00712'><img src='https://img.shields.io/badge/Arxiv-2405.20340-A42C25?style=flat&logo=arXiv&logoColor=A42C25'></a>
48
- <a href='https://motionfix.is.tue.mpg.de'><img src='https://img.shields.io/badge/Project-Page-%23df5b46?style=flat&logo=Google%20chrome&logoColor=%23df5b46'></a>
49
- <a href='https://www.youtube.com/watch?v=cFa6V6Ua-TY'><img src='https://img.shields.io/badge/YouTube-red?style=flat&logo=youtube&logoColor=white'></a>
50
- </div>
51
- """)
52
-
53
- CREDITS=("""<div class="embed_hidden" style="text-align: center;">
54
- <h3>
55
- The renderer of this demo is adapted from the render of
56
- <a href="https://geometry.stanford.edu/projects/humor/" target="_blank" rel="noopener noreferrer">HuMoR</a>
57
- with the help of <a href="https://ps.is.mpg.de/person/trakshit" target="_blank" rel="noopener noreferrer">Tithi Rakshit</a> :)
58
- </h3>
59
- """)
60
-
61
- WEB_source = ("""<div class="embed_hidden" style="text-align: center;">
62
- <h1>Pick a motion to edit!</h1>
63
- <h3>
64
- Here you should pick a source motion
65
- <hr class="double">
66
- </h3>
67
- </div>
68
- """)
69
-
70
- WEB_target = ("""<div class="embed_hidden" style="text-align: center;">
71
- <h1>Now type the text to edit that motion!</h1>
72
- <h3>
73
- Here you should get the generated motion!
74
- <hr class="double">
75
- </h3>
76
- </div>
77
- """)
78
  @spaces.GPU
79
  def greet(n):
80
  print(zero.device) # <-- 'cuda:0' 🤗
@@ -100,16 +50,17 @@ def show_video(input_text, key_to_use):
100
  # ds_sample = joblib.load(motion_to_edit)
101
  ds_sample = MFIX_DATASET_DICT[key_to_use]
102
  from feature_extractor import FEAT_GET_METHODS
103
- data_dict_source = {f'{feat}_source': FEAT_GET_METHODS[feat](ds_sample['motion_source'])
104
  for feat in infeats}
105
- data_dict_target = {f'{feat}_target': FEAT_GET_METHODS[feat](ds_sample['motion_target'])
106
  for feat in infeats}
107
  full_batch = data_dict_source | data_dict_target
108
- import ipdb; ipdb.set_trace()
109
  in_batch = normalizer.norm_and_cat(full_batch, infeats)
110
- source_motion_norm = ds_sample['source_feats_norm'].to('cuda')
111
- seqlen_tgt = ds_sample['target_feats_norm'].shape[0]
112
- seqlen_src = ds_sample['source_feats_norm'].shape[0]
 
 
113
  # import ipdb; ipdb.set_trace()
114
  checkpoint = {k.replace('denoiser.', ''): v for k, v in checkpoint.items()}
115
  tmed_denoiser = TMED_denoiser().to('cuda')
@@ -128,8 +79,8 @@ def show_video(input_text, key_to_use):
128
  texts_cond = ['']*no_of_texts + texts_cond
129
  texts_cond = ['']*no_of_texts + texts_cond
130
  text_emb, text_mask = text_encoder(texts_cond)
131
-
132
- cond_emb_motion = source_motion_norm.unsqueeze(0).permute(1, 0, 2)
133
  cond_motion_mask = torch.ones((bsz, seqlen_src),
134
  dtype=bool, device='cuda')
135
  mask_target = torch.ones((bsz, seqlen_tgt),
@@ -145,7 +96,9 @@ def show_video(input_text, key_to_use):
145
  gd_text=2.0,
146
  gd_motion=2.0,
147
  steps_num=300)
148
- edited_motion = diffout2motion(diff_out, normalizer).squeeze()
 
 
149
  # import ipdb; ipdb.set_trace()
150
  # aitrenderer = get_renderer()
151
  # SMPL_LAYER = SMPLLayer(model_type='smplh', ext='npz', gender='neutral')
@@ -158,26 +111,43 @@ def show_video(input_text, key_to_use):
158
  gender='neutral',ext='npz')
159
 
160
  # run_smpl_fwd_verticesbody_model, body_transl, body_orient, body_pose,
161
- import random
162
- xx = random.randint(1, 1000)
163
  # edited_mot_to_render
164
  from body_renderer import get_render
165
  from transform3d import transform_body_pose
 
166
  edited_motion_aa = transform_body_pose(edited_motion[:, 3:],
167
  '6d->aa')
 
 
 
168
  if os.path.exists('./output_movie.mp4'):
169
  os.remove('./output_movie.mp4')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  fname = get_render(body_model,
171
- [edited_motion[..., :3].detach().cpu()],
172
- [edited_motion_aa[..., :3].detach().cpu()],
173
- [edited_motion_aa[..., 3:].detach().cpu()],
174
  output_path='./output_movie.mp4',
175
- text='', colors=['sky blue'])
176
-
177
- # import ipdb; ipdb.set_trace()
178
-
179
 
180
-
181
  # fname = render_motion(AIT_RENDERER, [edited_mot_to_render],
182
  # f"movie_example--{str(xx)}",
183
  # pose_repr='aa',
@@ -187,57 +157,6 @@ def show_video(input_text, key_to_use):
187
  print(os.path.abspath(fname))
188
  return fname
189
 
190
- from huggingface_hub import hf_hub_download
191
-
192
- def download_models():
193
- REPO_ID = 'athn-nik/example-model'
194
- return hf_hub_download(REPO_ID, filename="tmed_compressed.ckpt")
195
-
196
- def download_model_config():
197
- REPO_ID = 'athn-nik/example-model'
198
- path_to_config = hf_hub_download(REPO_ID, filename="tmed/.hydra/config.yaml")
199
- from omegaconf import OmegaConf
200
- model_cfg = OmegaConf.to_yaml(path_to_config)
201
- return model_cfg.model.input_feats
202
-
203
-
204
- def download_motion_from_dataset(key_to_dl):
205
- REPO_ID = 'athn-nik/example-model'
206
- from huggingface_hub import snapshot_download
207
- keytodl = key_to_dl
208
- keytodl = '000008'
209
- path_for_ds = snapshot_download(repo_id=REPO_ID,
210
- allow_patterns=f"dataset_inputs/{keytodl}",
211
- token=access_token_smpl)
212
- path_for_ds_sample = path_for_ds + f'/dataset_inputs/{keytodl}.pth.tar'
213
- return path_for_ds_sample
214
-
215
- def download_tmr():
216
- REPO_ID = 'athn-nik/example-model'
217
- # return hf_hub_download(REPO_ID, filename="min_checkpoint.ckpt")
218
- from huggingface_hub import snapshot_download
219
- return snapshot_download(repo_id=REPO_ID, allow_patterns="tmr*",
220
- token=access_token_smpl)
221
-
222
- def download_motionfix():
223
- REPO_ID = 'athn-nik/example-model'
224
- # return hf_hub_download(REPO_ID, filename="min_checkpoint.ckpt")
225
- from huggingface_hub import snapshot_download
226
- return snapshot_download(repo_id=REPO_ID, allow_patterns="motionfix*",
227
- token=access_token_smpl)
228
-
229
- def download_motionfix_dataset():
230
- REPO_ID = 'athn-nik/example-model'
231
- dataset_downloaded_path = hf_hub_download(REPO_ID, filename="motionfix.pth.tar")
232
- dataset_dict = joblib.load(dataset_downloaded_path)
233
- return dataset_dict
234
-
235
- def download_embeddings():
236
- REPO_ID = 'athn-nik/example-model'
237
- # return hf_hub_download(REPO_ID, filename="min_checkpoint.ckpt")
238
- from huggingface_hub import snapshot_download
239
- return snapshot_download(repo_id=REPO_ID, allow_patterns="embeddings*",
240
- token=access_token_smpl)
241
 
242
 
243
  MFIX_p = download_motionfix() + '/motionfix'
 
3
  import gradio as gr
4
  import spaces
5
  import torch
 
6
  import os
7
  from pathlib import Path
8
  import smplx
9
  from body_renderer import get_render
10
+ import numpy as np
11
+ from download_deps import get_smpl_models, download_models, download_model_config
12
+ from download_deps import download_tmr, download_motionfix, download_motionfix_dataset
13
+ from download_deps import download_embeddings
14
+ from website import CREDITS, WEB_source, WEB_target, WEBSITE
15
  # import cv2
16
  # import moderngl
17
  # ctx = moderngl.create_context(standalone=True)
 
24
 
25
  DEFAULT_TEXT = "do it slower "
26
 
27
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  @spaces.GPU
29
  def greet(n):
30
  print(zero.device) # <-- 'cuda:0' 🤗
 
50
  # ds_sample = joblib.load(motion_to_edit)
51
  ds_sample = MFIX_DATASET_DICT[key_to_use]
52
  from feature_extractor import FEAT_GET_METHODS
53
+ data_dict_source = {f'{feat}_source': FEAT_GET_METHODS[feat](ds_sample['motion_source'])[None].to('cuda')
54
  for feat in infeats}
55
+ data_dict_target = {f'{feat}_target': FEAT_GET_METHODS[feat](ds_sample['motion_target'])[None].to('cuda')
56
  for feat in infeats}
57
  full_batch = data_dict_source | data_dict_target
 
58
  in_batch = normalizer.norm_and_cat(full_batch, infeats)
59
+ source_motion_norm = in_batch['source']
60
+ target_motion_norm = in_batch['target']
61
+
62
+ seqlen_tgt = source_motion_norm.shape[0]
63
+ seqlen_src = target_motion_norm.shape[0]
64
  # import ipdb; ipdb.set_trace()
65
  checkpoint = {k.replace('denoiser.', ''): v for k, v in checkpoint.items()}
66
  tmed_denoiser = TMED_denoiser().to('cuda')
 
79
  texts_cond = ['']*no_of_texts + texts_cond
80
  texts_cond = ['']*no_of_texts + texts_cond
81
  text_emb, text_mask = text_encoder(texts_cond)
82
+
83
+ cond_emb_motion = source_motion_norm
84
  cond_motion_mask = torch.ones((bsz, seqlen_src),
85
  dtype=bool, device='cuda')
86
  mask_target = torch.ones((bsz, seqlen_tgt),
 
96
  gd_text=2.0,
97
  gd_motion=2.0,
98
  steps_num=300)
99
+ edited_motion = diffout2motion(diff_out.permute(1,0,2), normalizer).squeeze()
100
+ gt_source = diffout2motion(source_motion_norm.permute(1,0,2),
101
+ normalizer).squeeze()
102
  # import ipdb; ipdb.set_trace()
103
  # aitrenderer = get_renderer()
104
  # SMPL_LAYER = SMPLLayer(model_type='smplh', ext='npz', gender='neutral')
 
111
  gender='neutral',ext='npz')
112
 
113
  # run_smpl_fwd_verticesbody_model, body_transl, body_orient, body_pose,
 
 
114
  # edited_mot_to_render
115
  from body_renderer import get_render
116
  from transform3d import transform_body_pose
117
+ # import ipdb; ipdb.set_trace()
118
  edited_motion_aa = transform_body_pose(edited_motion[:, 3:],
119
  '6d->aa')
120
+ gt_source_aa = transform_body_pose(gt_source[:, 3:],
121
+ '6d->aa')
122
+
123
  if os.path.exists('./output_movie.mp4'):
124
  os.remove('./output_movie.mp4')
125
+ from transform3d import rotate_body_degrees
126
+ gen_motion_trans = edited_motion[..., :3].detach().cpu()
127
+ gen_motion_rots_aa = edited_motion_aa.detach().cpu()
128
+ source_motion_trans = gt_source[..., :3].detach().cpu()
129
+ source_motion_rots_aa = gt_source_aa.detach().cpu()
130
+
131
+ gen_rots_rotated, gen_trans_rotated = rotate_body_degrees(transform_body_pose(
132
+ gen_motion_rots_aa,
133
+ 'aa->rot'),
134
+ gen_motion_trans, offset=np.pi)
135
+ src_rots_rotated, src_trans_rotated = rotate_body_degrees(transform_body_pose(
136
+ source_motion_rots_aa,
137
+ 'aa->rot'),
138
+ source_motion_trans, offset=np.pi)
139
+
140
+ src_rots_rotated_aa = transform_body_pose(src_rots_rotated,
141
+ 'rot->aa')
142
+ gen_rots_rotated_aa = transform_body_pose(gen_rots_rotated,
143
+ 'rot->aa')
144
  fname = get_render(body_model,
145
+ [gen_trans_rotated, src_trans_rotated],
146
+ [gen_rots_rotated_aa[:, 0], src_rots_rotated_aa[:, 0]],
147
+ [gen_rots_rotated_aa[:, 1:], src_rots_rotated_aa[:, 1:]],
148
  output_path='./output_movie.mp4',
149
+ text='', colors=['sky blue', 'red'])
 
 
 
150
 
 
151
  # fname = render_motion(AIT_RENDERER, [edited_mot_to_render],
152
  # f"movie_example--{str(xx)}",
153
  # pose_repr='aa',
 
157
  print(os.path.abspath(fname))
158
  return fname
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
 
162
  MFIX_p = download_motionfix() + '/motionfix'
deps/{statistics_bodilex.npy → statistics_motionfix.npy} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:9a0be87962557d3149203eb4586f3e670c1bd7785765ad8cef9ed91f6277a2c2
3
  size 4826
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dee69fd95d6bda36218e81cf36671a3e61988a358afce8338e771bcd3f14cef1
3
  size 4826
download_deps.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import joblib
3
+ from huggingface_hub import hf_hub_download
4
+ access_token_smpl = os.environ.get('HF_SMPL_TOKEN')
5
+
6
+ def get_smpl_models():
7
+ REPO_ID = 'athn-nik/smpl_models'
8
+ from huggingface_hub import snapshot_download
9
+ return snapshot_download(repo_id=REPO_ID, allow_patterns="smplh*",
10
+ token=access_token_smpl)
11
+
12
+ def download_models():
13
+ REPO_ID = 'athn-nik/example-model'
14
+ return hf_hub_download(REPO_ID, filename="tmed_compressed.ckpt")
15
+
16
+ def download_model_config():
17
+ REPO_ID = 'athn-nik/example-model'
18
+ path_to_config = hf_hub_download(REPO_ID, filename="tmed/.hydra/config.yaml")
19
+ from omegaconf import OmegaConf
20
+ model_cfg = OmegaConf.load(path_to_config)
21
+ return model_cfg.model.input_feats
22
+
23
+
24
+ def download_motion_from_dataset(key_to_dl):
25
+ REPO_ID = 'athn-nik/example-model'
26
+ from huggingface_hub import snapshot_download
27
+ keytodl = key_to_dl
28
+ keytodl = '000008'
29
+ path_for_ds = snapshot_download(repo_id=REPO_ID,
30
+ allow_patterns=f"dataset_inputs/{keytodl}",
31
+ token=access_token_smpl)
32
+ path_for_ds_sample = path_for_ds + f'/dataset_inputs/{keytodl}.pth.tar'
33
+ return path_for_ds_sample
34
+
35
+ def download_tmr():
36
+ REPO_ID = 'athn-nik/example-model'
37
+ # return hf_hub_download(REPO_ID, filename="min_checkpoint.ckpt")
38
+ from huggingface_hub import snapshot_download
39
+ return snapshot_download(repo_id=REPO_ID, allow_patterns="tmr*",
40
+ token=access_token_smpl)
41
+
42
+ def download_motionfix():
43
+ REPO_ID = 'athn-nik/example-model'
44
+ # return hf_hub_download(REPO_ID, filename="min_checkpoint.ckpt")
45
+ from huggingface_hub import snapshot_download
46
+ return snapshot_download(repo_id=REPO_ID, allow_patterns="motionfix*",
47
+ token=access_token_smpl)
48
+
49
+ def download_motionfix_dataset():
50
+ REPO_ID = 'athn-nik/example-model'
51
+ dataset_downloaded_path = hf_hub_download(REPO_ID, filename="motionfix.pth.tar")
52
+ dataset_dict = joblib.load(dataset_downloaded_path)
53
+ return dataset_dict
54
+
55
+ def download_embeddings():
56
+ REPO_ID = 'athn-nik/example-model'
57
+ # return hf_hub_download(REPO_ID, filename="min_checkpoint.ckpt")
58
+ from huggingface_hub import snapshot_download
59
+ return snapshot_download(repo_id=REPO_ID, allow_patterns="embeddings*",
60
+ token=access_token_smpl)
normalization.py CHANGED
@@ -7,7 +7,7 @@ import torch
7
  import numpy as np
8
 
9
  class Normalizer:
10
- def __init__(self, statistics_path: str='deps/statistics_bodilex.npy', nfeats: int=207,
11
  input_feats: List[str] = ["body_transl_delta_pelv",
12
  "body_orient_xy",
13
  "z_orient_delta", "body_pose",
 
7
  import numpy as np
8
 
9
  class Normalizer:
10
+ def __init__(self, statistics_path: str='deps/statistics_motionfix.npy', nfeats: int=207,
11
  input_feats: List[str] = ["body_transl_delta_pelv",
12
  "body_orient_xy",
13
  "z_orient_delta", "body_pose",
renderer/humor_render_tools/mesh_viewer.py CHANGED
@@ -640,7 +640,7 @@ class MeshViewer(object):
640
 
641
  camera_pose = self.get_init_cam_pose()
642
  camera_pose[:3, 3] = camera_pose[:3, 3] + np.array(
643
- [coord_to_add_camera[0], coord_to_add_camera[1]+1.5, 0.5]
644
  )
645
  self.scene.set_pose(cam_node, camera_pose)
646
 
 
640
 
641
  camera_pose = self.get_init_cam_pose()
642
  camera_pose[:3, 3] = camera_pose[:3, 3] + np.array(
643
+ [coord_to_add_camera[0], coord_to_add_camera[1] + 1.5, 0.5]
644
  )
645
  self.scene.set_pose(cam_node, camera_pose)
646
 
transform3d.py CHANGED
@@ -48,12 +48,11 @@ def rotate_trans(trans, rotZ, inverse=False):
48
  return trans_local
49
 
50
 
51
- def rotate_body_canonic(rots, trans, offset=0.0):
52
 
53
- '''
54
  Rotate the whole body
55
- '''
56
-
57
  # rots, trans = data.rots.clone(), data.trans.clone()
58
  global_poses = rots[..., 0, :, :]
59
  global_euler = matrix_to_euler_angles(global_poses, "ZYX")
@@ -80,11 +79,6 @@ def rotate_body_canonic(rots, trans, offset=0.0):
80
  # return RotTransDatastruct(rots=rots, trans=trans)
81
  return rots, trans
82
 
83
-
84
-
85
-
86
-
87
-
88
  """
89
  The transformation matrices returned from the functions in this file assume
90
  the points on which the transformation will be applied are column vectors.
 
48
  return trans_local
49
 
50
 
51
+ def rotate_body_degrees(rots, trans, offset=0.0):
52
 
53
+ """
54
  Rotate the whole body
55
+ """
 
56
  # rots, trans = data.rots.clone(), data.trans.clone()
57
  global_poses = rots[..., 0, :, :]
58
  global_euler = matrix_to_euler_angles(global_poses, "ZYX")
 
79
  # return RotTransDatastruct(rots=rots, trans=trans)
80
  return rots, trans
81
 
 
 
 
 
 
82
  """
83
  The transformation matrices returned from the functions in this file assume
84
  the points on which the transformation will be applied are column vectors.
website.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ WEBSITE = ("""<div class="embed_hidden" style="text-align: center;">
3
+ <h1>MotionFix: Text-Driven 3D Human Motion Editing</h1>
4
+ <h3>
5
+ <a href="https://is.mpg.de/person/~nathanasiou" target="_blank" rel="noopener noreferrer">Nikos Athanasiou</a><sup>1</sup>,
6
+ <a href="https://is.mpg.de/person/acseke" target="_blank" rel="noopener noreferrer">Alpar Cseke</a><sup>1</sup>,
7
+ <br>
8
+ <a href="https://ps.is.mpg.de/person/mdiomataris" target="_blank" rel="noopener noreferrer">Markos Diomataris</a><sup>1, 3</sup>,
9
+ <a href="https://is.mpg.de/person/black" target="_blank" rel="noopener noreferrer">Michael J. Black</a><sup>1</sup>,
10
+ <a href="https://imagine.enpc.fr/~varolg/" target="_blank" rel="noopener noreferrer">G&uuml;l Varol</a><sup>2</sup>
11
+ </h3>
12
+ <h3>
13
+ <sup>1</sup>Max Planck Institute for Intelligent Systems, T&uuml;bingen, Germany;
14
+ <sup>2</sup>LIGM, &Eacute;cole des Ponts, Univ Gustave Eiffel, CNRS, France,
15
+ <sup>3</sup>ETH Z&uuml;rich, Switzerland
16
+ </h3>
17
+ </div>
18
+ <div style="display:flex; gap: 0.3rem; justify-content: center; align-items: center;" align="center">
19
+ <a href='https://arxiv.org/pdf/2408.00712'><img src='https://img.shields.io/badge/Arxiv-2405.20340-A42C25?style=flat&logo=arXiv&logoColor=A42C25'></a>
20
+ <a href='https://motionfix.is.tue.mpg.de'><img src='https://img.shields.io/badge/Project-Page-%23df5b46?style=flat&logo=Google%20chrome&logoColor=%23df5b46'></a>
21
+ <a href='https://www.youtube.com/watch?v=cFa6V6Ua-TY'><img src='https://img.shields.io/badge/YouTube-red?style=flat&logo=youtube&logoColor=white'></a>
22
+ </div>
23
+ """)
24
+
25
+ CREDITS=("""<div class="embed_hidden" style="text-align: center;">
26
+ <h3>
27
+ The renderer of this demo is adapted from the render of
28
+ <a href="https://geometry.stanford.edu/projects/humor/" target="_blank" rel="noopener noreferrer">HuMoR</a>
29
+ with the help of <a href="https://ps.is.mpg.de/person/trakshit" target="_blank" rel="noopener noreferrer">Tithi Rakshit</a> :)
30
+ </h3>
31
+ """)
32
+
33
+ WEB_source = ("""<div class="embed_hidden" style="text-align: center;">
34
+ <h1>Pick a motion to edit!</h1>
35
+ <h3>
36
+ Here you should pick a source motion
37
+ <hr class="double">
38
+ </h3>
39
+ </div>
40
+ """)
41
+
42
+ WEB_target = ("""<div class="embed_hidden" style="text-align: center;">
43
+ <h1>Now type the text to edit that motion!</h1>
44
+ <h3>
45
+ Here you should get the generated motion!
46
+ <hr class="double">
47
+ </h3>
48
+ </div>
49
+ """)