Spaces:
Running
on
Zero
Running
on
Zero
Advanced 3D settings
Browse files
.gitignore
CHANGED
|
@@ -163,7 +163,7 @@ cython_debug/
|
|
| 163 |
/.vs
|
| 164 |
/src/__pycache__
|
| 165 |
/utils/__pycache__
|
| 166 |
-
|
| 167 |
/temp_models
|
| 168 |
/.vscode/settings.json
|
| 169 |
**/*.pyc
|
|
|
|
| 163 |
/.vs
|
| 164 |
/src/__pycache__
|
| 165 |
/utils/__pycache__
|
| 166 |
+
**/__pycache__
|
| 167 |
/temp_models
|
| 168 |
/.vscode/settings.json
|
| 169 |
**/*.pyc
|
app.py
CHANGED
|
@@ -613,7 +613,7 @@ def combine_images_with_lerp(input_image, output_image, alpha):
|
|
| 613 |
print(f"Combining images with alpha: {alpha}")
|
| 614 |
return lerp_imagemath(in_image, out_image, alpha)
|
| 615 |
|
| 616 |
-
def add_border(image, mask_width, mask_height, blank_color):
|
| 617 |
bordered_image_output = Image.open(image).convert("RGBA")
|
| 618 |
margin_color = detect_color_format(blank_color)
|
| 619 |
print(f"Adding border to image with width: {mask_width}, height: {mask_height}, color: {margin_color}")
|
|
@@ -751,47 +751,54 @@ def generate_3d_asset_part1(depth_image_source, randomize_seed, seed, input_imag
|
|
| 751 |
# Determine the final seed using default MAX_SEED from constants
|
| 752 |
final_seed = np.random.randint(0, constants.MAX_SEED) if randomize_seed else seed
|
| 753 |
# Process the image for depth estimation
|
| 754 |
-
depth_img = depth_process_image(image_path, resized_width=1536, z_scale=
|
| 755 |
depth_img = resize_image_with_aspect_ratio(depth_img, 1536, 1536)
|
| 756 |
|
| 757 |
return depth_img, image_path, output_name, final_seed
|
| 758 |
|
| 759 |
@spaces.GPU(duration=150,progress=gr.Progress(track_tqdm=True))
|
| 760 |
-
def generate_3d_asset_part2(depth_img, image_path, output_name, seed, req: gr.Request, progress=gr.Progress(track_tqdm=True)):
|
| 761 |
# Open image using standardized defaults
|
| 762 |
image_raw = Image.open(image_path).convert("RGB")
|
| 763 |
-
resized_image = resize_image_with_aspect_ratio(image_raw,
|
| 764 |
depth_img = Image.open(depth_img).convert("RGBA")
|
| 765 |
# Preprocess and run the Trellis pipeline with fixed sampler settings
|
| 766 |
-
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
|
| 774 |
-
|
| 775 |
-
|
| 776 |
-
|
| 777 |
-
|
| 778 |
-
|
| 779 |
-
|
| 780 |
-
|
|
|
|
| 781 |
|
| 782 |
-
|
| 783 |
-
|
| 784 |
-
|
| 785 |
-
|
| 786 |
-
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
|
| 791 |
|
| 792 |
-
|
| 793 |
-
|
| 794 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 795 |
|
| 796 |
# Ensure data is on GPU and has correct type
|
| 797 |
if not vertices.is_cuda or not faces.is_cuda:
|
|
@@ -807,9 +814,13 @@ def generate_3d_asset_part2(depth_img, image_path, output_name, seed, req: gr.Re
|
|
| 807 |
user_dir = os.path.join(constants.TMPDIR, str(req.session_hash))
|
| 808 |
os.makedirs(user_dir, exist_ok=True)
|
| 809 |
|
| 810 |
-
video = render_utils.render_video(outputs['gaussian'][0], resolution=
|
| 811 |
-
|
| 812 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 813 |
video_path = os.path.join(user_dir, f'{output_name}.mp4')
|
| 814 |
imageio.mimsave(video_path, video, fps=8)
|
| 815 |
|
|
@@ -818,7 +829,9 @@ def generate_3d_asset_part2(depth_img, image_path, output_name, seed, req: gr.Re
|
|
| 818 |
depth_snapshot = depth_img
|
| 819 |
|
| 820 |
state = pack_state(outputs['gaussian'][0], outputs['mesh'][0], output_name)
|
| 821 |
-
torch.cuda.
|
|
|
|
|
|
|
| 822 |
return [state, video_path, depth_snapshot]
|
| 823 |
|
| 824 |
|
|
@@ -845,7 +858,9 @@ def extract_glb(
|
|
| 845 |
glb = postprocessing_utils.to_glb(gs, mesh, simplify=mesh_simplify, texture_size=texture_size, verbose=False)
|
| 846 |
glb_path = os.path.join(user_dir, f'{name}.glb')
|
| 847 |
glb.export(glb_path)
|
|
|
|
| 848 |
torch.cuda.empty_cache()
|
|
|
|
| 849 |
return glb_path, glb_path
|
| 850 |
|
| 851 |
@spaces.GPU(progress=gr.Progress(track_tqdm=True))
|
|
@@ -863,7 +878,9 @@ def extract_gaussian(state: dict, req: gr.Request, progress=gr.Progress(track_tq
|
|
| 863 |
gs, _, name = unpack_state(state)
|
| 864 |
gaussian_path = os.path.join(user_dir, f'{name}.ply')
|
| 865 |
gs.save_ply(gaussian_path)
|
|
|
|
| 866 |
torch.cuda.empty_cache()
|
|
|
|
| 867 |
return gaussian_path, gaussian_path
|
| 868 |
|
| 869 |
|
|
@@ -1171,16 +1188,21 @@ with gr.Blocks(css_paths="style_20250128.css", title=title, theme='Surn/beeuty',
|
|
| 1171 |
|
| 1172 |
with gr.Accordion("Height Maps and 3D", open=False):
|
| 1173 |
with gr.Row():
|
| 1174 |
-
|
| 1175 |
-
|
| 1176 |
-
|
| 1177 |
-
|
| 1178 |
-
|
| 1179 |
-
|
| 1180 |
-
|
| 1181 |
-
|
| 1182 |
-
|
| 1183 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1184 |
with gr.Row():
|
| 1185 |
generate_3d_asset_button = gr.Button("Generate 3D Asset", elem_classes="solid", variant="secondary")
|
| 1186 |
with gr.Row():
|
|
@@ -1196,9 +1218,16 @@ with gr.Blocks(css_paths="style_20250128.css", title=title, theme='Surn/beeuty',
|
|
| 1196 |
extract_glb_btn = gr.Button("Extract GLB", interactive=False)
|
| 1197 |
extract_gaussian_btn = gr.Button("Extract Gaussian", interactive=False)
|
| 1198 |
with gr.Row():
|
| 1199 |
-
|
|
|
|
| 1200 |
elem_classes="centered solid imgcontainer", interactive=True)
|
| 1201 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1202 |
is_multiimage = gr.State(False)
|
| 1203 |
output_buf = gr.State()
|
| 1204 |
ddd_image_path = gr.State("./images/images/Beeuty-1.png")
|
|
@@ -1320,7 +1349,7 @@ with gr.Blocks(css_paths="style_20250128.css", title=title, theme='Surn/beeuty',
|
|
| 1320 |
scroll_to_output=True
|
| 1321 |
).then(
|
| 1322 |
fn=generate_3d_asset_part2,
|
| 1323 |
-
inputs=[depth_output, ddd_image_path, ddd_file_name, seed_3d ],
|
| 1324 |
outputs=[output_buf, video_output, depth_output],
|
| 1325 |
scroll_to_output=True
|
| 1326 |
).then(
|
|
@@ -1332,19 +1361,19 @@ with gr.Blocks(css_paths="style_20250128.css", title=title, theme='Surn/beeuty',
|
|
| 1332 |
extract_glb_btn.click(
|
| 1333 |
fn=extract_glb,
|
| 1334 |
inputs=[output_buf, mesh_simplify, texture_size],
|
| 1335 |
-
outputs=[model_output,
|
| 1336 |
).then(
|
| 1337 |
lambda: gr.Button(interactive=True),
|
| 1338 |
-
outputs=[
|
| 1339 |
)
|
| 1340 |
|
| 1341 |
extract_gaussian_btn.click(
|
| 1342 |
fn=extract_gaussian,
|
| 1343 |
inputs=[output_buf],
|
| 1344 |
-
outputs=[model_output,
|
| 1345 |
).then(
|
| 1346 |
lambda: gr.Button(interactive=True),
|
| 1347 |
-
outputs=[
|
| 1348 |
)
|
| 1349 |
|
| 1350 |
if __name__ == "__main__":
|
|
|
|
| 613 |
print(f"Combining images with alpha: {alpha}")
|
| 614 |
return lerp_imagemath(in_image, out_image, alpha)
|
| 615 |
|
| 616 |
+
def add_border(image, mask_width, mask_height, blank_color):
|
| 617 |
bordered_image_output = Image.open(image).convert("RGBA")
|
| 618 |
margin_color = detect_color_format(blank_color)
|
| 619 |
print(f"Adding border to image with width: {mask_width}, height: {mask_height}, color: {margin_color}")
|
|
|
|
| 751 |
# Determine the final seed using default MAX_SEED from constants
|
| 752 |
final_seed = np.random.randint(0, constants.MAX_SEED) if randomize_seed else seed
|
| 753 |
# Process the image for depth estimation
|
| 754 |
+
depth_img = depth_process_image(image_path, resized_width=1536, z_scale=336)
|
| 755 |
depth_img = resize_image_with_aspect_ratio(depth_img, 1536, 1536)
|
| 756 |
|
| 757 |
return depth_img, image_path, output_name, final_seed
|
| 758 |
|
| 759 |
@spaces.GPU(duration=150,progress=gr.Progress(track_tqdm=True))
|
| 760 |
+
def generate_3d_asset_part2(depth_img, image_path, output_name, seed, steps, model_resolution, video_resolution, req: gr.Request, progress=gr.Progress(track_tqdm=True)):
|
| 761 |
# Open image using standardized defaults
|
| 762 |
image_raw = Image.open(image_path).convert("RGB")
|
| 763 |
+
resized_image = resize_image_with_aspect_ratio(image_raw, model_resolution, model_resolution)
|
| 764 |
depth_img = Image.open(depth_img).convert("RGBA")
|
| 765 |
# Preprocess and run the Trellis pipeline with fixed sampler settings
|
| 766 |
+
try:
|
| 767 |
+
processed_image = TRELLIS_PIPELINE.preprocess_image(resized_image, max_resolution=model_resolution)
|
| 768 |
+
outputs = TRELLIS_PIPELINE.run(
|
| 769 |
+
processed_image,
|
| 770 |
+
seed=seed,
|
| 771 |
+
formats=["gaussian", "mesh"],
|
| 772 |
+
preprocess_image=False,
|
| 773 |
+
sparse_structure_sampler_params={
|
| 774 |
+
"steps": steps,
|
| 775 |
+
"cfg_strength": 7.5,
|
| 776 |
+
},
|
| 777 |
+
slat_sampler_params={
|
| 778 |
+
"steps": steps,
|
| 779 |
+
"cfg_strength": 3.0,
|
| 780 |
+
},
|
| 781 |
+
)
|
| 782 |
|
| 783 |
+
# Validate the mesh
|
| 784 |
+
mesh = outputs['mesh'][0]
|
| 785 |
+
meshisdict = isinstance(mesh, dict)
|
| 786 |
+
if meshisdict:
|
| 787 |
+
vertices = mesh['vertices']
|
| 788 |
+
faces = mesh['faces']
|
| 789 |
+
else:
|
| 790 |
+
vertices = mesh.vertices
|
| 791 |
+
faces = mesh.faces
|
| 792 |
|
| 793 |
+
print(f"Mesh vertices: {vertices.shape}, faces: {faces.shape}")
|
| 794 |
+
if faces.max() >= vertices.shape[0]:
|
| 795 |
+
raise ValueError(f"Invalid mesh: face index {faces.max()} exceeds vertex count {vertices.shape[0]}")
|
| 796 |
+
except Exception as e:
|
| 797 |
+
gr.Warning(f"Error generating 3D asset: {e}")
|
| 798 |
+
print(f"Error generating 3D asset: {e}")
|
| 799 |
+
torch.cuda.empty_cache()
|
| 800 |
+
torch.cuda.ipc_collect()
|
| 801 |
+
return None,None, depth_img
|
| 802 |
|
| 803 |
# Ensure data is on GPU and has correct type
|
| 804 |
if not vertices.is_cuda or not faces.is_cuda:
|
|
|
|
| 814 |
user_dir = os.path.join(constants.TMPDIR, str(req.session_hash))
|
| 815 |
os.makedirs(user_dir, exist_ok=True)
|
| 816 |
|
| 817 |
+
video = render_utils.render_video(outputs['gaussian'][0], resolution=video_resolution, num_frames=64, r=1, fov=45)['color']
|
| 818 |
+
try:
|
| 819 |
+
video_geo = render_utils.render_video(outputs['mesh'][0], resolution=video_resolution, num_frames=64, r=1, fov=45)['normal']
|
| 820 |
+
video = [np.concatenate([video[i], video_geo[i]], axis=1) for i in range(len(video))]
|
| 821 |
+
except Exception as e:
|
| 822 |
+
gr.Info(f"Error rendering video: {e}")
|
| 823 |
+
print(f"Error rendering video: {e}")
|
| 824 |
video_path = os.path.join(user_dir, f'{output_name}.mp4')
|
| 825 |
imageio.mimsave(video_path, video, fps=8)
|
| 826 |
|
|
|
|
| 829 |
depth_snapshot = depth_img
|
| 830 |
|
| 831 |
state = pack_state(outputs['gaussian'][0], outputs['mesh'][0], output_name)
|
| 832 |
+
if torch.cuda.is_available():
|
| 833 |
+
torch.cuda.empty_cache()
|
| 834 |
+
torch.cuda.ipc_collect()
|
| 835 |
return [state, video_path, depth_snapshot]
|
| 836 |
|
| 837 |
|
|
|
|
| 858 |
glb = postprocessing_utils.to_glb(gs, mesh, simplify=mesh_simplify, texture_size=texture_size, verbose=False)
|
| 859 |
glb_path = os.path.join(user_dir, f'{name}.glb')
|
| 860 |
glb.export(glb_path)
|
| 861 |
+
|
| 862 |
torch.cuda.empty_cache()
|
| 863 |
+
torch.cuda.ipc_collect()
|
| 864 |
return glb_path, glb_path
|
| 865 |
|
| 866 |
@spaces.GPU(progress=gr.Progress(track_tqdm=True))
|
|
|
|
| 878 |
gs, _, name = unpack_state(state)
|
| 879 |
gaussian_path = os.path.join(user_dir, f'{name}.ply')
|
| 880 |
gs.save_ply(gaussian_path)
|
| 881 |
+
|
| 882 |
torch.cuda.empty_cache()
|
| 883 |
+
torch.cuda.ipc_collect()
|
| 884 |
return gaussian_path, gaussian_path
|
| 885 |
|
| 886 |
|
|
|
|
| 1188 |
|
| 1189 |
with gr.Accordion("Height Maps and 3D", open=False):
|
| 1190 |
with gr.Row():
|
| 1191 |
+
depth_image_source = gr.Radio(
|
| 1192 |
+
label="Depth Image Source",
|
| 1193 |
+
choices=["Input Image", "Hexagon Grid Image", "Overlay Image", "Image with Margins"],
|
| 1194 |
+
value="Input Image"
|
| 1195 |
+
)
|
| 1196 |
+
with gr.Accordion("Advanced 3D Generation Settings", open=False):
|
| 1197 |
+
with gr.Row():
|
| 1198 |
+
with gr.Column():
|
| 1199 |
+
# Use standard seed settings only
|
| 1200 |
+
seed_3d = gr.Slider(0, constants.MAX_SEED, label="Seed (3D Generation)", value=0, step=1, randomize=True)
|
| 1201 |
+
randomize_seed_3d = gr.Checkbox(label="Randomize Seed (3D Generation)", value=True)
|
| 1202 |
+
with gr.Column():
|
| 1203 |
+
steps = gr.Slider(6, 36, value=12, step=1, label="Image Sampling Steps", interactive=True)
|
| 1204 |
+
video_resolution = gr.Slider(384, 768, value=480, step=32, label="Video Resolution (*danger*)", interactive=True)
|
| 1205 |
+
model_resolution = gr.Slider(512, 2304, value=1024, step=64, label="3D Model Resolution", interactive=True)
|
| 1206 |
with gr.Row():
|
| 1207 |
generate_3d_asset_button = gr.Button("Generate 3D Asset", elem_classes="solid", variant="secondary")
|
| 1208 |
with gr.Row():
|
|
|
|
| 1218 |
extract_glb_btn = gr.Button("Extract GLB", interactive=False)
|
| 1219 |
extract_gaussian_btn = gr.Button("Extract Gaussian", interactive=False)
|
| 1220 |
with gr.Row():
|
| 1221 |
+
with gr.Column(scale=2):
|
| 1222 |
+
model_output = gr.Model3D(label="Extracted 3D Model", clear_color=[1.0, 1.0, 1.0, 1.0],
|
| 1223 |
elem_classes="centered solid imgcontainer", interactive=True)
|
| 1224 |
+
with gr.Column(scale=1):
|
| 1225 |
+
glb_file = gr.File(label="3D GLTF", elem_classes="solid small centered", height=250)
|
| 1226 |
+
gaussian_file = gr.File(label="Gaussian", elem_classes="solid small centered", height=250)
|
| 1227 |
+
gr.Markdown("""
|
| 1228 |
+
### Files over 10 MB may not display in the 3D model viewer
|
| 1229 |
+
""", elem_id="file_size_info", elem_classes="intro" )
|
| 1230 |
+
|
| 1231 |
is_multiimage = gr.State(False)
|
| 1232 |
output_buf = gr.State()
|
| 1233 |
ddd_image_path = gr.State("./images/images/Beeuty-1.png")
|
|
|
|
| 1349 |
scroll_to_output=True
|
| 1350 |
).then(
|
| 1351 |
fn=generate_3d_asset_part2,
|
| 1352 |
+
inputs=[depth_output, ddd_image_path, ddd_file_name, seed_3d, steps, model_resolution, video_resolution ],
|
| 1353 |
outputs=[output_buf, video_output, depth_output],
|
| 1354 |
scroll_to_output=True
|
| 1355 |
).then(
|
|
|
|
| 1361 |
extract_glb_btn.click(
|
| 1362 |
fn=extract_glb,
|
| 1363 |
inputs=[output_buf, mesh_simplify, texture_size],
|
| 1364 |
+
outputs=[model_output, glb_file]
|
| 1365 |
).then(
|
| 1366 |
lambda: gr.Button(interactive=True),
|
| 1367 |
+
outputs=[glb_file]
|
| 1368 |
)
|
| 1369 |
|
| 1370 |
extract_gaussian_btn.click(
|
| 1371 |
fn=extract_gaussian,
|
| 1372 |
inputs=[output_buf],
|
| 1373 |
+
outputs=[model_output, gaussian_file]
|
| 1374 |
).then(
|
| 1375 |
lambda: gr.Button(interactive=True),
|
| 1376 |
+
outputs=[gaussian_file]
|
| 1377 |
)
|
| 1378 |
|
| 1379 |
if __name__ == "__main__":
|
trellis/modules/transformer/__pycache__/__init__.cpython-312.pyc
DELETED
|
Binary file (216 Bytes)
|
|
|
trellis/modules/transformer/__pycache__/blocks.cpython-312.pyc
DELETED
|
Binary file (9.18 kB)
|
|
|
trellis/modules/transformer/__pycache__/modulated.cpython-312.pyc
DELETED
|
Binary file (7.64 kB)
|
|
|