cronos3k commited on
Commit
9a9f462
·
verified ·
1 Parent(s): 238c028

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +225 -37
app.py CHANGED
@@ -15,48 +15,236 @@ from trellis.utils import render_utils, postprocessing_utils
15
  from gradio_litmodel3d import LitModel3D
16
 
17
 
18
- def check_gpu():
19
- """Check if CUDA GPU is available and properly initialized"""
20
- if not torch.cuda.is_available():
21
- raise RuntimeError(
22
- "This application requires a CUDA-capable GPU to run. "
23
- "No CUDA GPU was detected in your system."
24
- )
 
 
25
 
26
- # Print GPU information for debugging
27
- gpu_count = torch.cuda.device_count()
28
- print(f"Found {gpu_count} CUDA GPU(s)")
29
- for i in range(gpu_count):
30
- gpu_name = torch.cuda.get_device_name(i)
31
- print(f"GPU {i}: {gpu_name}")
32
 
33
- # Try to initialize CUDA
34
- try:
35
- torch.cuda.init()
36
- current_device = torch.cuda.current_device()
37
- print(f"Using GPU {current_device}: {torch.cuda.get_device_name(current_device)}")
38
- except Exception as e:
39
- raise RuntimeError(f"Failed to initialize CUDA: {str(e)}")
40
 
41
- # ... [rest of the code remains exactly the same until main] ...
 
42
 
43
- if __name__ == "__main__":
44
- # Check GPU availability first
45
- check_gpu()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
- # Initialize pipeline with explicit device setting
48
- device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
49
- pipeline = TrellisImageTo3DPipeline.from_pretrained(
50
- "JeffreyXiang/TRELLIS-image-large"
51
- ).to(device)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  try:
54
- # Use smaller test image and explicit device
55
- test_img = np.zeros((256, 256, 3), dtype=np.uint8)
56
- pipeline.preprocess_image(Image.fromarray(test_img))
57
- del test_img
58
- except Exception as e:
59
- print(f"Warning: Failed to preload rembg: {str(e)}")
60
-
61
- # Launch the demo
62
  demo.launch()
 
15
  from gradio_litmodel3d import LitModel3D
16
 
17
 
18
+ MAX_SEED = np.iinfo(np.int32).max
19
+ TMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp')
20
+ os.makedirs(TMP_DIR, exist_ok=True)
21
+
22
+
23
+ def start_session(req: gr.Request):
24
+ user_dir = os.path.join(TMP_DIR, str(req.session_hash))
25
+ print(f'Creating user directory: {user_dir}')
26
+ os.makedirs(user_dir, exist_ok=True)
27
 
28
+ def end_session(req: gr.Request):
29
+ user_dir = os.path.join(TMP_DIR, str(req.session_hash))
30
+ print(f'Removing user directory: {user_dir}')
31
+ shutil.rmtree(user_dir)
 
 
32
 
