Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -19,6 +19,8 @@ from trellis.utils import render_utils, postprocessing_utils
|
|
| 19 |
|
| 20 |
MAX_SEED = np.iinfo(np.int32).max
|
| 21 |
TMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp')
|
|
|
|
|
|
|
| 22 |
os.makedirs(TMP_DIR, exist_ok=True)
|
| 23 |
|
| 24 |
def start_session(req: gr.Request):
|
|
@@ -29,8 +31,6 @@ def start_session(req: gr.Request):
|
|
| 29 |
def end_session(req: gr.Request):
|
| 30 |
user_dir = os.path.join(TMP_DIR, str(req.session_hash))
|
| 31 |
shutil.rmtree(user_dir)
|
| 32 |
-
|
| 33 |
-
@spaces.GPU
|
| 34 |
def preprocess_image(image: Image.Image) -> Image.Image:
|
| 35 |
"""
|
| 36 |
Preprocess the input image for 3D generation.
|
|
@@ -48,7 +48,33 @@ def preprocess_image(image: Image.Image) -> Image.Image:
|
|
| 48 |
processed_image = pipeline.preprocess_image(image)
|
| 49 |
return processed_image
|
| 50 |
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
def preprocess_images(images: List[Tuple[Image.Image, str]]) -> List[Image.Image]:
|
| 53 |
"""
|
| 54 |
Preprocess a list of input images for multi-image 3D generation.
|
|
@@ -124,7 +150,7 @@ def get_seed(randomize_seed: bool, seed: int) -> int:
|
|
| 124 |
return np.random.randint(0, MAX_SEED) if randomize_seed else seed
|
| 125 |
|
| 126 |
|
| 127 |
-
@spaces.GPU
|
| 128 |
def generate_and_extract_glb(
|
| 129 |
multiimages: List[Tuple[Image.Image, str]],
|
| 130 |
seed: int,
|
|
@@ -264,13 +290,31 @@ def split_image(image: Image.Image) -> List[Image.Image]:
|
|
| 264 |
images.append(Image.fromarray(image[:, s:e+1]))
|
| 265 |
return [preprocess_image(image) for image in images]
|
| 266 |
|
| 267 |
-
|
| 268 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 269 |
gr.Markdown("""
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 274 |
|
| 275 |
✨This demo is partial. We will release the whole model later. Stay tuned!✨
|
| 276 |
""")
|
|
@@ -278,11 +322,14 @@ with gr.Blocks(delete_cache=(600, 600)) as demo:
|
|
| 278 |
with gr.Row():
|
| 279 |
with gr.Column():
|
| 280 |
with gr.Tabs() as input_tabs:
|
| 281 |
-
with gr.Tab(label="
|
|
|
|
| 282 |
image_prompt = gr.Image(label="Image Prompt", format="png", visible=False, image_mode="RGBA", type="pil", height=300)
|
| 283 |
multiimage_prompt = gr.Gallery(label="Image Prompt", format="png", type="pil", height=300, columns=3)
|
| 284 |
gr.Markdown("""
|
| 285 |
Input different views of the object in separate images.
|
|
|
|
|
|
|
| 286 |
""")
|
| 287 |
|
| 288 |
with gr.Accordion(label="Generation Settings", open=False):
|
|
@@ -333,6 +380,11 @@ with gr.Blocks(delete_cache=(600, 600)) as demo:
|
|
| 333 |
demo.load(start_session)
|
| 334 |
demo.unload(end_session)
|
| 335 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 336 |
|
| 337 |
multiimage_prompt.upload(
|
| 338 |
preprocess_images,
|
|
@@ -345,10 +397,6 @@ with gr.Blocks(delete_cache=(600, 600)) as demo:
|
|
| 345 |
inputs=[randomize_seed, seed],
|
| 346 |
outputs=[seed],
|
| 347 |
).then(
|
| 348 |
-
# lambda: [None, None, None, None], # 先清空 video_output
|
| 349 |
-
# inputs=[],
|
| 350 |
-
# outputs=[video_output, model_output, download_glb, download_gs],
|
| 351 |
-
# ).then(
|
| 352 |
generate_and_extract_glb,
|
| 353 |
inputs=[multiimage_prompt, seed, ss_guidance_strength, ss_sampling_steps, slat_guidance_strength, slat_sampling_steps, multiimage_algo, mesh_simplify, texture_size],
|
| 354 |
outputs=[output_buf, video_output, model_output, download_glb],
|
|
|
|
| 19 |
|
| 20 |
MAX_SEED = np.iinfo(np.int32).max
|
| 21 |
TMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp')
|
| 22 |
+
# TMP_DIR = "tmp/Trellis-demo"
|
| 23 |
+
# os.environ['GRADIO_TEMP_DIR'] = 'tmp'
|
| 24 |
os.makedirs(TMP_DIR, exist_ok=True)
|
| 25 |
|
| 26 |
def start_session(req: gr.Request):
|
|
|
|
| 31 |
def end_session(req: gr.Request):
|
| 32 |
user_dir = os.path.join(TMP_DIR, str(req.session_hash))
|
| 33 |
shutil.rmtree(user_dir)
|
|
|
|
|
|
|
| 34 |
def preprocess_image(image: Image.Image) -> Image.Image:
|
| 35 |
"""
|
| 36 |
Preprocess the input image for 3D generation.
|
|
|
|
| 48 |
processed_image = pipeline.preprocess_image(image)
|
| 49 |
return processed_image
|
| 50 |
|
| 51 |
+
def preprocess_videos(video: str) -> List[Tuple[Image.Image, str]]:
|
| 52 |
+
"""
|
| 53 |
+
Preprocess the input video for multi-image 3D generation.
|
| 54 |
+
|
| 55 |
+
This function is called when a user uploads a video.
|
| 56 |
+
It extracts frames from the video and processes each frame to prepare them
|
| 57 |
+
for the multi-image 3D generation pipeline.
|
| 58 |
+
|
| 59 |
+
Args:
|
| 60 |
+
video (str): The path to the input video file
|
| 61 |
+
|
| 62 |
+
Returns:
|
| 63 |
+
List[Tuple[Image.Image, str]]: The list of preprocessed images ready for 3D generation
|
| 64 |
+
"""
|
| 65 |
+
vid = imageio.get_reader(video, 'ffmpeg')
|
| 66 |
+
fps = vid.get_meta_data()['fps']
|
| 67 |
+
images = []
|
| 68 |
+
for i, frame in enumerate(vid):
|
| 69 |
+
if i % max(int(fps * 1), 1) == 0:
|
| 70 |
+
img = Image.fromarray(frame)
|
| 71 |
+
W, H = img.size
|
| 72 |
+
img = img.resize((int(W / H * 512), 512))
|
| 73 |
+
images.append(img)
|
| 74 |
+
vid.close()
|
| 75 |
+
processed_images = [pipeline.preprocess_image(image) for image in images]
|
| 76 |
+
return processed_images
|
| 77 |
+
|
| 78 |
def preprocess_images(images: List[Tuple[Image.Image, str]]) -> List[Image.Image]:
|
| 79 |
"""
|
| 80 |
Preprocess a list of input images for multi-image 3D generation.
|
|
|
|
| 150 |
return np.random.randint(0, MAX_SEED) if randomize_seed else seed
|
| 151 |
|
| 152 |
|
| 153 |
+
@spaces.GPU(duration=120)
|
| 154 |
def generate_and_extract_glb(
|
| 155 |
multiimages: List[Tuple[Image.Image, str]],
|
| 156 |
seed: int,
|
|
|
|
| 290 |
images.append(Image.fromarray(image[:, s:e+1]))
|
| 291 |
return [preprocess_image(image) for image in images]
|
| 292 |
|
| 293 |
+
# Create interface
|
| 294 |
+
demo = gr.Blocks(
|
| 295 |
+
title="ReconViaGen",
|
| 296 |
+
css="""
|
| 297 |
+
.slider .inner { width: 5px; background: #FFF; }
|
| 298 |
+
.viewport { aspect-ratio: 4/3; }
|
| 299 |
+
.tabs button.selected { font-size: 20px !important; color: crimson !important; }
|
| 300 |
+
h1, h2, h3 { text-align: center; display: block; }
|
| 301 |
+
.md_feedback li { margin-bottom: 0px !important; }
|
| 302 |
+
"""
|
| 303 |
+
)
|
| 304 |
+
with demo:
|
| 305 |
gr.Markdown("""
|
| 306 |
+
# 💻 ReconViaGen
|
| 307 |
+
<p align="center">
|
| 308 |
+
<a title="Github" href="https://github.com/GAP-LAB-CUHK-SZ/ReconViaGen" target="_blank" rel="noopener noreferrer" style="display: inline-block;">
|
| 309 |
+
<img src="https://img.shields.io/github/stars/GAP-LAB-CUHK-SZ/ReconViaGen?label=GitHub%20%E2%98%85&logo=github&color=C8C" alt="badge-github-stars">
|
| 310 |
+
</a>
|
| 311 |
+
<a title="Website" href="https://jiahao620.github.io/reconviagen/" target="_blank" rel="noopener noreferrer" style="display: inline-block;">
|
| 312 |
+
<img src="https://www.obukhov.ai/img/badges/badge-website.svg">
|
| 313 |
+
</a>
|
| 314 |
+
<a title="arXiv" href="https://jiahao620.github.io/reconviagen/" target="_blank" rel="noopener noreferrer" style="display: inline-block;">
|
| 315 |
+
<img src="https://www.obukhov.ai/img/badges/badge-pdf.svg">
|
| 316 |
+
</a>
|
| 317 |
+
</p>
|
| 318 |
|
| 319 |
✨This demo is partial. We will release the whole model later. Stay tuned!✨
|
| 320 |
""")
|
|
|
|
| 322 |
with gr.Row():
|
| 323 |
with gr.Column():
|
| 324 |
with gr.Tabs() as input_tabs:
|
| 325 |
+
with gr.Tab(label="Input Video or Images", id=0) as multiimage_input_tab:
|
| 326 |
+
input_video = gr.Video(label="Upload Video", interactive=True, height=300)
|
| 327 |
image_prompt = gr.Image(label="Image Prompt", format="png", visible=False, image_mode="RGBA", type="pil", height=300)
|
| 328 |
multiimage_prompt = gr.Gallery(label="Image Prompt", format="png", type="pil", height=300, columns=3)
|
| 329 |
gr.Markdown("""
|
| 330 |
Input different views of the object in separate images.
|
| 331 |
+
|
| 332 |
+
*NOTE: this is an experimental algorithm without training a specialized model. It may not produce the best results for all images, especially those having different poses or inconsistent details.*
|
| 333 |
""")
|
| 334 |
|
| 335 |
with gr.Accordion(label="Generation Settings", open=False):
|
|
|
|
| 380 |
demo.load(start_session)
|
| 381 |
demo.unload(end_session)
|
| 382 |
|
| 383 |
+
input_video.upload(
|
| 384 |
+
preprocess_videos,
|
| 385 |
+
inputs=[input_video],
|
| 386 |
+
outputs=[multiimage_prompt],
|
| 387 |
+
)
|
| 388 |
|
| 389 |
multiimage_prompt.upload(
|
| 390 |
preprocess_images,
|
|
|
|
| 397 |
inputs=[randomize_seed, seed],
|
| 398 |
outputs=[seed],
|
| 399 |
).then(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 400 |
generate_and_extract_glb,
|
| 401 |
inputs=[multiimage_prompt, seed, ss_guidance_strength, ss_sampling_steps, slat_guidance_strength, slat_sampling_steps, multiimage_algo, mesh_simplify, texture_size],
|
| 402 |
outputs=[output_buf, video_output, model_output, download_glb],
|