abreza commited on
Commit
39b4836
1 Parent(s): 57b8167
Files changed (1) hide show
  1. app.py +167 -293
app.py CHANGED
@@ -1,39 +1,41 @@
1
- import spaces
2
-
3
  import os
4
- import imageio
 
 
 
 
5
  import numpy as np
6
- import torch
7
  import rembg
 
 
 
 
 
8
  from PIL import Image
9
- from torchvision.transforms import v2
10
  from pytorch_lightning import seed_everything
11
- from omegaconf import OmegaConf
12
- from einops import rearrange, repeat
13
  from tqdm import tqdm
14
- from diffusers import DiffusionPipeline, EulerAncestralDiscreteScheduler
15
 
 
 
 
16
  from src.utils.train_util import instantiate_from_config
17
- from src.utils.camera_util import (
18
- FOV_to_intrinsics,
19
- get_zero123plus_input_cameras,
20
- get_circular_camera_poses,
21
- )
22
- from src.utils.mesh_util import save_obj, save_glb
23
- from src.utils.infer_util import remove_background, resize_foreground, images_to_video
24
 
25
- import tempfile
26
- from functools import partial
27
 
28
- from huggingface_hub import hf_hub_download
 
 
 
29
 
30
- import gradio as gr
 
 
 
 
 
31
 
32
 
33
  def get_render_cameras(batch_size=1, M=120, radius=2.5, elevation=10.0, is_flexicubes=False):
34
- """
35
- Get the rendering camera parameters.
36
- """
37
  c2ws = get_circular_camera_poses(M=M, radius=radius, elevation=elevation)
38
  if is_flexicubes:
39
  cameras = torch.linalg.inv(c2ws)