33
+ def preprocess_image(image: Image.Image) -> Tuple[str, Image.Image]:
34
+ """
35
+ Preprocess the input image.
 
 
 
 
36
 
37
+ Args:
38
+ image (Image.Image): The input image.
39
 
40
+ Returns:
41
+ str: uuid of the trial.
42
+ Image.Image: The preprocessed image.
43
+ """
44
+ processed_image = pipeline.preprocess_image(image)
45
+ return processed_image
46
+
47
+ def pack_state(gs: Gaussian, mesh: MeshExtractResult, trial_id: str) -> dict:
48
+ return {
49
+ 'gaussian': {
50
+ **gs.init_params,
51
+ '_xyz': gs._xyz.cpu().numpy(),
52
+ '_features_dc': gs._features_dc.cpu().numpy(),
53
+ '_scaling': gs._scaling.cpu().numpy(),
54
+ '_rotation': gs._rotation.cpu().numpy(),
55
+ '_opacity': gs._opacity.cpu().numpy(),
56
+ },
57
+ 'mesh': {
58
+ 'vertices': mesh.vertices.cpu().numpy(),
59
+ 'faces': mesh.faces.cpu().numpy(),
60
+ },
61
+ 'trial_id': trial_id,
62
+ }
63
+
64
+ def unpack_state(state: dict) -> Tuple[Gaussian, edict, str]:
65
+ gs = Gaussian(
66
+ aabb=state['gaussian']['aabb'],
67
+ sh_degree=state['gaussian']['sh_degree'],
68
+ mininum_kernel_size=state['gaussian']['mininum_kernel_size'],
69
+ scaling_bias=state['gaussian']['scaling_bias'],
70
+ opacity_bias=state['gaussian']['opacity_bias'],
71
+ scaling_activation=state['gaussian']['scaling_activation'],
72
+ )
73
+ gs._xyz = torch.tensor(state['gaussian']['_xyz'], device='cuda')
74
+ gs._features_dc = torch.tensor(state['gaussian']['_features_dc'], device='cuda')
75
+ gs._scaling = torch.tensor(state['gaussian']['_scaling'], device='cuda')
76
+ gs._rotation = torch.tensor(state['gaussian']['_rotation'], device='cuda')
77
+ gs._opacity = torch.tensor(state['gaussian']['_opacity'], device='cuda')
78
+
79
+ mesh = edict(
80
+ vertices=torch.tensor(state['mesh']['vertices'], device='cuda'),
81
+ faces=torch.tensor(state['mesh']['faces'], device='cuda'),
82
+ )
83
+
84
+ return gs, mesh, state['trial_id']
85
+
86
+ def get_seed(randomize_seed: bool, seed: int) -> int:
87
+ """
88
+ Get the random seed.
89
+ """
90
+ return np.random.randint(0, MAX_SEED) if randomize_seed else seed
91
+
92
+ def image_to_3d(
93
+ image: Image.Image,
94
+ seed: int,
95
+ ss_guidance_strength: float,
96
+ ss_sampling_steps: int,
97
+ slat_guidance_strength: float,
98
+ slat_sampling_steps: int,
99
+ req: gr.Request,
100
+ ) -> Tuple[dict, str, str, str]:
101
+ """
102
+ Convert an image to a 3D model.
103
+ """
104
+ user_dir = os.path.join(TMP_DIR, str(req.session_hash))
105
+ outputs = pipeline.run(
106
+ image,
107
+ seed=seed,
108
+ formats=["gaussian", "mesh"],
109
+ preprocess_image=False,
110
+ sparse_structure_sampler_params={
111
+ "steps": ss_sampling_steps,
112
+ "cfg_strength": ss_guidance_strength,
113
+ },
114
+ slat_sampler_params={
115
+ "steps": slat_sampling_steps,
116
+ "cfg_strength": slat_guidance_strength,
117
+ },
118
+ )
119
+ video = render_utils.render_video(outputs['gaussian'][0], num_frames=120)['color']
120
+ video_geo = render_utils.render_video(outputs['mesh'][0], num_frames=120)['normal']
121
+ video = [np.concatenate([video[i], video_geo[i]], axis=1) for i in range(len(video))]
122
+ trial_id = str(uuid.uuid4())
123
+ video_path = os.path.join(user_dir, f"{trial_id}.mp4")
124
+ imageio.mimsave(video_path, video, fps=15)
125
+
126
+ # Save full quality GLB
127
+ full_glb = postprocessing_utils.to_glb(
128
+ outputs['gaussian'][0],
129
+ outputs['mesh'][0],
130
+ simplify=0.0, # No simplification
131
+ texture_size=2048, # Maximum texture resolution
132
+ verbose=False
133
+ )
134
+ full_glb_path = os.path.join(user_dir, f"{trial_id}_full.glb")
135
+ full_glb.export(full_glb_path)
136
 
