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)
|
|