Spaces:
Running
on
Zero
Running
on
Zero
update the code of gradio
Browse files- gradio_app.py +78 -38
gradio_app.py
CHANGED
@@ -4,18 +4,16 @@ import os
|
|
4 |
import json
|
5 |
import torch
|
6 |
import sys
|
7 |
-
import
|
8 |
-
import importlib
|
9 |
import numpy as np
|
10 |
-
from omegaconf import OmegaConf
|
11 |
from huggingface_hub import hf_hub_download
|
12 |
-
from diffusers import DiffusionPipeline
|
13 |
|
14 |
import PIL
|
15 |
from PIL import Image
|
16 |
from collections import OrderedDict
|
17 |
import trimesh
|
18 |
import rembg
|
|
|
19 |
import gradio as gr
|
20 |
from typing import Any
|
21 |
|
@@ -50,7 +48,7 @@ _CITE_ = r"""
|
|
50 |
If you find our work useful for your research or applications, please cite using this bibtex:
|
51 |
```bibtex
|
52 |
@article{li2024craftsman,
|
53 |
-
author = {Weiyu Li and Jiarui Liu and Rui Chen and Yixun Liang and Xuelin Chen and Ping Tan and Xiaoxiao Long},
|
54 |
title = {CraftsMan: High-fidelity Mesh Generation with 3D Native Generation and Interactive Geometry Refiner},
|
55 |
journal = {arXiv preprint arXiv:2405.14979},
|
56 |
year = {2024},
|
@@ -67,7 +65,6 @@ If you have any questions, feel free to open a discussion or contact us at <b>we
|
|
67 |
model = None
|
68 |
cached_dir = None
|
69 |
|
70 |
-
|
71 |
def check_input_image(input_image):
|
72 |
if input_image is None:
|
73 |
raise gr.Error("No image uploaded!")
|
@@ -87,7 +84,7 @@ class RMBG(object):
|
|
87 |
if image.mode == "RGBA" and image.getextrema()[3][0] < 255:
|
88 |
# explain why current do not rm bg
|
89 |
print("alhpa channl not enpty, skip remove background, using alpha channel as mask")
|
90 |
-
background = Image.new("RGBA", image.size, background_color)
|
91 |
image = Image.alpha_composite(background, image)
|
92 |
do_remove = False
|
93 |
do_remove = do_remove or force
|
@@ -97,11 +94,11 @@ class RMBG(object):
|
|
97 |
# calculate the min bbox of the image
|
98 |
alpha = image.split()[-1]
|
99 |
image = image.crop(alpha.getbbox())
|
100 |
-
|
101 |
return image
|
102 |
return _rembg_remove(input_image, None, force_remove=True)
|
103 |
|
104 |
-
def run(self, rm_type,
|
|
|
105 |
if "Original" in background_choice:
|
106 |
return image
|
107 |
else:
|
@@ -120,7 +117,7 @@ class RMBG(object):
|
|
120 |
# Resize the image while maintaining the aspect ratio
|
121 |
resized_image = image.resize(new_size)
|
122 |
# Create a new image with the original size and white background
|
123 |
-
padded_image = PIL.Image.new("RGBA", image.size, (
|
124 |
paste_position = ((image.width - resized_image.width) // 2, (image.height - resized_image.height) // 2)
|
125 |
padded_image.paste(resized_image, paste_position)
|
126 |
|
@@ -129,24 +126,29 @@ class RMBG(object):
|
|
129 |
if width == height:
|
130 |
return padded_image
|
131 |
new_size = (max(width, height), max(width, height))
|
132 |
-
image = PIL.Image.new("RGBA", new_size, (
|
133 |
paste_position = ((new_size[0] - width) // 2, (new_size[1] - height) // 2)
|
134 |
image.paste(padded_image, paste_position)
|
135 |
-
|
|
|
|
|
136 |
|
137 |
-
@spaces.GPU
|
138 |
def image2mesh(image: Any,
|
139 |
more: bool = False,
|
140 |
scheluder_name: str ="DDIMScheduler",
|
141 |
guidance_scale: int = 7.5,
|
142 |
-
steps: int =
|
143 |
seed: int = 4,
|
144 |
target_face_count: int = 2000,
|
145 |
octree_depth: int = 7):
|
146 |
|
|
|
|
|
|
|
147 |
sample_inputs = {
|
148 |
"image": [
|
149 |
-
|
150 |
]
|
151 |
}
|
152 |
|
@@ -169,7 +171,7 @@ def image2mesh(image: Any,
|
|
169 |
assert len(mesh_outputs) == 1, "Only support single mesh output for gradio demo"
|
170 |
mesh = trimesh.Trimesh(mesh_outputs[0][0], mesh_outputs[0][1])
|
171 |
# filepath = f"{cached_dir}/{time.time()}.obj"
|
172 |
-
filepath = tempfile.NamedTemporaryFile(suffix=f".
|
173 |
mesh.export(filepath, include_normals=True)
|
174 |
|
175 |
if 'Remesh' in more:
|
@@ -181,6 +183,30 @@ def image2mesh(image: Any,
|
|
181 |
|
182 |
return filepath
|
183 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
184 |
if __name__=="__main__":
|
185 |
parser = argparse.ArgumentParser()
|
186 |
parser.add_argument("--model_path", type=str, default="", help="Path to the object file",)
|
@@ -238,39 +264,23 @@ if __name__=="__main__":
|
|
238 |
label="Image Input",
|
239 |
image_mode="RGBA",
|
240 |
sources="upload",
|
241 |
-
type="
|
242 |
)
|
243 |
run_btn = gr.Button('Generate', variant='primary', interactive=True)
|
244 |
|
245 |
with gr.Row():
|
246 |
gr.Markdown('''Try a different <b>seed and MV Model</b> for better results. Good Luck :)''')
|
247 |
with gr.Row():
|
248 |
-
seed = gr.Number(
|
249 |
more = gr.CheckboxGroup(["Remesh"], label="More", show_label=False)
|
250 |
target_face_count = gr.Number(2000, label='Target Face Count', show_label=True)
|
251 |
|
252 |
-
with gr.Row():
|
253 |
-
gr.Examples(
|
254 |
-
examples=[os.path.join("./examples", i) for i in os.listdir("./examples")],
|
255 |
-
inputs=[image_input],
|
256 |
-
examples_per_page=8
|
257 |
-
)
|
258 |
|
259 |
-
with gr.Column(scale=4):
|
260 |
-
with gr.Row():
|
261 |
-
output_model_obj = gr.Model3D(
|
262 |
-
label="Output Model (OBJ Format)",
|
263 |
-
camera_position=(90.0, 90.0, 3.5),
|
264 |
-
interactive=False,
|
265 |
-
)
|
266 |
-
with gr.Row():
|
267 |
-
gr.Markdown('''*please note that the model is fliped due to the gradio viewer, please download the obj file and you will get the correct orientation.''')
|
268 |
-
|
269 |
with gr.Accordion('Advanced options', open=False):
|
270 |
with gr.Row():
|
271 |
background_choice = gr.Dropdown(label="Backgroud Choice", value="Auto Remove Background",choices=list(background_choice.keys()))
|
272 |
rmbg_type = gr.Dropdown(label="Backgroud Remove Type", value="rembg",choices=['sam', "rembg"])
|
273 |
-
foreground_ratio = gr.Slider(label="Foreground Ratio", value=
|
274 |
|
275 |
with gr.Row():
|
276 |
guidance_scale = gr.Number(label="3D Guidance Scale", value=7.5, minimum=3.0, maximum=10.0)
|
@@ -279,10 +289,34 @@ if __name__=="__main__":
|
|
279 |
with gr.Row():
|
280 |
scheduler = gr.Dropdown(label="scheluder", value="DDIMScheduler",choices=list(scheluder_dict.keys()))
|
281 |
octree_depth = gr.Slider(label="Octree Depth", value=7, minimum=4, maximum=8, step=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
282 |
|
283 |
gr.Markdown(_CITE_)
|
284 |
|
285 |
-
outputs = [output_model_obj]
|
|
|
286 |
rmbg = RMBG()
|
287 |
|
288 |
# model = load_model(ckpt_path, config_path, device)
|
@@ -304,7 +338,13 @@ if __name__=="__main__":
|
|
304 |
).success(
|
305 |
fn=image2mesh,
|
306 |
inputs=[image_input, more, scheduler, guidance_scale, steps, seed, target_face_count, octree_depth],
|
307 |
-
outputs=
|
308 |
-
api_name="generate_img2obj"
|
|
|
|
|
|
|
|
|
|
|
|
|
309 |
|
310 |
demo.queue().launch(share=True, allowed_paths=[args.cached_dir])
|
|
|
4 |
import json
|
5 |
import torch
|
6 |
import sys
|
7 |
+
import base64
|
|
|
8 |
import numpy as np
|
|
|
9 |
from huggingface_hub import hf_hub_download
|
|
|
10 |
|
11 |
import PIL
|
12 |
from PIL import Image
|
13 |
from collections import OrderedDict
|
14 |
import trimesh
|
15 |
import rembg
|
16 |
+
import requests
|
17 |
import gradio as gr
|
18 |
from typing import Any
|
19 |
|
|
|
48 |
If you find our work useful for your research or applications, please cite using this bibtex:
|
49 |
```bibtex
|
50 |
@article{li2024craftsman,
|
51 |
+
author = {Weiyu Li and Jiarui Liu and Hongyu Yan and Rui Chen and Yixun Liang and Xuelin Chen and Ping Tan and Xiaoxiao Long},
|
52 |
title = {CraftsMan: High-fidelity Mesh Generation with 3D Native Generation and Interactive Geometry Refiner},
|
53 |
journal = {arXiv preprint arXiv:2405.14979},
|
54 |
year = {2024},
|
|
|
65 |
model = None
|
66 |
cached_dir = None
|
67 |
|
|
|
68 |
def check_input_image(input_image):
|
69 |
if input_image is None:
|
70 |
raise gr.Error("No image uploaded!")
|
|
|
84 |
if image.mode == "RGBA" and image.getextrema()[3][0] < 255:
|
85 |
# explain why current do not rm bg
|
86 |
print("alhpa channl not enpty, skip remove background, using alpha channel as mask")
|
87 |
+
background = Image.new("RGBA", image.size, (*background_color, 0))
|
88 |
image = Image.alpha_composite(background, image)
|
89 |
do_remove = False
|
90 |
do_remove = do_remove or force
|
|
|
94 |
# calculate the min bbox of the image
|
95 |
alpha = image.split()[-1]
|
96 |
image = image.crop(alpha.getbbox())
|
|
|
97 |
return image
|
98 |
return _rembg_remove(input_image, None, force_remove=True)
|
99 |
|
100 |
+
def run(self, rm_type, image_file, foreground_ratio, background_choice, background_color=(255, 255, 255)):
|
101 |
+
image = Image.open(image_file)
|
102 |
if "Original" in background_choice:
|
103 |
return image
|
104 |
else:
|
|
|
117 |
# Resize the image while maintaining the aspect ratio
|
118 |
resized_image = image.resize(new_size)
|
119 |
# Create a new image with the original size and white background
|
120 |
+
padded_image = PIL.Image.new("RGBA", image.size, (*background_color, 0))
|
121 |
paste_position = ((image.width - resized_image.width) // 2, (image.height - resized_image.height) // 2)
|
122 |
padded_image.paste(resized_image, paste_position)
|
123 |
|
|
|
126 |
if width == height:
|
127 |
return padded_image
|
128 |
new_size = (max(width, height), max(width, height))
|
129 |
+
image = PIL.Image.new("RGBA", new_size, (*background_color, 1))
|
130 |
paste_position = ((new_size[0] - width) // 2, (new_size[1] - height) // 2)
|
131 |
image.paste(padded_image, paste_position)
|
132 |
+
filepath = tempfile.NamedTemporaryFile(suffix=f".png", delete=False).name
|
133 |
+
image.save(filepath)
|
134 |
+
return filepath
|
135 |
|
136 |
+
# @spaces.GPU
|
137 |
def image2mesh(image: Any,
|
138 |
more: bool = False,
|
139 |
scheluder_name: str ="DDIMScheduler",
|
140 |
guidance_scale: int = 7.5,
|
141 |
+
steps: int = 50,
|
142 |
seed: int = 4,
|
143 |
target_face_count: int = 2000,
|
144 |
octree_depth: int = 7):
|
145 |
|
146 |
+
# global rmbg
|
147 |
+
# processed_image = rmbg.run(rm_type, image, foreground_ratio, background_choice)
|
148 |
+
processed_image = Image.open(image)
|
149 |
sample_inputs = {
|
150 |
"image": [
|
151 |
+
processed_image
|
152 |
]
|
153 |
}
|
154 |
|
|
|
171 |
assert len(mesh_outputs) == 1, "Only support single mesh output for gradio demo"
|
172 |
mesh = trimesh.Trimesh(mesh_outputs[0][0], mesh_outputs[0][1])
|
173 |
# filepath = f"{cached_dir}/{time.time()}.obj"
|
174 |
+
filepath = tempfile.NamedTemporaryFile(suffix=f".glb", delete=False).name
|
175 |
mesh.export(filepath, include_normals=True)
|
176 |
|
177 |
if 'Remesh' in more:
|
|
|
183 |
|
184 |
return filepath
|
185 |
|
186 |
+
def mesh2texture(mesh_file, image_file):
|
187 |
+
headers = {'Content-Type': 'application/json'}
|
188 |
+
server_url = "114.249.238.184:34119"
|
189 |
+
with open(image_file, 'rb') as f:
|
190 |
+
image_bytes = f.read()
|
191 |
+
with open(mesh_file, 'rb') as f:
|
192 |
+
mesh_bytes = f.read()
|
193 |
+
request = {
|
194 |
+
'png_base64_image': base64.b64encode(image_bytes).decode('utf-8'),
|
195 |
+
'glb_base64_mesh': base64.b64encode(mesh_bytes).decode('utf-8'),
|
196 |
+
}
|
197 |
+
response = requests.post(
|
198 |
+
url=f"http://{server_url}/generate_texture",
|
199 |
+
headers=headers,
|
200 |
+
data=json.dumps(request),
|
201 |
+
).json()
|
202 |
+
mesh_bytes = base64.b64decode(response['glb_base64_mesh'])
|
203 |
+
filepath = tempfile.NamedTemporaryFile(suffix=f".glb", delete=False).name
|
204 |
+
with open(filepath, 'wb') as f:
|
205 |
+
f.write(mesh_bytes)
|
206 |
+
|
207 |
+
return filepath
|
208 |
+
|
209 |
+
|
210 |
if __name__=="__main__":
|
211 |
parser = argparse.ArgumentParser()
|
212 |
parser.add_argument("--model_path", type=str, default="", help="Path to the object file",)
|
|
|
264 |
label="Image Input",
|
265 |
image_mode="RGBA",
|
266 |
sources="upload",
|
267 |
+
type="filepath",
|
268 |
)
|
269 |
run_btn = gr.Button('Generate', variant='primary', interactive=True)
|
270 |
|
271 |
with gr.Row():
|
272 |
gr.Markdown('''Try a different <b>seed and MV Model</b> for better results. Good Luck :)''')
|
273 |
with gr.Row():
|
274 |
+
seed = gr.Number(42, label='Seed', show_label=True)
|
275 |
more = gr.CheckboxGroup(["Remesh"], label="More", show_label=False)
|
276 |
target_face_count = gr.Number(2000, label='Target Face Count', show_label=True)
|
277 |
|
|
|
|
|
|
|
|
|
|
|
|
|
278 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
with gr.Accordion('Advanced options', open=False):
|
280 |
with gr.Row():
|
281 |
background_choice = gr.Dropdown(label="Backgroud Choice", value="Auto Remove Background",choices=list(background_choice.keys()))
|
282 |
rmbg_type = gr.Dropdown(label="Backgroud Remove Type", value="rembg",choices=['sam', "rembg"])
|
283 |
+
foreground_ratio = gr.Slider(label="Foreground Ratio", value=0.95, minimum=0.5, maximum=1.0, step=0.01)
|
284 |
|
285 |
with gr.Row():
|
286 |
guidance_scale = gr.Number(label="3D Guidance Scale", value=7.5, minimum=3.0, maximum=10.0)
|
|
|
289 |
with gr.Row():
|
290 |
scheduler = gr.Dropdown(label="scheluder", value="DDIMScheduler",choices=list(scheluder_dict.keys()))
|
291 |
octree_depth = gr.Slider(label="Octree Depth", value=7, minimum=4, maximum=8, step=1)
|
292 |
+
|
293 |
+
with gr.Row():
|
294 |
+
gr.Examples(
|
295 |
+
examples=[os.path.join("./assets/examples", i) for i in os.listdir("./assets/examples")],
|
296 |
+
inputs=[image_input],
|
297 |
+
examples_per_page=8
|
298 |
+
)
|
299 |
+
|
300 |
+
with gr.Column(scale=4):
|
301 |
+
with gr.Row():
|
302 |
+
output_model_obj = gr.Model3D(
|
303 |
+
label="Output Model (GLB Format)",
|
304 |
+
camera_position=(90.0, 90.0, 3.5),
|
305 |
+
interactive=False,
|
306 |
+
)
|
307 |
+
with gr.Row():
|
308 |
+
output_model_tex = gr.Model3D(
|
309 |
+
label="Output Textured Model (GLB Format)",
|
310 |
+
camera_position=(90.0, 90.0, 3.5),
|
311 |
+
interactive=False,
|
312 |
+
)
|
313 |
+
# with gr.Row():
|
314 |
+
# gr.Markdown('''*please note that the model is fliped due to the gradio viewer, please download the obj file and you will get the correct orientation.''')
|
315 |
|
316 |
gr.Markdown(_CITE_)
|
317 |
|
318 |
+
# outputs = [output_model_obj]
|
319 |
+
# outputs_tex = [output_model_tex]
|
320 |
rmbg = RMBG()
|
321 |
|
322 |
# model = load_model(ckpt_path, config_path, device)
|
|
|
338 |
).success(
|
339 |
fn=image2mesh,
|
340 |
inputs=[image_input, more, scheduler, guidance_scale, steps, seed, target_face_count, octree_depth],
|
341 |
+
outputs=[output_model_obj],
|
342 |
+
api_name="generate_img2obj"
|
343 |
+
).success(
|
344 |
+
fn=mesh2texture,
|
345 |
+
inputs=[output_model_obj, image_input],
|
346 |
+
outputs=[output_model_tex],
|
347 |
+
api_name="generate_obj2tex"
|
348 |
+
)
|
349 |
|
350 |
demo.queue().launch(share=True, allowed_paths=[args.cached_dir])
|