CoolFace
Apppublic

rusandy/TRELLIS

sourceHugging Facemitupdated 2y agoView on Hugging Face
0likes
app.py282 linesDownload Raw Back to root
1import gradio as gr2import spaces3from gradio_litmodel3d import LitModel3D4 5import os6import shutil7os.environ['SPCONV_ALGO'] = 'native'8from typing import *9import torch10import numpy as np11import imageio12import uuid13from easydict import EasyDict as edict14from PIL import Image15from trellis.pipelines import TrellisImageTo3DPipeline16from trellis.representations import Gaussian, MeshExtractResult17from trellis.utils import render_utils, postprocessing_utils18 19 20MAX_SEED = np.iinfo(np.int32).max21TMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp')22os.makedirs(TMP_DIR, exist_ok=True)23 24 25def start_session(req: gr.Request):26    user_dir = os.path.join(TMP_DIR, str(req.session_hash))27    print(f'Creating user directory: {user_dir}')28    os.makedirs(user_dir, exist_ok=True)29    30    31def end_session(req: gr.Request):32    user_dir = os.path.join(TMP_DIR, str(req.session_hash))33    print(f'Removing user directory: {user_dir}')34    shutil.rmtree(user_dir)35 36 37def preprocess_image(image: Image.Image) -> Tuple[str, Image.Image]:38    """39    Preprocess the input image.40 41    Args:42        image (Image.Image): The input image.43 44    Returns:45        str: uuid of the trial.46        Image.Image: The preprocessed image.47    """48    processed_image = pipeline.preprocess_image(image)49    return processed_image50 51 52def pack_state(gs: Gaussian, mesh: MeshExtractResult, trial_id: str) -> dict:53    return {54        'gaussian': {55            **gs.init_params,56            '_xyz': gs._xyz.cpu().numpy(),57            '_features_dc': gs._features_dc.cpu().numpy(),58            '_scaling': gs._scaling.cpu().numpy(),59            '_rotation': gs._rotation.cpu().numpy(),60            '_opacity': gs._opacity.cpu().numpy(),61        },62        'mesh': {63            'vertices': mesh.vertices.cpu().numpy(),64            'faces': mesh.faces.cpu().numpy(),65        },66        'trial_id': trial_id,67    }68    69    70def unpack_state(state: dict) -> Tuple[Gaussian, edict, str]:71    gs = Gaussian(72        aabb=state['gaussian']['aabb'],73        sh_degree=state['gaussian']['sh_degree'],74        mininum_kernel_size=state['gaussian']['mininum_kernel_size'],75        scaling_bias=state['gaussian']['scaling_bias'],76        opacity_bias=state['gaussian']['opacity_bias'],77        scaling_activation=state['gaussian']['scaling_activation'],78    )79    gs._xyz = torch.tensor(state['gaussian']['_xyz'], device='cuda')80    gs._features_dc = torch.tensor(state['gaussian']['_features_dc'], device='cuda')81    gs._scaling = torch.tensor(state['gaussian']['_scaling'], device='cuda')82    gs._rotation = torch.tensor(state['gaussian']['_rotation'], device='cuda')83    gs._opacity = torch.tensor(state['gaussian']['_opacity'], device='cuda')84    85    mesh = edict(86        vertices=torch.tensor(state['mesh']['vertices'], device='cuda'),87        faces=torch.tensor(state['mesh']['faces'], device='cuda'),88    )89    90    return gs, mesh, state['trial_id']91 92 93def get_seed(randomize_seed: bool, seed: int) -> int:94    """95    Get the random seed.96    """97    return np.random.randint(0, MAX_SEED) if randomize_seed else seed98 99 100@spaces.GPU101def image_to_3d(102    image: Image.Image,103    seed: int,104    ss_guidance_strength: float,105    ss_sampling_steps: int,106    slat_guidance_strength: float,107    slat_sampling_steps: int,108    req: gr.Request,109) -> Tuple[dict, str]:110    """111    Convert an image to a 3D model.112 113    Args:114        image (Image.Image): The input image.115        seed (int): The random seed.116        ss_guidance_strength (float): The guidance strength for sparse structure generation.117        ss_sampling_steps (int): The number of sampling steps for sparse structure generation.118        slat_guidance_strength (float): The guidance strength for structured latent generation.119        slat_sampling_steps (int): The number of sampling steps for structured latent generation.120 121    Returns:122        dict: The information of the generated 3D model.123        str: The path to the video of the 3D model.124    """125    user_dir = os.path.join(TMP_DIR, str(req.session_hash))126    outputs = pipeline.run(127        image,128        seed=seed,129        formats=["gaussian", "mesh"],130        preprocess_image=False,131        sparse_structure_sampler_params={132            "steps": ss_sampling_steps,133            "cfg_strength": ss_guidance_strength,134        },135        slat_sampler_params={136            "steps": slat_sampling_steps,137            "cfg_strength": slat_guidance_strength,138        },139    )140    video = render_utils.render_video(outputs['gaussian'][0], num_frames=120)['color']141    video_geo = render_utils.render_video(outputs['mesh'][0], num_frames=120)['normal']142    video = [np.concatenate([video[i], video_geo[i]], axis=1) for i in range(len(video))]143    trial_id = uuid.uuid4()144    video_path = os.path.join(user_dir, f"{trial_id}.mp4")145    imageio.mimsave(video_path, video, fps=15)146    state = pack_state(outputs['gaussian'][0], outputs['mesh'][0], trial_id)147    torch.cuda.empty_cache()148    return state, video_path149 150 151@spaces.GPU152def extract_glb(153    state: dict,154    mesh_simplify: float,155    texture_size: int,156    req: gr.Request,157) -> Tuple[str, str]:158    """159    Extract a GLB file from the 3D model.160 161    Args:162        state (dict): The state of the generated 3D model.163        mesh_simplify (float): The mesh simplification factor.164        texture_size (int): The texture resolution.165 166    Returns:167        str: The path to the extracted GLB file.168    """169    user_dir = os.path.join(TMP_DIR, str(req.session_hash))170    gs, mesh, trial_id = unpack_state(state)171    glb = postprocessing_utils.to_glb(gs, mesh, simplify=mesh_simplify, texture_size=texture_size, verbose=False)172    glb_path = os.path.join(user_dir, f"{trial_id}.glb")173    glb.export(glb_path)174    torch.cuda.empty_cache()175    return glb_path, glb_path176 177 178with gr.Blocks(delete_cache=(600, 600)) as demo:179    gr.Markdown("""180    ## Image to 3D Asset with [TRELLIS](https://trellis3d.github.io/)181    * Upload an image and click "Generate" to create a 3D asset. If the image has alpha channel, it be used as the mask. Otherwise, we use `rembg` to remove the background.182    * If you find the generated 3D asset satisfactory, click "Extract GLB" to extract the GLB file and download it.183    """)184    185    with gr.Row():186        with gr.Column():187            image_prompt = gr.Image(label="Image Prompt", format="png", image_mode="RGBA", type="pil", height=300)188            189            with gr.Accordion(label="Generation Settings", open=False):190                seed = gr.Slider(0, MAX_SEED, label="Seed", value=0, step=1)191                randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)192                gr.Markdown("Stage 1: Sparse Structure Generation")193                with gr.Row():194                    ss_guidance_strength = gr.Slider(0.0, 10.0, label="Guidance Strength", value=7.5, step=0.1)195                    ss_sampling_steps = gr.Slider(1, 50, label="Sampling Steps", value=12, step=1)196                gr.Markdown("Stage 2: Structured Latent Generation")197                with gr.Row():198                    slat_guidance_strength = gr.Slider(0.0, 10.0, label="Guidance Strength", value=3.0, step=0.1)199                    slat_sampling_steps = gr.Slider(1, 50, label="Sampling Steps", value=12, step=1)200 201            generate_btn = gr.Button("Generate")202            203            with gr.Accordion(label="GLB Extraction Settings", open=False):204                mesh_simplify = gr.Slider(0.9, 0.98, label="Simplify", value=0.95, step=0.01)205                texture_size = gr.Slider(512, 2048, label="Texture Size", value=1024, step=512)206            207            extract_glb_btn = gr.Button("Extract GLB", interactive=False)208 209        with gr.Column():210            video_output = gr.Video(label="Generated 3D Asset", autoplay=True, loop=True, height=300)211            model_output = LitModel3D(label="Extracted GLB", exposure=20.0, height=300)212            download_glb = gr.DownloadButton(label="Download GLB", interactive=False)213            214    output_buf = gr.State()215 216    # Example images at the bottom of the page217    with gr.Row():218        examples = gr.Examples(219            examples=[220                f'assets/example_image/{image}'221                for image in os.listdir("assets/example_image")222            ],223            inputs=[image_prompt],224            fn=preprocess_image,225            outputs=[image_prompt],226            run_on_click=True,227            examples_per_page=64,228        )229 230    # Handlers231    demo.load(start_session)232    demo.unload(end_session)233    234    image_prompt.upload(235        preprocess_image,236        inputs=[image_prompt],237        outputs=[image_prompt],238    )239 240    generate_btn.click(241        get_seed,242        inputs=[randomize_seed, seed],243        outputs=[seed],244    ).then(245        image_to_3d,246        inputs=[image_prompt, seed, ss_guidance_strength, ss_sampling_steps, slat_guidance_strength, slat_sampling_steps],247        outputs=[output_buf, video_output],248    ).then(249        lambda: gr.Button(interactive=True),250        outputs=[extract_glb_btn],251    )252 253    video_output.clear(254        lambda: gr.Button(interactive=False),255        outputs=[extract_glb_btn],256    )257 258    extract_glb_btn.click(259        extract_glb,260        inputs=[output_buf, mesh_simplify, texture_size],261        outputs=[model_output, download_glb],262    ).then(263        lambda: gr.Button(interactive=True),264        outputs=[download_glb],265    )266 267    model_output.clear(268        lambda: gr.Button(interactive=False),269        outputs=[download_glb],270    )271    272 273# Launch the Gradio app274if __name__ == "__main__":275    pipeline = TrellisImageTo3DPipeline.from_pretrained("JeffreyXiang/TRELLIS-image-large")276    pipeline.cuda()277    try:278        pipeline.preprocess_image(Image.fromarray(np.zeros((512, 512, 3), dtype=np.uint8)))    # Preload rembg279    except:280        pass281    demo.launch()282