@@ -46,89 +48,42 @@ def get_render_cameras(batch_size=1, M=120, radius=2.5, elevation=10.0, is_flexi
46
  return cameras
47
 
48
 
49
- def images_to_video(images, output_path, fps=30):
50
- # images: (N, C, H, W)
51
- os.makedirs(os.path.dirname(output_path), exist_ok=True)
52
- frames = []
53
- for i in range(images.shape[0]):
54
- frame = (images[i].permute(1, 2, 0).cpu().numpy() * 255).astype(np.uint8).clip(0, 255)
55
- assert frame.shape[0] == images.shape[2] and frame.shape[1] == images.shape[3], \
56
- f"Frame shape mismatch: {frame.shape} vs {images.shape}"
57
- assert frame.min() >= 0 and frame.max() <= 255, \
58
- f"Frame value out of range: {frame.min()} ~ {frame.max()}"
59
- frames.append(frame)
60
- imageio.mimwrite(output_path, np.stack(frames), fps=fps, codec='h264')
61
-
62
-
63
- ###############################################################################
64
- # Configuration.
65
- ###############################################################################
66
-
67
- import shutil
68
-
69
- def find_cuda():
70
- # Check if CUDA_HOME or CUDA_PATH environment variables are set
71
- cuda_home = os.environ.get('CUDA_HOME') or os.environ.get('CUDA_PATH')
72
-
73
- if cuda_home and os.path.exists(cuda_home):
74
- return cuda_home
75
-
76
- # Search for the nvcc executable in the system's PATH
77
- nvcc_path = shutil.which('nvcc')
78
-
79
- if nvcc_path:
80
- # Remove the 'bin/nvcc' part to get the CUDA installation path
81
- cuda_path = os.path.dirname(os.path.dirname(nvcc_path))
82
- return cuda_path
83
-
84
- return None
85
 
86
- cuda_path = find_cuda()
87
 
88
- if cuda_path:
89
- print(f"CUDA installation found at: {cuda_path}")
90
- else:
91
- print("CUDA installation not found")
92
 
93
- config_path = 'configs/instant-mesh-large.yaml'
94
- config = OmegaConf.load(config_path)
95
- config_name = os.path.basename(config_path).replace('.yaml', '')
96
- model_config = config.model_config
97
- infer_config = config.infer_config
98
-
99
- IS_FLEXICUBES = True if config_name.startswith('instant-mesh') else False
100
-
101
- device = torch.device('cuda')
102
-
103
- # load diffusion model
104
- print('Loading diffusion model ...')
105
- pipeline = DiffusionPipeline.from_pretrained(
106
- "sudo-ai/zero123plus-v1.2",
107
- custom_pipeline="zero123plus",
108
- torch_dtype=torch.float16,
109
- )
110
- pipeline.scheduler = EulerAncestralDiscreteScheduler.from_config(
111
- pipeline.scheduler.config, timestep_spacing='trailing'
112
- )
113
 
114
- # load custom white-background UNet
115
- unet_ckpt_path = hf_hub_download(repo_id="TencentARC/InstantMesh", filename="diffusion_pytorch_model.bin", repo_type="model")
116
- state_dict = torch.load(unet_ckpt_path, map_location='cpu')
117
- pipeline.unet.load_state_dict(state_dict, strict=True)
118
 
119
- pipeline = pipeline.to(device)
120
 
121
- # load reconstruction model
122
- print('Loading reconstruction model ...')
123
- model_ckpt_path = hf_hub_download(repo_id="TencentARC/InstantMesh", filename="instant_mesh_large.ckpt", repo_type="model")
124
- model = instantiate_from_config(model_config)
125
- state_dict = torch.load(model_ckpt_path, map_location='cpu')['state_dict']
126
- state_dict = {k[14:]: v for k, v in state_dict.items() if k.startswith('lrm_generator.') and 'source_camera' not in k}
127
- model.load_state_dict(state_dict, strict=True)
128
 
129
- model = model.to(device)
130
 
131
- print('Loading Finished!')
132
 
133
 
134
  def check_input_image(input_image):
@@ -137,7 +92,6 @@ def check_input_image(input_image):
137
 
138
 
139
  def preprocess(input_image, do_remove_background):
140
-
141
  rembg_session = rembg.new_session() if do_remove_background else None
142
 
143
  if do_remove_background:
@@ -147,19 +101,16 @@ def preprocess(input_image, do_remove_background):
147
  return input_image
148
 
149
 
150
- @spaces.GPU
151
- def generate_mvs(input_image, sample_steps, sample_seed):
152
-
153
  seed_everything(sample_seed)
154
-
155
- # sampling
156
  z123_image = pipeline(
157
- input_image,
158
  num_inference_steps=sample_steps
159
  ).images[0]
160
 
161
  show_image = np.asarray(z123_image, dtype=np.uint8)
162
- show_image = torch.from_numpy(show_image) # (960, 640, 3)
163
  show_image = rearrange(show_image, '(n h) (m w) c -> (n m) h w c', n=3, m=2)
164
  show_image = rearrange(show_image, '(n m) h w c -> (n h) (m w) c', n=2, m=3)
165
  show_image = Image.fromarray(show_image.numpy())
@@ -167,224 +118,147 @@ def generate_mvs(input_image, sample_steps, sample_seed):
167
  return z123_image, show_image
168
 
169
 
170
- @spaces.GPU
171
- def make3d(images):
172
 
173
- global model
174
- if IS_FLEXICUBES:
175
  model.init_flexicubes_geometry(device, use_renderer=False)
176
  model = model.eval()
177
 
178
  images = np.asarray(images, dtype=np.float32) / 255.0
179
- images = torch.from_numpy(images).permute(2, 0, 1).contiguous().float() # (3, 960, 640)
180
- images = rearrange(images, 'c (n h) (m w) -> (n m) c h w', n=3, m=2) # (6, 3, 320, 320)
181
 
182
  input_cameras = get_zero123plus_input_cameras(batch_size=1, radius=4.0).to(device)
183
- render_cameras = get_render_cameras(batch_size=1, radius=2.5, is_flexicubes=IS_FLEXICUBES).to(device)
184
 
185
  images = images.unsqueeze(0).to(device)
186
  images = v2.functional.resize(images, (320, 320), interpolation=3, antialias=True).clamp(0, 1)
187
 
188
  mesh_fpath = tempfile.NamedTemporaryFile(suffix=f".obj", delete=False).name
189
- print(mesh_fpath)
190
  mesh_basename = os.path.basename(mesh_fpath).split('.')[0]
191
  mesh_dirname = os.path.dirname(mesh_fpath)
192
- video_fpath = os.path.join(mesh_dirname, f"{mesh_basename}.mp4")
193
  mesh_glb_fpath = os.path.join(mesh_dirname, f"{mesh_basename}.glb")
194
 
195
  with torch.no_grad():
196
- # get triplane
197
  planes = model.forward_planes(images, input_cameras)
198
-
199
- # # get video
200
- # chunk_size = 20 if IS_FLEXICUBES else 1
201
- # render_size = 384
202
-
203
- # frames = []
204
- # for i in tqdm(range(0, render_cameras.shape[1], chunk_size)):
205
- # if IS_FLEXICUBES:
206
- # frame = model.forward_geometry(
207
- # planes,
208
- # render_cameras[:, i:i+chunk_size],
209
- # render_size=render_size,
210
- # )['img']
211
- # else:
212
- # frame = model.synthesizer(
213
- # planes,
214
- # cameras=render_cameras[:, i:i+chunk_size],
215
- # render_size=render_size,
216
- # )['images_rgb']
217
- # frames.append(frame)
218
- # frames = torch.cat(frames, dim=1)
219
-
220
- # images_to_video(
221
- # frames[0],
222
- # video_fpath,
223
- # fps=30,
224
- # )
225
-
226
- # print(f"Video saved to {video_fpath}")
227
-
228
- # get mesh
229
- mesh_out = model.extract_mesh(
230
- planes,
231
- use_texture_map=False,
232
- **infer_config,
233
- )
234
 
235
  vertices, faces, vertex_colors = mesh_out
236
  vertices = vertices[:, [1, 2, 0]]
237
-
238
  save_glb(vertices, faces, vertex_colors, mesh_glb_fpath)
239
  save_obj(vertices, faces, vertex_colors, mesh_fpath)
240
-
241
- print(f"Mesh saved to {mesh_fpath}")
242
 
243
  return mesh_fpath, mesh_glb_fpath
244
 
245
 
246
- _HEADER_ = '''
247
- <h2><b>Official 🤗 Gradio Demo</b></h2><h2><a href='https://github.com/TencentARC/InstantMesh' target='_blank'><b>InstantMesh: Efficient 3D Mesh Generation from a Single Image with Sparse-view Large Reconstruction Models</b></a></h2>
248
-
249
- **InstantMesh** is a feed-forward framework for efficient 3D mesh generation from a single image based on the LRM/Instant3D architecture.
250
-
251
- Code: <a href='https://github.com/TencentARC/InstantMesh' target='_blank'>GitHub</a>. Techenical report: <a href='https://arxiv.org/abs/2404.07191' target='_blank'>ArXiv</a>.
252
-
253
- ❗️❗️❗️**Important Notes:**
254
- - Our demo can export a .obj mesh with vertex colors or a .glb mesh now. If you prefer to export a .obj mesh with a **texture map**, please refer to our <a href='https://github.com/TencentARC/InstantMesh?tab=readme-ov-file#running-with-command-line' target='_blank'>Github Repo</a>.
255
- - The 3D mesh generation results highly depend on the quality of generated multi-view images. Please try a different **seed value** if the result is unsatisfying (Default: 42).
256
- '''
257
-
258
- _CITE_ = r"""
259
- If InstantMesh is helpful, please help to ⭐ the <a href='https://github.com/TencentARC/InstantMesh' target='_blank'>Github Repo</a>. Thanks! [![GitHub Stars](https://img.shields.io/github/stars/TencentARC/InstantMesh?style=social)](https://github.com/TencentARC/InstantMesh)
260
- ---
261
- 📝 **Citation**
262
-
263
- If you find our work useful for your research or applications, please cite using this bibtex:
264
- ```bibtex
265
- @article{xu2024instantmesh,
266
- title={InstantMesh: Efficient 3D Mesh Generation from a Single Image with Sparse-view Large Reconstruction Models},
267
- author={Xu, Jiale and Cheng, Weihao and Gao, Yiming and Wang, Xintao and Gao, Shenghua and Shan, Ying},
268
- journal={arXiv preprint arXiv:2404.07191},
269
- year={2024}
270
- }
271
- ```
272
-
273
- 📋 **License**
274
-
275
- Apache-2.0 LICENSE. Please refer to the [LICENSE file](https://huggingface.co/spaces/TencentARC/InstantMesh/blob/main/LICENSE) for details.
276
-
277
- 📧 **Contact**
278
-
279
- If you have any questions, feel free to open a discussion or contact us at <b>bluestyle928@gmail.com</b>.
280
- """
281
-
282
-
283
- with gr.Blocks() as demo:
284
- gr.Markdown(_HEADER_)
285
- with gr.Row(variant="panel"):
286
- with gr.Column():
287
- with gr.Row():
288
- input_image = gr.Image(
289
- label="Input Image",
290
- image_mode="RGBA",
291
- sources="upload",
292
- #width=256,
293
- #height=256,
294
- type="pil",
295
- elem_id="content_image",
296
- )
297
- processed_image = gr.Image(
298
- label="Processed Image",
299
- image_mode="RGBA",
300
- #width=256,
301
- #height=256,
302
- type="pil",
303
- interactive=False
304
- )
305
- with gr.Row():
306
- with gr.Group():
307
- do_remove_background = gr.Checkbox(
308
- label="Remove Background", value=True
309
- )
310
- sample_seed = gr.Number(value=42, label="Seed Value", precision=0)
311
-
312
- sample_steps = gr.Slider(
313
- label="Sample Steps",
314
- minimum=30,
315
- maximum=75,
316
- value=75,
317
- step=5
318
  )
319
-
320
- with gr.Row():
321
- submit = gr.Button("Generate", elem_id="generate", variant="primary")
322
-
323
- with gr.Row(variant="panel"):
324
- gr.Examples(
325
- examples=[
326
- os.path.join("examples", img_name) for img_name in sorted(os.listdir("examples"))
327
- ],
328
- inputs=[input_image],
329
- label="Examples",
330
- cache_examples=False,
331
- examples_per_page=16
332
- )
333
-
334
- with gr.Column():
335
-
336
- with gr.Row():
337
-
338
- with gr.Column():
339
- mv_show_images = gr.Image(
340
- label="Generated Multi-views",
341
  type="pil",
342
- width=379,
343
  interactive=False
344
  )
345
-
346
- # with gr.Column():
347
- # output_video = gr.Video(
348
- # label="video", format="mp4",
349
- # width=379,
350
- # autoplay=True,
351
- # interactive=False
352
- # )
353
-
354
- with gr.Row():
355
- with gr.Tab("OBJ"):
356
- output_model_obj = gr.Model3D(
357
- label="Output Model (OBJ Format)",
358
- interactive=False,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
  )
360
- gr.Markdown("Note: Downloaded .obj model will be flipped. Export .glb instead or manually flip it before usage.")
361
- with gr.Tab("GLB"):
362
- output_model_glb = gr.Model3D(
363
- label="Output Model (GLB Format)",
364
- interactive=False,
365
- )
366
- gr.Markdown("Note: The model shown here has a darker appearance. Download to get correct results.")
367
-
368
- with gr.Row():
369
- gr.Markdown('''Try a different <b>seed value</b> if the result is unsatisfying (Default: 42).''')
370
-
371
- gr.Markdown(_CITE_)
372
-
373
- mv_images = gr.State()
374
-
375
- submit.click(fn=check_input_image, inputs=[input_image]).success(
376
- fn=preprocess,
377
- inputs=[input_image, do_remove_background],
378
- outputs=[processed_image],
379
- ).success(
380
- fn=generate_mvs,
381
- inputs=[processed_image, sample_steps, sample_seed],
382
- outputs=[mv_images, mv_show_images]
383
-
384
- ).success(
385
- fn=make3d,
386
- inputs=[mv_images],
387
- outputs=[output_model_obj, output_model_glb]
388
- )
389
 
390
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
+ import shutil
3
+ import tempfile
4
+ from functools import partial
5
+
6
+ import gradio as gr
7
  import numpy as np
 
8
  import rembg
9
+ import torch
10
+ from diffusers import DiffusionPipeline, EulerAncestralDiscreteScheduler
11
+ from einops import rearrange
12
+ from huggingface_hub import hf_hub_download
13
+ from omegaconf import OmegaConf
14
  from PIL import Image
 
15
  from pytorch_lightning import seed_everything
16
+ from torchvision.transforms import v2
 
17
  from tqdm import tqdm
 
18
 
19
+ from src.utils.camera_util import FOV_to_intrinsics, get_circular_camera_poses, get_zero123plus_input_cameras
20
+ from src.utils.infer_util import images_to_video, remove_background, resize_foreground
21
+ from src.utils.mesh_util import save_glb, save_obj
22
  from src.utils.train_util import instantiate_from_config
 
 
 
 
 
 
 
23
 
 
 
24
 
25
+ def find_cuda():
26
+ cuda_home = os.environ.get('CUDA_HOME') or os.environ.get('CUDA_PATH')
27
+ if cuda_home and os.path.exists(cuda_home):
28
+ return cuda_home
29
 
30
+ nvcc_path = shutil.which('nvcc')
31
+ if nvcc_path:
32
+ cuda_path = os.path.dirname(os.path.dirname(nvcc_path))
33
+ return cuda_path
34
+
35
+ return None
36
 
37
 
38
  def get_render_cameras(batch_size=1, M=120, radius=2.5, elevation=10.0, is_flexicubes=False):
 
 
 
39
  c2ws = get_circular_camera_poses(M=M, radius=radius, elevation=elevation)
40
  if is_flexicubes:
41
  cameras = torch.linalg.inv(c2ws)
 
48
  return cameras
49
 
50
 
51
+ def load_models(config_path):
52
+ config = OmegaConf.load(config_path)
53
+ config_name = os.path.basename(config_path).replace('.yaml', '')
54
+ model_config = config.model_config
55
+ infer_config = config.infer_config
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
+ is_flexicubes = config_name.startswith('instant-mesh')
58
 
59
+ device = torch.device('cuda')
 
 
 
60
 
61
+ pipeline = DiffusionPipeline.from_pretrained(
62
+ "sudo-ai/zero123plus-v1.2",
63
+ custom_pipeline="zero123plus",
64
+ torch_dtype=torch.float16,
65
+ )
66
+ pipeline.scheduler = EulerAncestralDiscreteScheduler.from_config(
67
+ pipeline.scheduler.config, timestep_spacing='trailing'
68
+ )
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
+ unet_ckpt_path = hf_hub_download(
71
+ repo_id="TencentARC/InstantMesh", filename="diffusion_pytorch_model.bin", repo_type="model")
72
+ state_dict = torch.load(unet_ckpt_path, map_location='cpu')
73
+ pipeline.unet.load_state_dict(state_dict, strict=True)
74
 
75
+ pipeline = pipeline.to(device)
76
 
77
+ model_ckpt_path = hf_hub_download(
78
+ repo_id="TencentARC/InstantMesh", filename="instant_mesh_large.ckpt", repo_type="model")
79
+ model = instantiate_from_config(model_config)
80
+ state_dict = torch.load(model_ckpt_path, map_location='cpu')['state_dict']
81
+ state_dict = {k[14:]: v for k, v in state_dict.items() if k.startswith('lrm_generator.') and 'source_camera' not in k}
82
+ model.load_state_dict(state_dict, strict=True)
 
83
 
84
+ model = model.to(device)
85
 
86
+ return pipeline, model, is_flexicubes, infer_config
87
 
88
 
89
  def check_input_image(input_image):
 
92
 
93
 
94
  def preprocess(input_image, do_remove_background):
 
95
  rembg_session = rembg.new_session() if do_remove_background else None
96
 
97
  if do_remove_background:
 
101
  return input_image
102
 
103
 
104
+ def generate_mvs(input_image, sample_steps, sample_seed, pipeline):
 
 
105
  seed_everything(sample_seed)
106
+
 
107
  z123_image = pipeline(
108
+ input_image,
109
  num_inference_steps=sample_steps
110
  ).images[0]
111
 
112
  show_image = np.asarray(z123_image, dtype=np.uint8)
113
+ show_image = torch.from_numpy(show_image)
114
  show_image = rearrange(show_image, '(n h) (m w) c -> (n m) h w c', n=3, m=2)
115
  show_image = rearrange(show_image, '(n m) h w c -> (n h) (m w) c', n=2, m=3)
116
  show_image = Image.fromarray(show_image.numpy())
 
118
  return z123_image, show_image
119
 
120
 
121
+ def make3d(images, model, is_flexicubes, infer_config):
122
+ device = torch.device('cuda')
123
 
124
+ if is_flexicubes:
 
125
  model.init_flexicubes_geometry(device, use_renderer=False)
126
  model = model.eval()
127
 
128
  images = np.asarray(images, dtype=np.float32) / 255.0
129
+ images = torch.from_numpy(images).permute(2, 0, 1).contiguous().float()
130
+ images = rearrange(images, 'c (n h) (m w) -> (n m) c h w', n=3, m=2)
131
 
132
  input_cameras = get_zero123plus_input_cameras(batch_size=1, radius=4.0).to(device)
133
+ render_cameras = get_render_cameras(batch_size=1, radius=2.5, is_flexicubes=is_flexicubes).to(device)
134
 
135
  images = images.unsqueeze(0).to(device)
136
  images = v2.functional.resize(images, (320, 320), interpolation=3, antialias=True).clamp(0, 1)
137
 
138
  mesh_fpath = tempfile.NamedTemporaryFile(suffix=f".obj", delete=False).name
 
139
  mesh_basename = os.path.basename(mesh_fpath).split('.')[0]
140
  mesh_dirname = os.path.dirname(mesh_fpath)
 
141
  mesh_glb_fpath = os.path.join(mesh_dirname, f"{mesh_basename}.glb")
142
 
143
  with torch.no_grad():
 
144
  planes = model.forward_planes(images, input_cameras)
145
+ mesh_out = model.extract_mesh(planes, use_texture_map=False, **infer_config)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
  vertices, faces, vertex_colors = mesh_out
148
  vertices = vertices[:, [1, 2, 0]]
149
+
150
  save_glb(vertices, faces, vertex_colors, mesh_glb_fpath)
151
  save_obj(vertices, faces, vertex_colors, mesh_fpath)
 
 
152
 
153
  return mesh_fpath, mesh_glb_fpath
154
 
155
 
156
+ def launch_demo(config_path):
157
+ cuda_path = find_cuda()
158
+ if cuda_path:
159
+ print(f"CUDA installation found at: {cuda_path}")
160
+ else:
161
+ print("CUDA installation not found")
162
+
163
+ pipeline, model, is_flexicubes, infer_config = load_models(config_path)
164
+
165
+ with gr.Blocks() as demo:
166
+ with gr.Row(variant="panel"):
167
+ with gr.Column():
168
+ with gr.Row():
169
+ input_image = gr.Image(
170
+ label="Input Image",
171
+ image_mode="RGBA",
172
+ sources="upload",
173
+ type="pil",
174
+ elem_id="content_image",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  )
176
+ processed_image = gr.Image(
177
+ label="Processed Image",
178
+ image_mode="RGBA",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  type="pil",
 
180
  interactive=False
181
  )
182
+ with gr.Row():
183
+ with gr.Group():
184
+ do_remove_background = gr.Checkbox(
185
+ label="Remove Background", value=True
186
+ )
187
+ sample_seed = gr.Number(
188
+ value=42, label="Seed Value", precision=0)
189
+
190
+ sample_steps = gr.Slider(
191
+ label="Sample Steps",
192
+ minimum=30,
193
+ maximum=75,
194
+ value=75,
195
+ step=5
196
+ )
197
+
198
+ with gr.Row():
199
+ submit = gr.Button(
200
+ "Generate", elem_id="generate", variant="primary")
201
+
202
+ with gr.Row(variant="panel"):
203
+ gr.Examples(
204
+ examples=[
205
+ os.path.join("examples", img_name) for img_name in sorted(os.listdir("examples"))
206
+ ],
207
+ inputs=[input_image],
208
+ label="Examples",
209
+ cache_examples=False,
210
+ examples_per_page=16
211
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
+ with gr.Column():
214
+ with gr.Row():
215
+ with gr.Column():
216
+ mv_show_images = gr.Image(
217
+ label="Generated Multi-views",
218
+ type="pil",
219
+ width=379,
220
+ interactive=False
221
+ )
222
+
223
+ with gr.Row():
224
+ with gr.Tab("OBJ"):
225
+ output_model_obj = gr.Model3D(
226
+ label="Output Model (OBJ Format)",
227
+ interactive=False,
228
+ )
229
+ gr.Markdown(
230
+ "Note: Downloaded .obj model will be flipped. Export .glb instead or manually flip it before usage.")
231
+ with gr.Tab("GLB"):
232
+ output_model_glb = gr.Model3D(
233
+ label="Output Model (GLB Format)",
234
+ interactive=False,
235
+ )
236
+ gr.Markdown(
237
+ "Note: The model shown here has a darker appearance. Download to get correct results.")
238
+
239
+ with gr.Row():
240
+ gr.Markdown(
241
+ '''Try a different <b>seed value</b> if the result is unsatisfying (Default: 42).''')
242
+
243
+ mv_images = gr.State()
244
+
245
+ submit.click(fn=check_input_image, inputs=[input_image]).success(
246
+ fn=preprocess,
247
+ inputs=[input_image, do_remove_background],
248
+ outputs=[processed_image],
249
+ ).success(
250
+ fn=generate_mvs,
251
+ inputs=[processed_image, sample_steps, sample_seed, pipeline],
252
+ outputs=[mv_images, mv_show_images]
253
+ ).success(
254
+ fn=make3d,
255
+ inputs=[mv_images, model, is_flexicubes, infer_config],
256
+ outputs=[output_model_obj, output_model_glb]
257
+ )
258
+
259
+ demo.launch()
260
+
261
+
262
+ if __name__ == "__main__":
263
+ config_path = 'configs/instant-mesh-large.yaml'
264
+ launch_demo(config_path)