File size: 11,348 Bytes
084ab29
823d579
084ab29
 
823d579
084ab29
 
 
 
 
 
 
 
 
55c9d69
823d579
084ab29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
823d579
 
 
 
 
084ab29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
823d579
084ab29
 
823d579
 
 
084ab29
823d579
 
 
084ab29
 
 
a4ac72c
 
823d579
084ab29
823d579
 
 
6a23860
823d579
 
f286cb8
823d579
 
 
 
084ab29
823d579
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
084ab29
823d579
 
 
 
 
 
a4ac72c
 
 
084ab29
a4ac72c
823d579
 
a4ac72c
823d579
 
 
 
a4ac72c
 
 
823d579
a4ac72c
823d579
a4ac72c
 
 
 
 
 
 
084ab29
 
a4ac72c
 
084ab29
 
 
 
 
 
 
 
 
 
823d579
 
 
 
 
 
 
 
084ab29
 
a4ac72c
 
 
084ab29
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import gradio as gr
import os
import imageio
import numpy as np
from einops import rearrange

from demo.img_gen import img_gen
from demo.mesh_recon import mesh_reconstruction
from demo.relighting_gen import relighting_gen
from demo.render_hints import render_hint_images_btn_func
from demo.rm_bg import rm_bg


with gr.Blocks(title="DiLightNet Demo") as demo:
    gr.Markdown("""# DiLightNet: Fine-grained Lighting Control for Diffusion-based Image Generation
                ## A demo for generating images under point/environmantal lighting using DiLightNet. For full usage (video generation & arbitary lighting condition), please refer to our [GitHub repository](https://github.com/iamNCJ/DiLightNet)""")

    with gr.Row():
        # 1. Reference Image Input / Generation
        with gr.Column(variant="panel"):
            gr.Markdown("## Step 1. Input or Generate Reference Image")
            input_image = gr.Image(height=512, width=512, label="Input Image", interactive=True)
            with gr.Accordion("Generate Image", open=False):
                with gr.Group():
                    prompt = gr.Textbox(value="", label="Prompt", lines=3, placeholder="Input prompt here")
                    with gr.Row():
                        seed = gr.Number(value=42, label="Seed", interactive=True)
                        steps = gr.Number(value=20, label="Steps", interactive=True)
                        cfg = gr.Number(value=7.5, label="CFG", interactive=True)
                        down_from_768 = gr.Checkbox(label="Downsample from 768", value=True)
                with gr.Row():
                    generate_btn = gr.Button(value="Generate")
                    generate_btn.click(fn=img_gen, inputs=[prompt, seed, steps, cfg, down_from_768], outputs=[input_image])
            gr.Examples(
                examples=[os.path.join("examples/provisional_img", i) for i in os.listdir("examples/provisional_img")],
                inputs=[input_image],
                examples_per_page = 20,
            )

        # 2. Background Removal
        with gr.Column(variant="panel"):
            gr.Markdown("## Step 2. Remove Background")
            with gr.Tab("Masked Image"):
                masked_image = gr.Image(height=512, width=512, label="Masked Image", interactive=True)
            with gr.Tab("Mask"):
                mask = gr.Image(height=512, width=512, label="Mask", interactive=False)
            use_sam = gr.Checkbox(label="Use SAM for Refinement", value=False)
            rm_bg_btn = gr.Button(value="Remove Background")
            rm_bg_btn.click(fn=rm_bg, inputs=[input_image, use_sam], outputs=[masked_image, mask])

        # 3. Depth Estimation & Mesh Reconstruction
        with gr.Column(variant="panel"):
            gr.Markdown("## Step 3. Depth Estimation & Mesh Reconstruction")
            mesh = gr.Model3D(label="Mesh Reconstruction", clear_color=(1.0, 1.0, 1.0, 1.0), interactive=True)
            with gr.Column():
                with gr.Accordion("Options", open=False):
                    with gr.Group():
                        remove_edges = gr.Checkbox(label="Remove Occlusion Edges", value=False)
                        fov = gr.Number(value=55., label="FOV", interactive=False)
                        mask_threshold = gr.Slider(value=25., label="Mask Threshold", minimum=0., maximum=255., step=1.)
                depth_estimation_btn = gr.Button(value="Estimate Depth")
                def mesh_reconstruction_wrapper(image, mask, remove_edges, mask_threshold,
                                                progress=gr.Progress(track_tqdm=True)):
                    return mesh_reconstruction(image, mask, remove_edges, None, mask_threshold)
                depth_estimation_btn.click(
                    fn=mesh_reconstruction_wrapper,
                    inputs=[input_image, mask, remove_edges, mask_threshold],
                    outputs=[mesh, fov],
                )

    with gr.Row():
        with gr.Column(variant="panel"):
            gr.Markdown("## Step 4. Render Hints")
            hint_image = gr.Image(label="Hint Image", height=512, width=512)
            res_folder_path = gr.Textbox("", visible=False)
            is_env_lighting = gr.Checkbox(label="Use Environmental Lighting", value=True, interactive=False, visible=False)
            with gr.Tab("Environmental Lighting"):
                env_map_preview = gr.Image(label="Environment Map Preview", height=256, width=512, interactive=False, show_download_button=False)
                env_map_path = gr.Text(interactive=False, visible=False, value="examples/env_map/grace.exr")
                env_rotation = gr.Slider(value=0., label="Environment Rotation", minimum=0., maximum=360., step=0.5)
                env_examples = gr.Examples(
                    examples=[[os.path.join("examples/env_map_preview", i), os.path.join("examples/env_map", i).replace("png", "exr")] for i in os.listdir("examples/env_map_preview")],
                    inputs=[env_map_preview, env_map_path],
                    examples_per_page = 20,
                )
                render_btn_env = gr.Button(value="Render Hints")

                def render_wrapper_env(mesh, fov, env_map_path, env_rotation, progress=gr.Progress(track_tqdm=True)):
                    env_map_path = os.path.abspath(env_map_path)
                    res_path = render_hint_images_btn_func(mesh, float(fov), [(0, 0, 0)], env_map=env_map_path, env_start_azi=env_rotation / 360.)
                    hint_files = [res_path + '/hint00' + mat for mat in ["_diffuse.png", "_ggx0.05.png", "_ggx0.13.png", "_ggx0.34.png"]]
                    hints = []
                    for hint_file in hint_files:
                        hint = imageio.v3.imread(hint_file)
                        hints.append(hint)
                    hints = rearrange(np.stack(hints), '(n1 n2) h w c -> (n1 h) (n2 w) c', n1=2, n2=2)
                    return hints, res_path, True
                render_btn_env.click(
                    fn=render_wrapper_env,
                    inputs=[mesh, fov, env_map_path, env_rotation],
                    outputs=[hint_image, res_folder_path, is_env_lighting]
                )

            with gr.Tab("Point Lighting"):
                pl_pos_x = gr.Slider(value=3., label="Point Light X", minimum=-5., maximum=5., step=0.01)
                pl_pos_y = gr.Slider(value=1., label="Point Light Y", minimum=-5., maximum=5., step=0.01)
                pl_pos_z = gr.Slider(value=3., label="Point Light Z", minimum=-5., maximum=5., step=0.01)
                power = gr.Slider(value=1000., label="Point Light Power", minimum=0., maximum=2000., step=1.)
                render_btn_pl = gr.Button(value="Render Hints")

                def render_wrapper_pl(mesh, fov, pl_pos_x, pl_pos_y, pl_pos_z, power,
                                progress=gr.Progress(track_tqdm=True)):
                    res_path = render_hint_images_btn_func(mesh, float(fov), [(pl_pos_x, pl_pos_y, pl_pos_z)], power)
                    hint_files = [res_path + '/hint00' + mat for mat in ["_diffuse.png", "_ggx0.05.png", "_ggx0.13.png", "_ggx0.34.png"]]
                    hints = []
                    for hint_file in hint_files:
                        hint = imageio.v3.imread(hint_file)
                        hints.append(hint)
                    hints = rearrange(np.stack(hints), '(n1 n2) h w c -> (n1 h) (n2 w) c', n1=2, n2=2)
                    return hints, res_path, False

                render_btn_pl.click(
                    fn=render_wrapper_pl,
                    inputs=[mesh, fov, pl_pos_x, pl_pos_y, pl_pos_z, power],
                    outputs=[hint_image, res_folder_path, is_env_lighting]
                )

        with gr.Column(variant="panel"):
            gr.Markdown("## Step 5. Control Lighting!")
            res_image = gr.Image(label="Result Image", height=512, width=512)
            with gr.Group():
                relighting_prompt = gr.Textbox(value="", label="Appearance Text Prompt", lines=3,
                                                placeholder="Input prompt here",
                                                interactive=True)
                # several example prompts
                with gr.Row():
                    metallic_prompt_btn = gr.Button(value="Metallic", size="sm")
                    specular_prompt_btn = gr.Button(value="Specular", size="sm")
                    very_specular_prompt_btn = gr.Button(value="Very Specular", size="sm")
                metallic_prompt_btn.click(fn=lambda x: x + " metallic", inputs=[relighting_prompt], outputs=[relighting_prompt])
                specular_prompt_btn.click(fn=lambda x: x + " specular", inputs=[relighting_prompt], outputs=[relighting_prompt])
                very_specular_prompt_btn.click(fn=lambda x: x + " very specular", inputs=[relighting_prompt], outputs=[relighting_prompt])
                with gr.Row():
                    clear_prompt_btn = gr.Button(value="Clear")
                    reuse_btn = gr.Button(value="Reuse Provisional Image Generation Prompt")
                clear_prompt_btn.click(fn=lambda x: "", inputs=[relighting_prompt], outputs=[relighting_prompt])
                reuse_btn.click(fn=lambda x: x, inputs=[prompt], outputs=[relighting_prompt])
            with gr.Accordion("Options", open=False):
                relighting_seed = gr.Number(value=3407, label="Seed", interactive=True)
                relighting_steps = gr.Number(value=20, label="Steps", interactive=True)
                relighting_cfg = gr.Number(value=3.0, label="CFG", interactive=True)
            relighting_generate_btn = gr.Button(value="Generate")

            def gen_relighting_image(masked_image, mask, res_folder_path, relighting_prompt, relighting_seed,
                                    relighting_steps, relighting_cfg, do_env_inpainting,
                                    progress=gr.Progress(track_tqdm=True)):
                relighting_gen(
                    masked_ref_img=masked_image,
                    mask=mask,
                    cond_path=res_folder_path,
                    frames=1,
                    prompt=relighting_prompt,
                    steps=int(relighting_steps),
                    seed=int(relighting_seed),
                    cfg=relighting_cfg
                )
                relit_img = imageio.v3.imread(res_folder_path + '/relighting00.png')
                if do_env_inpainting:
                    bg = imageio.v3.imread(res_folder_path + f'/bg00.png') / 255.
                    relit_img = relit_img / 255.
                    mask_for_bg = imageio.v3.imread(res_folder_path + '/hint00_diffuse.png')[..., -1:] / 255.
                    relit_img = relit_img * mask_for_bg + bg * (1. - mask_for_bg)
                    relit_img = (relit_img * 255).clip(0, 255).astype(np.uint8)
                return relit_img

            relighting_generate_btn.click(fn=gen_relighting_image,
                                        inputs=[masked_image, mask, res_folder_path, relighting_prompt, relighting_seed,
                                                relighting_steps, relighting_cfg, is_env_lighting],
                                        outputs=[res_image])


if __name__ == '__main__':
    demo.queue().launch(server_name="0.0.0.0", share=True)