Commit ·
76e0a5c
1
Parent(s): 35447e1
fix mcs to glb conversion
Browse files- pipeline/mcs_export_cam.py +58 -25
- pipeline/pipeline.py +5 -7
- requirements.txt +2 -0
- scripts/fetch_smplx.sh +2 -1
- scripts/install.sh +0 -3
pipeline/mcs_export_cam.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
import json
|
| 2 |
import base64
|
| 3 |
from typing import List, Dict, Any, Union, Tuple
|
|
@@ -5,6 +6,15 @@ import numpy as np
|
|
| 5 |
import scipy as sp
|
| 6 |
from numpy.typing import NDArray
|
| 7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
def create_gltf_structure(num_frames: int) -> Dict[str, Any]:
|
| 9 |
"""Create the initial structure of the GLTF file.
|
| 10 |
|
|
@@ -79,6 +89,7 @@ def add_camera_intrinsics(
|
|
| 79 |
"aspectRatio": float(aspect_ratio)
|
| 80 |
}
|
| 81 |
|
|
|
|
| 82 |
def add_smpl_buffers_to_gltf(
|
| 83 |
gltf: Dict[str, Any],
|
| 84 |
smpl_buffers: List[bytes],
|
|
@@ -238,6 +249,7 @@ def add_camera_animation(
|
|
| 238 |
]
|
| 239 |
})
|
| 240 |
|
|
|
|
| 241 |
def write_gltf_to_file(gltf: Dict[str, Any], output_path: str) -> None:
|
| 242 |
"""Write the GLTF structure to a file.
|
| 243 |
|
|
@@ -248,6 +260,48 @@ def write_gltf_to_file(gltf: Dict[str, Any], output_path: str) -> None:
|
|
| 248 |
with open(output_path, 'w', encoding='utf-8') as f:
|
| 249 |
json.dump(gltf, f, indent=2)
|
| 250 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
def export_scene_with_camera(
|
| 252 |
smpl_buffers: List[bytes],
|
| 253 |
frame_presences: List[List[int]],
|
|
@@ -257,7 +311,8 @@ def export_scene_with_camera(
|
|
| 257 |
translations: NDArray[np.float32],
|
| 258 |
focal_length: float,
|
| 259 |
principal_point: Tuple[float, float],
|
| 260 |
-
frame_rate: float
|
|
|
|
| 261 |
) -> None:
|
| 262 |
"""Export the GLTF file with SMPL bodies and animated camera.
|
| 263 |
|
|
@@ -277,27 +332,5 @@ def export_scene_with_camera(
|
|
| 277 |
add_smpl_buffers_to_gltf(gltf, smpl_buffers, frame_presences)
|
| 278 |
add_camera_animation(gltf, rotation_matrices, translations, num_frames, frame_rate)
|
| 279 |
write_gltf_to_file(gltf, output_path)
|
| 280 |
-
print(f"
|
| 281 |
-
|
| 282 |
-
if __name__ == "__main__":
|
| 283 |
-
# Example usage
|
| 284 |
-
MFV_RUN_NAME = "dancing_on_beach"
|
| 285 |
-
SMPL_PATHS = [f"../mfv_with_cameras/{MFV_RUN_NAME}/{MFV_RUN_NAME}_sub-1.smpl"]
|
| 286 |
-
FRAME_RATE = np.load(SMPL_PATHS[0])["frameRate"]
|
| 287 |
-
FRAME_PRESENCES = [[0, 511]]
|
| 288 |
-
NUM_FRAMES = 511
|
| 289 |
-
camera_data = np.load(f"../mfv_with_cameras/{MFV_RUN_NAME}/camera.npz")
|
| 290 |
-
|
| 291 |
-
smpl_buffer_data = [open(path, 'rb').read() for path in SMPL_PATHS]
|
| 292 |
-
|
| 293 |
-
export_scene_with_camera(
|
| 294 |
-
smpl_buffer_data,
|
| 295 |
-
FRAME_PRESENCES,
|
| 296 |
-
NUM_FRAMES,
|
| 297 |
-
f"./data/mcs_w_camera/{MFV_RUN_NAME}.mcs",
|
| 298 |
-
camera_data["R"],
|
| 299 |
-
camera_data["T"],
|
| 300 |
-
camera_data["focal_length"],
|
| 301 |
-
camera_data["principal_point"],
|
| 302 |
-
FRAME_RATE
|
| 303 |
-
)
|
|
|
|
| 1 |
+
import os
|
| 2 |
import json
|
| 3 |
import base64
|
| 4 |
from typing import List, Dict, Any, Union, Tuple
|
|
|
|
| 6 |
import scipy as sp
|
| 7 |
from numpy.typing import NDArray
|
| 8 |
|
| 9 |
+
from gloss import ViewerDummy
|
| 10 |
+
|
| 11 |
+
from smpl_rs import SmplCache
|
| 12 |
+
from smpl_rs.codec import McsCodec, GltfCodec
|
| 13 |
+
from smpl_rs.plugins import SmplPlugin
|
| 14 |
+
from smpl_rs.types import SmplType, Gender, GltfCompatibilityMode
|
| 15 |
+
from smpl_rs.components import GlossInterop
|
| 16 |
+
|
| 17 |
+
|
| 18 |
def create_gltf_structure(num_frames: int) -> Dict[str, Any]:
|
| 19 |
"""Create the initial structure of the GLTF file.
|
| 20 |
|
|
|
|
| 89 |
"aspectRatio": float(aspect_ratio)
|
| 90 |
}
|
| 91 |
|
| 92 |
+
|
| 93 |
def add_smpl_buffers_to_gltf(
|
| 94 |
gltf: Dict[str, Any],
|
| 95 |
smpl_buffers: List[bytes],
|
|
|
|
| 249 |
]
|
| 250 |
})
|
| 251 |
|
| 252 |
+
|
| 253 |
def write_gltf_to_file(gltf: Dict[str, Any], output_path: str) -> None:
|
| 254 |
"""Write the GLTF structure to a file.
|
| 255 |
|
|
|
|
| 260 |
with open(output_path, 'w', encoding='utf-8') as f:
|
| 261 |
json.dump(gltf, f, indent=2)
|
| 262 |
|
| 263 |
+
|
| 264 |
+
def convert_mcs_to_gltf(mcs_path: str, gltf_path: str, smplx_path: str) -> None:
|
| 265 |
+
"""Convert an MCS file to a GLTF file.
|
| 266 |
+
|
| 267 |
+
Args:
|
| 268 |
+
mcs_path: Path to the MCS file.
|
| 269 |
+
gltf_path: Path to write the GLTF file.
|
| 270 |
+
"""
|
| 271 |
+
viewer = ViewerDummy()
|
| 272 |
+
|
| 273 |
+
mcs_codec = McsCodec.from_file(mcs_path)
|
| 274 |
+
|
| 275 |
+
print("\nInformation from the MCS file:")
|
| 276 |
+
print(f"Number of frames: {mcs_codec.num_frames}")
|
| 277 |
+
print(f"Number of bodies: {mcs_codec.num_bodies}")
|
| 278 |
+
print(f"Has camera: {mcs_codec.has_camera}")
|
| 279 |
+
print(f"Frame rate: {mcs_codec.frame_rate}")
|
| 280 |
+
|
| 281 |
+
entity_builders = mcs_codec.to_entity_builders()
|
| 282 |
+
|
| 283 |
+
for current_ent, builder in enumerate(entity_builders):
|
| 284 |
+
entity = viewer.get_or_create_entity(name=f"mcs_entity_{current_ent}")
|
| 285 |
+
entity.insert(builder)
|
| 286 |
+
interop = GlossInterop(with_uv=True)
|
| 287 |
+
entity.insert(interop)
|
| 288 |
+
|
| 289 |
+
smpl_models = SmplCache.default()
|
| 290 |
+
smpl_models.set_lazy_loading(SmplType.SmplX, Gender.Neutral, smplx_path)
|
| 291 |
+
|
| 292 |
+
viewer.add_resource(smpl_models)
|
| 293 |
+
viewer.insert_plugin(SmplPlugin(autorun=False))
|
| 294 |
+
viewer.run_manual_plugins()
|
| 295 |
+
|
| 296 |
+
# Create the writer and export as Glb
|
| 297 |
+
gltf_codec = GltfCodec.from_scene(viewer.get_scene().ptr_idx(), export_camera = True)
|
| 298 |
+
gltf_codec.save(gltf_path, GltfCompatibilityMode.Unreal)
|
| 299 |
+
print(f"glTF file exported to {os.path.abspath(gltf_path)}")
|
| 300 |
+
|
| 301 |
+
# here there is gltf and buffer0.bin data, how can I combine them into a single file?
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
|
| 305 |
def export_scene_with_camera(
|
| 306 |
smpl_buffers: List[bytes],
|
| 307 |
frame_presences: List[List[int]],
|
|
|
|
| 311 |
translations: NDArray[np.float32],
|
| 312 |
focal_length: float,
|
| 313 |
principal_point: Tuple[float, float],
|
| 314 |
+
frame_rate: float,
|
| 315 |
+
smplx_path: str
|
| 316 |
) -> None:
|
| 317 |
"""Export the GLTF file with SMPL bodies and animated camera.
|
| 318 |
|
|
|
|
| 332 |
add_smpl_buffers_to_gltf(gltf, smpl_buffers, frame_presences)
|
| 333 |
add_camera_animation(gltf, rotation_matrices, translations, num_frames, frame_rate)
|
| 334 |
write_gltf_to_file(gltf, output_path)
|
| 335 |
+
print(f"MCS file exported to {os.path.abspath(output_path)}")
|
| 336 |
+
convert_mcs_to_gltf(output_path, output_path.replace(".mcs", ".glb"), smplx_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pipeline/pipeline.py
CHANGED
|
@@ -395,13 +395,11 @@ class Pipeline:
|
|
| 395 |
focal_length=self.results['camera_world']['img_focal'],
|
| 396 |
principal_point=self.results['camera_world']['img_center'],
|
| 397 |
frame_rate=float(self.cfg.fps),
|
|
|
|
| 398 |
)
|
| 399 |
-
|
| 400 |
-
print(
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
shutil.copy(MCS_OUTPUT_PATH, f'{seq_folder}/world4d.glb')
|
| 404 |
-
print(f'GLB file saved to "{os.path.abspath(f"{seq_folder}/world4d.glb")}"')
|
| 405 |
-
print(f'You can import the "world4d.glb" file on Blender to view the result')
|
| 406 |
|
| 407 |
return self.results
|
|
|
|
| 395 |
focal_length=self.results['camera_world']['img_focal'],
|
| 396 |
principal_point=self.results['camera_world']['img_center'],
|
| 397 |
frame_rate=float(self.cfg.fps),
|
| 398 |
+
smplx_path='data/body_models/smplx/SMPLX_neutral_array_f32_slim.npz',
|
| 399 |
)
|
| 400 |
+
|
| 401 |
+
print("Usage:")
|
| 402 |
+
print(f'\tYou can drag and drop the "world4d.mcs" file to https://me.meshcapade.com/editor to view the result')
|
| 403 |
+
print(f'\tYou can import the "world4d.glb" file on Blender to view the result')
|
|
|
|
|
|
|
|
|
|
| 404 |
|
| 405 |
return self.results
|
requirements.txt
CHANGED
|
@@ -32,5 +32,7 @@ smplx==0.1.28
|
|
| 32 |
fvcore
|
| 33 |
pyliblzfse
|
| 34 |
smplcodec
|
|
|
|
|
|
|
| 35 |
git+https://github.com/mattloper/chumpy@9b045ff5d6588a24a0bab52c83f032e2ba433e17
|
| 36 |
git+https://github.com/facebookresearch/pytorch3d.git@stable
|
|
|
|
| 32 |
fvcore
|
| 33 |
pyliblzfse
|
| 34 |
smplcodec
|
| 35 |
+
smpl-rs==0.6.1
|
| 36 |
+
gloss-rs==0.6.0
|
| 37 |
git+https://github.com/mattloper/chumpy@9b045ff5d6588a24a0bab52c83f032e2ba433e17
|
| 38 |
git+https://github.com/facebookresearch/pytorch3d.git@stable
|
scripts/fetch_smplx.sh
CHANGED
|
@@ -33,4 +33,5 @@ rm -rf data/body_models/smpl/smpl
|
|
| 33 |
rm -rf data/body_models/smpl/smpl.zip
|
| 34 |
|
| 35 |
# Supplementary files
|
| 36 |
-
gdown --folder -O ./data/ https://drive.google.com/drive/folders/1JU7CuU2rKkwD7WWjvSZJKpQFFk_Z6NL7?usp=share_link
|
|
|
|
|
|
| 33 |
rm -rf data/body_models/smpl/smpl.zip
|
| 34 |
|
| 35 |
# Supplementary files
|
| 36 |
+
gdown --folder -O ./data/ https://drive.google.com/drive/folders/1JU7CuU2rKkwD7WWjvSZJKpQFFk_Z6NL7?usp=share_link
|
| 37 |
+
gdown -O ./data/body_models/smplx/ 1v9Qy7ZXWcTM8_a9K2nSLyyVrJMFYcUOk
|
scripts/install.sh
CHANGED
|
@@ -128,7 +128,6 @@ if [ "$PT_VERSION" == "2.4" ]; then
|
|
| 128 |
pip install data/wheels/droid_backends_intr-0.3-cp311-cp311-linux_x86_64.whl
|
| 129 |
pip install data/wheels/lietorch-0.3-cp311-cp311-linux_x86_64.whl
|
| 130 |
pip install data/wheels/sam2-1.5-cp311-cp311-linux_x86_64.whl
|
| 131 |
-
pip install data/wheels/gloss-0.5.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
|
| 132 |
fi
|
| 133 |
|
| 134 |
elif [ "$PT_VERSION" == "2.6" ]; then
|
|
@@ -151,8 +150,6 @@ elif [ "$PT_VERSION" == "2.6" ]; then
|
|
| 151 |
pip install data/wheels/sam2-1.6-cp312-cp312-linux_x86_64.whl
|
| 152 |
pip install data/wheels/detectron2-0.9-cp312-cp312-linux_x86_64.whl
|
| 153 |
pip install data/wheels/droid_backends_intr-0.4-cp312-cp312-linux_x86_64.whl
|
| 154 |
-
# pip install data/wheels/gloss_rs-0.6.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
|
| 155 |
-
pip install data/wheels/gloss-0.5.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
|
| 156 |
pip install data/wheels/lietorch-0.4-cp312-cp312-linux_x86_64.whl
|
| 157 |
fi
|
| 158 |
fi
|
|
|
|
| 128 |
pip install data/wheels/droid_backends_intr-0.3-cp311-cp311-linux_x86_64.whl
|
| 129 |
pip install data/wheels/lietorch-0.3-cp311-cp311-linux_x86_64.whl
|
| 130 |
pip install data/wheels/sam2-1.5-cp311-cp311-linux_x86_64.whl
|
|
|
|
| 131 |
fi
|
| 132 |
|
| 133 |
elif [ "$PT_VERSION" == "2.6" ]; then
|
|
|
|
| 150 |
pip install data/wheels/sam2-1.6-cp312-cp312-linux_x86_64.whl
|
| 151 |
pip install data/wheels/detectron2-0.9-cp312-cp312-linux_x86_64.whl
|
| 152 |
pip install data/wheels/droid_backends_intr-0.4-cp312-cp312-linux_x86_64.whl
|
|
|
|
|
|
|
| 153 |
pip install data/wheels/lietorch-0.4-cp312-cp312-linux_x86_64.whl
|
| 154 |
fi
|
| 155 |
fi
|