Spaces:
Running
on
Zero
Running
on
Zero
xinjie.wang
commited on
Commit
·
eae4507
1
Parent(s):
cbd4574
update
Browse files- app.py +8 -12
- asset3d_gen/data/backproject_v2.py +9 -8
- asset3d_gen/data/mesh_operator.py +2 -1
- asset3d_gen/models/delight_model.py +6 -6
- asset3d_gen/models/gs_model.py +4 -2
- asset3d_gen/models/sr_model.py +14 -7
- asset3d_gen/scripts/render_gs.py +2 -1
- asset3d_gen/utils/process_media.py +2 -1
- asset3d_gen/validators/aesthetic_predictor.py +2 -1
- common.py +61 -19
app.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1 |
import os
|
2 |
|
3 |
os.environ["GRADIO_APP"] = "imageto3d"
|
|
|
|
|
4 |
import gradio as gr
|
5 |
from common import (
|
6 |
MAX_SEED,
|
@@ -198,12 +200,9 @@ with gr.Blocks(
|
|
198 |
with gr.Row() as single_image_example:
|
199 |
examples = gr.Examples(
|
200 |
label="Image Gallery",
|
201 |
-
examples=
|
202 |
-
|
203 |
-
|
204 |
-
"assets/example_image"
|
205 |
-
)
|
206 |
-
],
|
207 |
inputs=[image_prompt],
|
208 |
fn=preprocess_image_fn,
|
209 |
outputs=[image_prompt, raw_image_cache],
|
@@ -214,12 +213,9 @@ with gr.Blocks(
|
|
214 |
with gr.Row(visible=False) as single_sam_image_example:
|
215 |
examples = gr.Examples(
|
216 |
label="Image Gallery",
|
217 |
-
examples=
|
218 |
-
|
219 |
-
|
220 |
-
"assets/example_image"
|
221 |
-
)
|
222 |
-
],
|
223 |
inputs=[image_prompt_sam],
|
224 |
fn=preprocess_sam_image_fn,
|
225 |
outputs=[image_prompt_sam, raw_image_cache],
|
|
|
1 |
import os
|
2 |
|
3 |
os.environ["GRADIO_APP"] = "imageto3d"
|
4 |
+
from glob import glob
|
5 |
+
|
6 |
import gradio as gr
|
7 |
from common import (
|
8 |
MAX_SEED,
|
|
|
200 |
with gr.Row() as single_image_example:
|
201 |
examples = gr.Examples(
|
202 |
label="Image Gallery",
|
203 |
+
examples=sorted(
|
204 |
+
glob("assets/example_image/*")
|
205 |
+
),
|
|
|
|
|
|
|
206 |
inputs=[image_prompt],
|
207 |
fn=preprocess_image_fn,
|
208 |
outputs=[image_prompt, raw_image_cache],
|
|
|
213 |
with gr.Row(visible=False) as single_sam_image_example:
|
214 |
examples = gr.Examples(
|
215 |
label="Image Gallery",
|
216 |
+
examples=sorted(
|
217 |
+
glob("assets/example_image/*")
|
218 |
+
),
|
|
|
|
|
|
|
219 |
inputs=[image_prompt_sam],
|
220 |
fn=preprocess_sam_image_fn,
|
221 |
outputs=[image_prompt_sam, raw_image_cache],
|
asset3d_gen/data/backproject_v2.py
CHANGED
@@ -2,10 +2,11 @@ import argparse
|
|
2 |
import logging
|
3 |
import math
|
4 |
import os
|
5 |
-
|
6 |
import cv2
|
7 |
import numpy as np
|
8 |
import nvdiffrast.torch as dr
|
|
|
9 |
import torch
|
10 |
import torch.nn.functional as F
|
11 |
import trimesh
|
@@ -220,7 +221,7 @@ class TextureBacker:
|
|
220 |
bake_angle_thresh: int = 75,
|
221 |
mask_thresh: float = 0.5,
|
222 |
):
|
223 |
-
|
224 |
self.camera_params = camera_params
|
225 |
self.renderer = None
|
226 |
self.view_weights = view_weights
|
@@ -419,17 +420,17 @@ class TextureBacker:
|
|
419 |
return texture
|
420 |
|
421 |
@spaces.GPU
|
422 |
-
def
|
423 |
self,
|
424 |
colors: list[Image.Image],
|
425 |
mesh: trimesh.Trimesh,
|
426 |
) -> trimesh.Trimesh:
|
427 |
self._lazy_init_render(self.camera_params, self.mask_thresh)
|
428 |
-
|
429 |
vertices = torch.from_numpy(mesh.vertices).to(self.device).float()
|
430 |
faces = torch.from_numpy(mesh.faces).to(self.device).to(torch.int)
|
431 |
uv_map = torch.from_numpy(mesh.visual.uv).to(self.device).float()
|
432 |
-
|
433 |
rendered_depth, masks = self.renderer.render_depth(vertices, faces)
|
434 |
norm_deps = self.renderer.normalize_map_by_mask(rendered_depth, masks)
|
435 |
render_uvs, _ = self.renderer.render_uv(vertices, faces, uv_map)
|
@@ -454,7 +455,7 @@ class TextureBacker:
|
|
454 |
|
455 |
texture_np = texture.cpu().numpy()
|
456 |
mask_np = (mask.squeeze(-1).cpu().numpy() * 255).astype(np.uint8)
|
457 |
-
|
458 |
return texture_np, mask_np
|
459 |
|
460 |
def __call__(
|
@@ -464,8 +465,8 @@ class TextureBacker:
|
|
464 |
output_path: str,
|
465 |
) -> trimesh.Trimesh:
|
466 |
mesh = self.load_mesh(mesh)
|
467 |
-
texture_np, mask_np = self.
|
468 |
-
|
469 |
texture_np = self.uv_inpaint(mesh, texture_np, mask_np)
|
470 |
texture_np = post_process_texture(texture_np)
|
471 |
vertices, faces, uv_map = self.get_mesh_np_attrs(
|
|
|
2 |
import logging
|
3 |
import math
|
4 |
import os
|
5 |
+
|
6 |
import cv2
|
7 |
import numpy as np
|
8 |
import nvdiffrast.torch as dr
|
9 |
+
import spaces
|
10 |
import torch
|
11 |
import torch.nn.functional as F
|
12 |
import trimesh
|
|
|
221 |
bake_angle_thresh: int = 75,
|
222 |
mask_thresh: float = 0.5,
|
223 |
):
|
224 |
+
|
225 |
self.camera_params = camera_params
|
226 |
self.renderer = None
|
227 |
self.view_weights = view_weights
|
|
|
420 |
return texture
|
421 |
|
422 |
@spaces.GPU
|
423 |
+
def compute_texture(
|
424 |
self,
|
425 |
colors: list[Image.Image],
|
426 |
mesh: trimesh.Trimesh,
|
427 |
) -> trimesh.Trimesh:
|
428 |
self._lazy_init_render(self.camera_params, self.mask_thresh)
|
429 |
+
|
430 |
vertices = torch.from_numpy(mesh.vertices).to(self.device).float()
|
431 |
faces = torch.from_numpy(mesh.faces).to(self.device).to(torch.int)
|
432 |
uv_map = torch.from_numpy(mesh.visual.uv).to(self.device).float()
|
433 |
+
|
434 |
rendered_depth, masks = self.renderer.render_depth(vertices, faces)
|
435 |
norm_deps = self.renderer.normalize_map_by_mask(rendered_depth, masks)
|
436 |
render_uvs, _ = self.renderer.render_uv(vertices, faces, uv_map)
|
|
|
455 |
|
456 |
texture_np = texture.cpu().numpy()
|
457 |
mask_np = (mask.squeeze(-1).cpu().numpy() * 255).astype(np.uint8)
|
458 |
+
|
459 |
return texture_np, mask_np
|
460 |
|
461 |
def __call__(
|
|
|
465 |
output_path: str,
|
466 |
) -> trimesh.Trimesh:
|
467 |
mesh = self.load_mesh(mesh)
|
468 |
+
texture_np, mask_np = self.compute_texture(colors, mesh)
|
469 |
+
|
470 |
texture_np = self.uv_inpaint(mesh, texture_np, mask_np)
|
471 |
texture_np = post_process_texture(texture_np)
|
472 |
vertices, faces, uv_map = self.get_mesh_np_attrs(
|
asset3d_gen/data/mesh_operator.py
CHANGED
@@ -1,9 +1,10 @@
|
|
1 |
import logging
|
2 |
from typing import Tuple, Union
|
3 |
-
|
4 |
import igraph
|
5 |
import numpy as np
|
6 |
import pyvista as pv
|
|
|
7 |
import torch
|
8 |
import utils3d
|
9 |
from pymeshfix import _meshfix
|
|
|
1 |
import logging
|
2 |
from typing import Tuple, Union
|
3 |
+
|
4 |
import igraph
|
5 |
import numpy as np
|
6 |
import pyvista as pv
|
7 |
+
import spaces
|
8 |
import torch
|
9 |
import utils3d
|
10 |
from pymeshfix import _meshfix
|
asset3d_gen/models/delight_model.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1 |
import os
|
2 |
from typing import Union
|
3 |
-
|
4 |
import cv2
|
5 |
import numpy as np
|
|
|
6 |
import torch
|
7 |
from diffusers import (
|
8 |
EulerAncestralDiscreteScheduler,
|
@@ -28,7 +29,6 @@ class DelightingModel(object):
|
|
28 |
device: str = "cuda",
|
29 |
seed: int = 0,
|
30 |
) -> None:
|
31 |
-
|
32 |
self.image_guide_scale = image_guide_scale
|
33 |
self.text_guide_scale = text_guide_scale
|
34 |
self.num_infer_step = num_infer_step
|
@@ -38,8 +38,8 @@ class DelightingModel(object):
|
|
38 |
)
|
39 |
self.seed = seed
|
40 |
self.device = device
|
41 |
-
self.pipeline = None
|
42 |
-
|
43 |
if model_path is None:
|
44 |
suffix = "hunyuan3d-delight-v2-0"
|
45 |
model_path = snapshot_download(
|
@@ -114,7 +114,7 @@ class DelightingModel(object):
|
|
114 |
target_wh: tuple[int, int] = None,
|
115 |
) -> Image.Image:
|
116 |
self._lazy_init_pipeline()
|
117 |
-
|
118 |
if isinstance(image, str):
|
119 |
image = Image.open(image)
|
120 |
elif isinstance(image, np.ndarray):
|
@@ -158,7 +158,7 @@ if __name__ == "__main__":
|
|
158 |
delighting_model = DelightingModel(
|
159 |
# model_path="/horizon-bucket/robot_lab/users/xinjie.wang/weights/hunyuan3d-delight-v2-0" # noqa
|
160 |
)
|
161 |
-
image_path = "
|
162 |
image = delighting_model(
|
163 |
image_path, preprocess=True, target_wh=(512, 512)
|
164 |
) # noqa
|
|
|
1 |
import os
|
2 |
from typing import Union
|
3 |
+
|
4 |
import cv2
|
5 |
import numpy as np
|
6 |
+
import spaces
|
7 |
import torch
|
8 |
from diffusers import (
|
9 |
EulerAncestralDiscreteScheduler,
|
|
|
29 |
device: str = "cuda",
|
30 |
seed: int = 0,
|
31 |
) -> None:
|
|
|
32 |
self.image_guide_scale = image_guide_scale
|
33 |
self.text_guide_scale = text_guide_scale
|
34 |
self.num_infer_step = num_infer_step
|
|
|
38 |
)
|
39 |
self.seed = seed
|
40 |
self.device = device
|
41 |
+
self.pipeline = None # lazy load model adapt to @spaces.GPU
|
42 |
+
|
43 |
if model_path is None:
|
44 |
suffix = "hunyuan3d-delight-v2-0"
|
45 |
model_path = snapshot_download(
|
|
|
114 |
target_wh: tuple[int, int] = None,
|
115 |
) -> Image.Image:
|
116 |
self._lazy_init_pipeline()
|
117 |
+
|
118 |
if isinstance(image, str):
|
119 |
image = Image.open(image)
|
120 |
elif isinstance(image, np.ndarray):
|
|
|
158 |
delighting_model = DelightingModel(
|
159 |
# model_path="/horizon-bucket/robot_lab/users/xinjie.wang/weights/hunyuan3d-delight-v2-0" # noqa
|
160 |
)
|
161 |
+
image_path = "scripts/apps/assets/example_image/room_bottle_002.jpeg"
|
162 |
image = delighting_model(
|
163 |
image_path, preprocess=True, target_wh=(512, 512)
|
164 |
) # noqa
|
asset3d_gen/models/gs_model.py
CHANGED
@@ -428,7 +428,7 @@ class GaussianOperator(GaussianBase):
|
|
428 |
sh_degree=self.sh_degree,
|
429 |
device=self.device,
|
430 |
)
|
431 |
-
|
432 |
return GaussianOperator(**gs_dict)
|
433 |
|
434 |
def rescale(self, scale: float):
|
@@ -459,7 +459,9 @@ class GaussianOperator(GaussianBase):
|
|
459 |
sh_degree: int = 0,
|
460 |
device: str = "cuda",
|
461 |
) -> None:
|
462 |
-
gs_model = GaussianOperator.load_from_ply(
|
|
|
|
|
463 |
|
464 |
if instance_pose is not None:
|
465 |
gs_model = gs_model.get_gaussians(instance_pose=instance_pose)
|
|
|
428 |
sh_degree=self.sh_degree,
|
429 |
device=self.device,
|
430 |
)
|
431 |
+
|
432 |
return GaussianOperator(**gs_dict)
|
433 |
|
434 |
def rescale(self, scale: float):
|
|
|
459 |
sh_degree: int = 0,
|
460 |
device: str = "cuda",
|
461 |
) -> None:
|
462 |
+
gs_model = GaussianOperator.load_from_ply(
|
463 |
+
in_ply, sh_degree, device=device
|
464 |
+
)
|
465 |
|
466 |
if instance_pose is not None:
|
467 |
gs_model = gs_model.get_gaussians(instance_pose=instance_pose)
|
asset3d_gen/models/sr_model.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1 |
import logging
|
2 |
import os
|
3 |
from typing import Union
|
4 |
-
|
5 |
import numpy as np
|
|
|
6 |
import torch
|
7 |
from huggingface_hub import snapshot_download
|
8 |
from PIL import Image
|
@@ -66,11 +67,16 @@ class ImageRealESRGAN:
|
|
66 |
if version.parse(torchvision.__version__) > version.parse("0.16"):
|
67 |
import sys
|
68 |
import types
|
|
|
69 |
import torchvision.transforms.functional as TF
|
70 |
|
71 |
-
functional_tensor = types.ModuleType(
|
|
|
|
|
72 |
functional_tensor.rgb_to_grayscale = TF.rgb_to_grayscale
|
73 |
-
sys.modules["torchvision.transforms.functional_tensor"] =
|
|
|
|
|
74 |
|
75 |
self.outscale = outscale
|
76 |
self.upsampler = None
|
@@ -80,15 +86,16 @@ class ImageRealESRGAN:
|
|
80 |
model_path = snapshot_download(
|
81 |
repo_id="xinjjj/RoboAssetGen", allow_patterns=f"{suffix}/*"
|
82 |
)
|
83 |
-
model_path = os.path.join(
|
|
|
|
|
84 |
|
85 |
self.model_path = model_path
|
86 |
-
|
87 |
def _lazy_init(self):
|
88 |
if self.upsampler is None:
|
89 |
from basicsr.archs.rrdbnet_arch import RRDBNet
|
90 |
from realesrgan import RealESRGANer
|
91 |
-
from huggingface_hub import snapshot_download
|
92 |
|
93 |
model = RRDBNet(
|
94 |
num_in_ch=3,
|
@@ -110,7 +117,7 @@ class ImageRealESRGAN:
|
|
110 |
@spaces.GPU
|
111 |
def __call__(self, image: Union[Image.Image, np.ndarray]) -> Image.Image:
|
112 |
self._lazy_init()
|
113 |
-
|
114 |
if isinstance(image, Image.Image):
|
115 |
image = np.array(image)
|
116 |
|
|
|
1 |
import logging
|
2 |
import os
|
3 |
from typing import Union
|
4 |
+
|
5 |
import numpy as np
|
6 |
+
import spaces
|
7 |
import torch
|
8 |
from huggingface_hub import snapshot_download
|
9 |
from PIL import Image
|
|
|
67 |
if version.parse(torchvision.__version__) > version.parse("0.16"):
|
68 |
import sys
|
69 |
import types
|
70 |
+
|
71 |
import torchvision.transforms.functional as TF
|
72 |
|
73 |
+
functional_tensor = types.ModuleType(
|
74 |
+
"torchvision.transforms.functional_tensor"
|
75 |
+
)
|
76 |
functional_tensor.rgb_to_grayscale = TF.rgb_to_grayscale
|
77 |
+
sys.modules["torchvision.transforms.functional_tensor"] = (
|
78 |
+
functional_tensor
|
79 |
+
)
|
80 |
|
81 |
self.outscale = outscale
|
82 |
self.upsampler = None
|
|
|
86 |
model_path = snapshot_download(
|
87 |
repo_id="xinjjj/RoboAssetGen", allow_patterns=f"{suffix}/*"
|
88 |
)
|
89 |
+
model_path = os.path.join(
|
90 |
+
model_path, suffix, "RealESRGAN_x4plus.pth"
|
91 |
+
)
|
92 |
|
93 |
self.model_path = model_path
|
94 |
+
|
95 |
def _lazy_init(self):
|
96 |
if self.upsampler is None:
|
97 |
from basicsr.archs.rrdbnet_arch import RRDBNet
|
98 |
from realesrgan import RealESRGANer
|
|
|
99 |
|
100 |
model = RRDBNet(
|
101 |
num_in_ch=3,
|
|
|
117 |
@spaces.GPU
|
118 |
def __call__(self, image: Union[Image.Image, np.ndarray]) -> Image.Image:
|
119 |
self._lazy_init()
|
120 |
+
|
121 |
if isinstance(image, Image.Image):
|
122 |
image = np.array(image)
|
123 |
|
asset3d_gen/scripts/render_gs.py
CHANGED
@@ -2,9 +2,10 @@ import argparse
|
|
2 |
import logging
|
3 |
import math
|
4 |
import os
|
5 |
-
|
6 |
import cv2
|
7 |
import numpy as np
|
|
|
8 |
import torch
|
9 |
from tqdm import tqdm
|
10 |
from asset3d_gen.data.utils import (
|
|
|
2 |
import logging
|
3 |
import math
|
4 |
import os
|
5 |
+
|
6 |
import cv2
|
7 |
import numpy as np
|
8 |
+
import spaces
|
9 |
import torch
|
10 |
from tqdm import tqdm
|
11 |
from asset3d_gen.data.utils import (
|
asset3d_gen/utils/process_media.py
CHANGED
@@ -6,11 +6,12 @@ import subprocess
|
|
6 |
from glob import glob
|
7 |
from io import BytesIO
|
8 |
from typing import Union
|
9 |
-
|
10 |
import cv2
|
11 |
import imageio
|
12 |
import numpy as np
|
13 |
import PIL.Image as Image
|
|
|
14 |
from moviepy.editor import VideoFileClip, clips_array
|
15 |
|
16 |
logging.basicConfig(level=logging.INFO)
|
|
|
6 |
from glob import glob
|
7 |
from io import BytesIO
|
8 |
from typing import Union
|
9 |
+
|
10 |
import cv2
|
11 |
import imageio
|
12 |
import numpy as np
|
13 |
import PIL.Image as Image
|
14 |
+
import spaces
|
15 |
from moviepy.editor import VideoFileClip, clips_array
|
16 |
|
17 |
logging.basicConfig(level=logging.INFO)
|
asset3d_gen/validators/aesthetic_predictor.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1 |
import os
|
2 |
-
|
3 |
import clip
|
4 |
import numpy as np
|
5 |
import pytorch_lightning as pl
|
|
|
6 |
import torch
|
7 |
import torch.nn as nn
|
8 |
from huggingface_hub import snapshot_download
|
|
|
1 |
import os
|
2 |
+
|
3 |
import clip
|
4 |
import numpy as np
|
5 |
import pytorch_lightning as pl
|
6 |
+
import spaces
|
7 |
import torch
|
8 |
import torch.nn as nn
|
9 |
from huggingface_hub import snapshot_download
|
common.py
CHANGED
@@ -11,7 +11,6 @@ import gradio as gr
|
|
11 |
import numpy as np
|
12 |
import spaces
|
13 |
import torch
|
14 |
-
import torch
|
15 |
import torch.nn.functional as F
|
16 |
import trimesh
|
17 |
from easydict import EasyDict as edict
|
@@ -58,8 +57,11 @@ from thirdparty.TRELLIS.trellis.representations import (
|
|
58 |
Gaussian,
|
59 |
MeshExtractResult,
|
60 |
)
|
61 |
-
from thirdparty.TRELLIS.trellis.representations.gaussian.general_utils import
|
62 |
-
|
|
|
|
|
|
|
63 |
from thirdparty.TRELLIS.trellis.utils import postprocessing_utils
|
64 |
from thirdparty.TRELLIS.trellis.utils.render_utils import (
|
65 |
render_frames,
|
@@ -87,7 +89,9 @@ def patched_setup_functions(self):
|
|
87 |
def inverse_softplus(x):
|
88 |
return x + torch.log(-torch.expm1(-x))
|
89 |
|
90 |
-
def build_covariance_from_scaling_rotation(
|
|
|
|
|
91 |
L = build_scaling_rotation(scaling_modifier * scaling, rotation)
|
92 |
actual_covariance = L @ L.transpose(1, 2)
|
93 |
symm = strip_symmetric(actual_covariance)
|
@@ -105,10 +109,15 @@ def patched_setup_functions(self):
|
|
105 |
self.inverse_opacity_activation = inverse_sigmoid
|
106 |
self.rotation_activation = F.normalize
|
107 |
|
108 |
-
self.scale_bias = self.inverse_scaling_activation(
|
|
|
|
|
109 |
self.rots_bias = torch.zeros((4)).to(self.device)
|
110 |
self.rots_bias[0] = 1
|
111 |
-
self.opacity_bias = self.inverse_opacity_activation(
|
|
|
|
|
|
|
112 |
|
113 |
Gaussian.setup_functions = patched_setup_functions
|
114 |
|
@@ -357,9 +366,7 @@ def pack_state(gs: Gaussian, mesh: MeshExtractResult) -> dict:
|
|
357 |
}
|
358 |
|
359 |
|
360 |
-
# @spaces.GPU
|
361 |
def unpack_state(state: dict, device: str = "cpu") -> tuple[Gaussian, dict]:
|
362 |
-
print("debug11")
|
363 |
gs = Gaussian(
|
364 |
aabb=state["gaussian"]["aabb"],
|
365 |
sh_degree=state["gaussian"]["sh_degree"],
|
@@ -369,7 +376,6 @@ def unpack_state(state: dict, device: str = "cpu") -> tuple[Gaussian, dict]:
|
|
369 |
scaling_activation=state["gaussian"]["scaling_activation"],
|
370 |
device=device,
|
371 |
)
|
372 |
-
print("debug12")
|
373 |
gs._xyz = torch.tensor(state["gaussian"]["_xyz"], device=device)
|
374 |
gs._features_dc = torch.tensor(
|
375 |
state["gaussian"]["_features_dc"], device=device
|
@@ -382,7 +388,6 @@ def unpack_state(state: dict, device: str = "cpu") -> tuple[Gaussian, dict]:
|
|
382 |
vertices=torch.tensor(state["mesh"]["vertices"], device=device),
|
383 |
faces=torch.tensor(state["mesh"]["faces"], device=device),
|
384 |
)
|
385 |
-
print("debug13")
|
386 |
|
387 |
return gs, mesh
|
388 |
|
@@ -484,21 +489,62 @@ def image_to_3d(
|
|
484 |
return state, video_path
|
485 |
|
486 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
487 |
def extract_3d_representations_v2(
|
488 |
state: dict,
|
489 |
enable_delight: bool,
|
490 |
req: gr.Request,
|
491 |
):
|
492 |
-
print("debug1")
|
493 |
output_root = TMP_DIR
|
494 |
user_dir = os.path.join(output_root, str(req.session_hash))
|
495 |
gs_model, mesh_model = unpack_state(state, device="cpu")
|
496 |
-
print("debug2")
|
497 |
|
498 |
filename = "sample"
|
499 |
gs_path = os.path.join(user_dir, f"{filename}_gs.ply")
|
500 |
gs_model.save_ply(gs_path)
|
501 |
-
print("debug3")
|
502 |
|
503 |
# Rotate mesh and GS by 90 degrees around Z-axis.
|
504 |
rot_matrix = [[0, 0, -1], [0, 1, 0], [1, 0, 0]]
|
@@ -509,17 +555,14 @@ def extract_3d_representations_v2(
|
|
509 |
gs_rot = np.array(gs_add_rot) @ np.array(rot_matrix)
|
510 |
pose = GaussianOperator.trans_to_quatpose(gs_rot)
|
511 |
aligned_gs_path = gs_path.replace(".ply", "_aligned.ply")
|
512 |
-
print("debug4")
|
513 |
GaussianOperator.resave_ply(
|
514 |
in_ply=gs_path,
|
515 |
out_ply=aligned_gs_path,
|
516 |
instance_pose=pose,
|
517 |
device="cpu",
|
518 |
)
|
519 |
-
print("debug5")
|
520 |
color_path = os.path.join(user_dir, "color.png")
|
521 |
render_gs_api(aligned_gs_path, color_path)
|
522 |
-
print("debug6")
|
523 |
|
524 |
mesh = trimesh.Trimesh(
|
525 |
vertices=mesh_model.vertices.cpu().numpy(),
|
@@ -530,7 +573,7 @@ def extract_3d_representations_v2(
|
|
530 |
|
531 |
mesh_obj_path = os.path.join(user_dir, f"{filename}.obj")
|
532 |
mesh.export(mesh_obj_path)
|
533 |
-
|
534 |
mesh = backproject_api(
|
535 |
delight_model=DELIGHT,
|
536 |
imagesr_model=IMAGESR_MODEL,
|
@@ -540,7 +583,6 @@ def extract_3d_representations_v2(
|
|
540 |
skip_fix_mesh=False,
|
541 |
delight=enable_delight,
|
542 |
)
|
543 |
-
print("debug8")
|
544 |
|
545 |
mesh_glb_path = os.path.join(user_dir, f"{filename}.glb")
|
546 |
mesh.export(mesh_glb_path)
|
@@ -560,7 +602,7 @@ def extract_urdf(
|
|
560 |
output_root = TMP_DIR
|
561 |
if req is not None:
|
562 |
output_root = os.path.join(output_root, str(req.session_hash))
|
563 |
-
|
564 |
# Convert to URDF and recover attrs by GPT.
|
565 |
filename = "sample"
|
566 |
urdf_convertor = URDFGenerator(GPT_CLIENT, render_view_num=4)
|
|
|
11 |
import numpy as np
|
12 |
import spaces
|
13 |
import torch
|
|
|
14 |
import torch.nn.functional as F
|
15 |
import trimesh
|
16 |
from easydict import EasyDict as edict
|
|
|
57 |
Gaussian,
|
58 |
MeshExtractResult,
|
59 |
)
|
60 |
+
from thirdparty.TRELLIS.trellis.representations.gaussian.general_utils import (
|
61 |
+
build_scaling_rotation,
|
62 |
+
inverse_sigmoid,
|
63 |
+
strip_symmetric,
|
64 |
+
)
|
65 |
from thirdparty.TRELLIS.trellis.utils import postprocessing_utils
|
66 |
from thirdparty.TRELLIS.trellis.utils.render_utils import (
|
67 |
render_frames,
|
|
|
89 |
def inverse_softplus(x):
|
90 |
return x + torch.log(-torch.expm1(-x))
|
91 |
|
92 |
+
def build_covariance_from_scaling_rotation(
|
93 |
+
scaling, scaling_modifier, rotation
|
94 |
+
):
|
95 |
L = build_scaling_rotation(scaling_modifier * scaling, rotation)
|
96 |
actual_covariance = L @ L.transpose(1, 2)
|
97 |
symm = strip_symmetric(actual_covariance)
|
|
|
109 |
self.inverse_opacity_activation = inverse_sigmoid
|
110 |
self.rotation_activation = F.normalize
|
111 |
|
112 |
+
self.scale_bias = self.inverse_scaling_activation(
|
113 |
+
torch.tensor(self.scaling_bias)
|
114 |
+
).to(self.device)
|
115 |
self.rots_bias = torch.zeros((4)).to(self.device)
|
116 |
self.rots_bias[0] = 1
|
117 |
+
self.opacity_bias = self.inverse_opacity_activation(
|
118 |
+
torch.tensor(self.opacity_bias)
|
119 |
+
).to(self.device)
|
120 |
+
|
121 |
|
122 |
Gaussian.setup_functions = patched_setup_functions
|
123 |
|
|
|
366 |
}
|
367 |
|
368 |
|
|
|
369 |
def unpack_state(state: dict, device: str = "cpu") -> tuple[Gaussian, dict]:
|
|
|
370 |
gs = Gaussian(
|
371 |
aabb=state["gaussian"]["aabb"],
|
372 |
sh_degree=state["gaussian"]["sh_degree"],
|
|
|
376 |
scaling_activation=state["gaussian"]["scaling_activation"],
|
377 |
device=device,
|
378 |
)
|
|
|
379 |
gs._xyz = torch.tensor(state["gaussian"]["_xyz"], device=device)
|
380 |
gs._features_dc = torch.tensor(
|
381 |
state["gaussian"]["_features_dc"], device=device
|
|
|
388 |
vertices=torch.tensor(state["mesh"]["vertices"], device=device),
|
389 |
faces=torch.tensor(state["mesh"]["faces"], device=device),
|
390 |
)
|
|
|
391 |
|
392 |
return gs, mesh
|
393 |
|
|
|
489 |
return state, video_path
|
490 |
|
491 |
|
492 |
+
@spaces.GPU
|
493 |
+
def extract_3d_representations(
|
494 |
+
state: dict, enable_delight: bool, req: gr.Request
|
495 |
+
):
|
496 |
+
output_root = TMP_DIR
|
497 |
+
output_root = os.path.join(output_root, str(req.session_hash))
|
498 |
+
gs_model, mesh_model = unpack_state(state)
|
499 |
+
|
500 |
+
mesh = postprocessing_utils.to_glb(
|
501 |
+
gs_model,
|
502 |
+
mesh_model,
|
503 |
+
simplify=0.9,
|
504 |
+
texture_size=1024,
|
505 |
+
verbose=True,
|
506 |
+
)
|
507 |
+
filename = "sample"
|
508 |
+
gs_path = os.path.join(output_root, f"{filename}_gs.ply")
|
509 |
+
gs_model.save_ply(gs_path)
|
510 |
+
|
511 |
+
# Rotate mesh and GS by 90 degrees around Z-axis.
|
512 |
+
rot_matrix = [[0, 0, -1], [0, 1, 0], [1, 0, 0]]
|
513 |
+
# Addtional rotation for GS to align mesh.
|
514 |
+
gs_rot = np.array([[1, 0, 0], [0, -1, 0], [0, 0, -1]]) @ np.array(
|
515 |
+
rot_matrix
|
516 |
+
)
|
517 |
+
pose = GaussianOperator.trans_to_quatpose(gs_rot)
|
518 |
+
aligned_gs_path = gs_path.replace(".ply", "_aligned.ply")
|
519 |
+
GaussianOperator.resave_ply(
|
520 |
+
in_ply=gs_path,
|
521 |
+
out_ply=aligned_gs_path,
|
522 |
+
instance_pose=pose,
|
523 |
+
)
|
524 |
+
|
525 |
+
mesh.vertices = mesh.vertices @ np.array(rot_matrix)
|
526 |
+
mesh_obj_path = os.path.join(output_root, f"{filename}.obj")
|
527 |
+
mesh.export(mesh_obj_path)
|
528 |
+
mesh_glb_path = os.path.join(output_root, f"{filename}.glb")
|
529 |
+
mesh.export(mesh_glb_path)
|
530 |
+
|
531 |
+
torch.cuda.empty_cache()
|
532 |
+
|
533 |
+
return mesh_glb_path, gs_path, mesh_obj_path, aligned_gs_path
|
534 |
+
|
535 |
+
|
536 |
def extract_3d_representations_v2(
|
537 |
state: dict,
|
538 |
enable_delight: bool,
|
539 |
req: gr.Request,
|
540 |
):
|
|
|
541 |
output_root = TMP_DIR
|
542 |
user_dir = os.path.join(output_root, str(req.session_hash))
|
543 |
gs_model, mesh_model = unpack_state(state, device="cpu")
|
|
|
544 |
|
545 |
filename = "sample"
|
546 |
gs_path = os.path.join(user_dir, f"{filename}_gs.ply")
|
547 |
gs_model.save_ply(gs_path)
|
|
|
548 |
|
549 |
# Rotate mesh and GS by 90 degrees around Z-axis.
|
550 |
rot_matrix = [[0, 0, -1], [0, 1, 0], [1, 0, 0]]
|
|
|
555 |
gs_rot = np.array(gs_add_rot) @ np.array(rot_matrix)
|
556 |
pose = GaussianOperator.trans_to_quatpose(gs_rot)
|
557 |
aligned_gs_path = gs_path.replace(".ply", "_aligned.ply")
|
|
|
558 |
GaussianOperator.resave_ply(
|
559 |
in_ply=gs_path,
|
560 |
out_ply=aligned_gs_path,
|
561 |
instance_pose=pose,
|
562 |
device="cpu",
|
563 |
)
|
|
|
564 |
color_path = os.path.join(user_dir, "color.png")
|
565 |
render_gs_api(aligned_gs_path, color_path)
|
|
|
566 |
|
567 |
mesh = trimesh.Trimesh(
|
568 |
vertices=mesh_model.vertices.cpu().numpy(),
|
|
|
573 |
|
574 |
mesh_obj_path = os.path.join(user_dir, f"{filename}.obj")
|
575 |
mesh.export(mesh_obj_path)
|
576 |
+
|
577 |
mesh = backproject_api(
|
578 |
delight_model=DELIGHT,
|
579 |
imagesr_model=IMAGESR_MODEL,
|
|
|
583 |
skip_fix_mesh=False,
|
584 |
delight=enable_delight,
|
585 |
)
|
|
|
586 |
|
587 |
mesh_glb_path = os.path.join(user_dir, f"{filename}.glb")
|
588 |
mesh.export(mesh_glb_path)
|
|
|
602 |
output_root = TMP_DIR
|
603 |
if req is not None:
|
604 |
output_root = os.path.join(output_root, str(req.session_hash))
|
605 |
+
|
606 |
# Convert to URDF and recover attrs by GPT.
|
607 |
filename = "sample"
|
608 |
urdf_convertor = URDFGenerator(GPT_CLIENT, render_view_num=4)
|