137
+ state = pack_state(outputs['gaussian'][0], outputs['mesh'][0], trial_id)
138
+ return state, video_path, model_output, full_glb_path
139
+
140
+ def extract_glb(
141
+ state: dict,
142
+ mesh_simplify: float,
143
+ texture_size: int,
144
+ req: gr.Request,
145
+ ) -> Tuple[str, str]:
146
+ """
147
+ Extract a GLB file from the 3D model.
148
+ """
149
+ user_dir = os.path.join(TMP_DIR, str(req.session_hash))
150
+ gs, mesh, trial_id = unpack_state(state)
151
+ glb = postprocessing_utils.to_glb(gs, mesh, simplify=mesh_simplify, texture_size=texture_size, verbose=False)
152
+ glb_path = os.path.join(user_dir, f"{trial_id}.glb")
153
+ glb.export(glb_path)
154
+ return glb_path, glb_path
155
+
156
+ with gr.Blocks(delete_cache=(600, 600)) as demo:
157
+ gr.Markdown("""
158
+ ## Image to 3D Asset with [TRELLIS](https://trellis3d.github.io/)
159
+ * Upload an image and click "Generate" to create a 3D asset
160
+ * You can download the full quality GLB immediately after generation
161
+ * Or create a reduced size version using the GLB Extraction Settings
162
+ """)
163
+
164
+ with gr.Row():
165
+ with gr.Column():
166
+ image_prompt = gr.Image(label="Image Prompt", format="png", image_mode="RGBA", type="pil", height=300)
167
+
168
+ with gr.Accordion(label="Generation Settings", open=False):
169
+ seed = gr.Slider(0, MAX_SEED, label="Seed", value=0, step=1)
170
+ randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
171
+ gr.Markdown("Stage 1: Sparse Structure Generation")
172
+ with gr.Row():
173
+ ss_guidance_strength = gr.Slider(0.0, 10.0, label="Guidance Strength", value=7.5, step=0.1)
174
+ ss_sampling_steps = gr.Slider(1, 500, label="Sampling Steps", value=12, step=1)
175
+ gr.Markdown("Stage 2: Structured Latent Generation")
176
+ with gr.Row():
177
+ slat_guidance_strength = gr.Slider(0.0, 10.0, label="Guidance Strength", value=3.0, step=0.1)
178
+ slat_sampling_steps = gr.Slider(1, 500, label="Sampling Steps", value=12, step=1)
179
+
180
+ generate_btn = gr.Button("Generate")
181
+
182
+ with gr.Accordion(label="GLB Extraction Settings", open=False):
183
+ mesh_simplify = gr.Slider(0.0, 0.98, label="Simplify", value=0.95, step=0.01)
184
+ texture_size = gr.Slider(512, 2048, label="Texture Size", value=1024, step=512)
185
+
186
+ extract_glb_btn = gr.Button("Extract Reduced GLB", interactive=False)
187
+
188
+ with gr.Column():
189
+ video_output = gr.Video(label="Generated 3D Asset", autoplay=True, loop=True, height=300)
190
+ model_output = LitModel3D(label="3D Model Preview", exposure=20.0, height=300)
191
+ with gr.Row():
192
+ download_full = gr.DownloadButton(label="Download Full-Quality GLB", interactive=False)
193
+ download_reduced = gr.DownloadButton(label="Download Reduced GLB", interactive=False)
194
+
195
+ output_buf = gr.State()
196
+
197
+ # Example images
198
+ with gr.Row():
199
+ examples = gr.Examples(
200
+ examples=[
201
+ f'assets/example_image/{image}'
202
+ for image in os.listdir("assets/example_image")
203
+ ],
204
+ inputs=[image_prompt],
205
+ fn=preprocess_image,
206
+ outputs=[image_prompt],
207
+ run_on_click=True,
208
+ examples_per_page=64,
209
+ )
210
+
211
+ # Event handlers
212
+ demo.load(start_session)
213
+ demo.unload(end_session)
214
 
215
+ image_prompt.upload(
216
+ preprocess_image,
217
+ inputs=[image_prompt],
218
+ outputs=[image_prompt],
219
+ )
220
+
221
+ generate_btn.click(
222
+ get_seed,
223
+ inputs=[randomize_seed, seed],
224
+ outputs=[seed],
225
+ ).then(
226
+ image_to_3d,
227
+ inputs=[image_prompt, seed, ss_guidance_strength, ss_sampling_steps, slat_guidance_strength, slat_sampling_steps],
228
+ outputs=[output_buf, video_output, model_output, download_full],
229
+ ).then(
230
+ lambda: (gr.Button(interactive=True), gr.Button(interactive=True), gr.Button(interactive=False)),
231
+ outputs=[download_full, extract_glb_btn, download_reduced],
232
+ )
233
+
234
+ extract_glb_btn.click(
235
+ extract_glb,
236
+ inputs=[output_buf, mesh_simplify, texture_size],
237
+ outputs=[model_output, download_reduced],
238
+ ).then(
239
+ lambda: gr.Button(interactive=True),
240
+ outputs=[download_reduced],
241
+ )
242
+
243
+ if __name__ == "__main__":
244
+ pipeline = TrellisImageTo3DPipeline.from_pretrained("JeffreyXiang/TRELLIS-image-large")
245
+ pipeline.cuda()
246
  try:
247
+ pipeline.preprocess_image(Image.fromarray(np.zeros((512, 512, 3), dtype=np.uint8))) # Preload rembg
248
+ except:
249
+ pass
 
 
 
 
 
250
  demo.launch()