wyysf commited on
Commit
02d09e5
β€’
1 Parent(s): f6849c0
apps/__pycache__/mv_models.cpython-38.pyc CHANGED
Binary files a/apps/__pycache__/mv_models.cpython-38.pyc and b/apps/__pycache__/mv_models.cpython-38.pyc differ
 
apps/examples/toy1.webp DELETED
Binary file (13.8 kB)
 
apps/mv_models.py CHANGED
@@ -54,6 +54,8 @@ class GenMVImage(object):
54
 
55
  @spaces.GPU
56
  def gen_image_from_mvdream(self, image, text):
 
 
57
  from .third_party.mvdream_diffusers.pipeline_mvdream import MVDreamPipeline
58
  if image is None:
59
  if "mvdream" in self.pipelines.keys():
 
54
 
55
  @spaces.GPU
56
  def gen_image_from_mvdream(self, image, text):
57
+ sys.path.append(f"{parent_dir}/apps/third_party/mvdream_diffusers")
58
+
59
  from .third_party.mvdream_diffusers.pipeline_mvdream import MVDreamPipeline
60
  if image is None:
61
  if "mvdream" in self.pipelines.keys():
gradio_app copy.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spaces
2
+ import argparse
3
+ import os
4
+ import json
5
+ import torch
6
+ import sys
7
+ import time
8
+ import importlib
9
+ import numpy as np
10
+ from omegaconf import OmegaConf
11
+ from huggingface_hub import hf_hub_download
12
+
13
+ from collections import OrderedDict
14
+ import trimesh
15
+ from einops import repeat, rearrange
16
+ import pytorch_lightning as pl
17
+ from typing import Dict, Optional, Tuple, List
18
+ import gradio as gr
19
+
20
+ proj_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
21
+ sys.path.append(os.path.join(proj_dir))
22
+
23
+ import tempfile
24
+ import craftsman
25
+ from craftsman.systems.base import BaseSystem
26
+ from craftsman.utils.config import ExperimentConfig, load_config
27
+
28
+ from apps.utils import *
29
+ from apps.mv_models import GenMVImage
30
+
31
+ _TITLE = '''CraftsMan: High-fidelity Mesh Generation with 3D Native Generation and Interactive Geometry Refiner'''
32
+ _DESCRIPTION = '''
33
+ <div>
34
+ Select or upload a image, then just click 'Generate'.
35
+ <br>
36
+ By mimicking the artist/craftsman modeling workflow, we propose CraftsMan (aka εŒ εΏƒ) that uses 3D Latent Set Diffusion Model that directly generate coarse meshes,
37
+ then a multi-view normal enhanced image generation model is used to refine the mesh.
38
+ We provide the coarse 3D diffusion part here.
39
+ <br>
40
+ If you found Crafts is helpful, please help to ⭐ the <a href='https://github.com/wyysf-98/CraftsMan/' target='_blank'>Github Repo</a>. Thanks!
41
+ <a style="display:inline-block; margin-left: .5em" href='https://github.com/wyysf-98/CraftsMan/'><img src='https://img.shields.io/github/stars/wyysf-98/CraftsMan?style=social' /></a>
42
+ <br>
43
+ *please note that the model is fliped due to the gradio viewer, please download the obj file and you will get the correct mesh.
44
+ <br>
45
+ *If you have your own multi-view images, you can directly upload it.
46
+ </div>
47
+ '''
48
+ _CITE_ = r"""
49
+ ---
50
+ πŸ“ **Citation**
51
+ If you find our work useful for your research or applications, please cite using this bibtex:
52
+ ```bibtex
53
+ @article{craftsman,
54
+ author = {Weiyu Li and Jiarui Liu and Rui Chen and Yixun Liang and Xuelin Chen and Ping Tan and Xiaoxiao Long},
55
+ title = {CraftsMan: High-fidelity Mesh Generation with 3D Native Generation and Interactive Geometry Refiner},
56
+ journal = {arxiv:xxx},
57
+ year = {2024},
58
+ }
59
+ ```
60
+ πŸ€— **Acknowledgements**
61
+ We use <a href='https://github.com/wjakob/instant-meshes' target='_blank'>Instant Meshes</a> to remesh the generated mesh to a lower face count, thanks to the authors for the great work.
62
+ πŸ“‹ **License**
63
+ CraftsMan is under [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.en.html), so any downstream solution and products (including cloud services) that include CraftsMan code or a trained model (both pretrained or custom trained) inside it should be open-sourced to comply with the AGPL conditions. If you have any questions about the usage of CraftsMan, please contact us first.
64
+ πŸ“§ **Contact**
65
+ If you have any questions, feel free to open a discussion or contact us at <b>weiyuli.cn@gmail.com</b>.
66
+ """
67
+
68
+ model = None
69
+ cached_dir = None
70
+
71
+ @spaces.GPU
72
+ def image2mesh(view_front: np.ndarray,
73
+ view_right: np.ndarray,
74
+ view_back: np.ndarray,
75
+ view_left: np.ndarray,
76
+ more: bool = False,
77
+ scheluder_name: str ="DDIMScheduler",
78
+ guidance_scale: int = 7.5,
79
+ seed: int = 4,
80
+ octree_depth: int = 7):
81
+
82
+ sample_inputs = {
83
+ "mvimages": [[
84
+ Image.fromarray(view_front),
85
+ Image.fromarray(view_right),
86
+ Image.fromarray(view_back),
87
+ Image.fromarray(view_left)
88
+ ]]
89
+ }
90
+
91
+ global model
92
+ latents = model.sample(
93
+ sample_inputs,
94
+ sample_times=1,
95
+ guidance_scale=guidance_scale,
96
+ return_intermediates=False,
97
+ seed=seed
98
+
99
+ )[0]
100
+
101
+ # decode the latents to mesh
102
+ box_v = 1.1
103
+ mesh_outputs, _ = model.shape_model.extract_geometry(
104
+ latents,
105
+ bounds=[-box_v, -box_v, -box_v, box_v, box_v, box_v],
106
+ octree_depth=octree_depth
107
+ )
108
+ assert len(mesh_outputs) == 1, "Only support single mesh output for gradio demo"
109
+ mesh = trimesh.Trimesh(mesh_outputs[0][0], mesh_outputs[0][1])
110
+ # filepath = f"{cached_dir}/{time.time()}.obj"
111
+ filepath = tempfile.NamedTemporaryFile(suffix=f".obj", delete=False).name
112
+ mesh.export(filepath, include_normals=True)
113
+
114
+ if 'Remesh' in more:
115
+ remeshed_filepath = tempfile.NamedTemporaryFile(suffix=f"_remeshed.obj", delete=False).name
116
+ print("Remeshing with Instant Meshes...")
117
+ # target_face_count = int(len(mesh.faces)/10)
118
+ target_face_count = 1000
119
+ command = f"{proj_dir}/apps/third_party/InstantMeshes {filepath} -f {target_face_count} -o {remeshed_filepath}"
120
+ os.system(command)
121
+ filepath = remeshed_filepath
122
+ # filepath = filepath.replace('.obj', '_remeshed.obj')
123
+
124
+ return filepath
125
+
126
+ if __name__=="__main__":
127
+ parser = argparse.ArgumentParser()
128
+ # parser.add_argument("--model_path", type=str, required=True, help="Path to the object file",)
129
+ parser.add_argument("--cached_dir", type=str, default="./gradio_cached_dir")
130
+ parser.add_argument("--device", type=int, default=0)
131
+ args = parser.parse_args()
132
+
133
+ cached_dir = args.cached_dir
134
+ os.makedirs(args.cached_dir, exist_ok=True)
135
+ device = torch.device(f"cuda:{args.device}" if torch.cuda.is_available() else "cpu")
136
+ print(f"using device: {device}")
137
+
138
+ # for multi-view images generation
139
+ background_choice = OrderedDict({
140
+ "Alpha as Mask": "Alpha as Mask",
141
+ "Auto Remove Background": "Auto Remove Background",
142
+ "Original Image": "Original Image",
143
+ })
144
+ # mvimg_model_config_list = ["CRM"]
145
+ mvimg_model_config_list = ["CRM", "ImageDream", "Wonder3D"]
146
+
147
+ # for 3D latent set diffusion
148
+ ckpt_path = hf_hub_download(repo_id="wyysf/CraftsMan", filename="image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6/model.ckpt", repo_type="model")
149
+ config_path = hf_hub_download(repo_id="wyysf/CraftsMan", filename="image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6/config.yaml", repo_type="model")
150
+ scheluder_dict = OrderedDict({
151
+ "DDIMScheduler": 'diffusers.schedulers.DDIMScheduler',
152
+ # "DPMSolverMultistepScheduler": 'diffusers.schedulers.DPMSolverMultistepScheduler', # not support yet
153
+ # "UniPCMultistepScheduler": 'diffusers.schedulers.UniPCMultistepScheduler', # not support yet
154
+ })
155
+
156
+ # main GUI
157
+ custom_theme = gr.themes.Soft(primary_hue="blue").set(
158
+ button_secondary_background_fill="*neutral_100",
159
+ button_secondary_background_fill_hover="*neutral_200")
160
+ custom_css = '''#disp_image {
161
+ text-align: center; /* Horizontally center the content */
162
+ }'''
163
+
164
+ with gr.Blocks(title=_TITLE, theme=custom_theme, css=custom_css) as demo:
165
+ with gr.Row():
166
+ with gr.Column(scale=1):
167
+ gr.Markdown('# ' + _TITLE)
168
+ gr.Markdown(_DESCRIPTION)
169
+
170
+ with gr.Row():
171
+ with gr.Column(scale=2):
172
+ with gr.Row():
173
+ image_input = gr.Image(
174
+ label="Image Input",
175
+ image_mode="RGBA",
176
+ sources="upload",
177
+ type="pil",
178
+ )
179
+ with gr.Row():
180
+ text = gr.Textbox(label="Prompt (Optional, only works for mvdream)", visible=False)
181
+ with gr.Row():
182
+ gr.Markdown('''Try a different <b>seed</b> if the result is unsatisfying. Good Luck :)''')
183
+ with gr.Row():
184
+ seed = gr.Number(42, label='Seed', show_label=True)
185
+ more = gr.CheckboxGroup(["Remesh", "Symmetry(TBD)"], label="More", show_label=False)
186
+ # remesh = gr.Checkbox(value=False, label='Remesh')
187
+ # symmetry = gr.Checkbox(value=False, label='Symmetry(TBD)', interactive=False)
188
+ run_btn = gr.Button('Generate', variant='primary', interactive=True)
189
+
190
+ with gr.Row():
191
+ gr.Examples(
192
+ examples=[os.path.join("./apps/examples", i) for i in os.listdir("./apps/examples")],
193
+ inputs=[image_input],
194
+ examples_per_page=8
195
+ )
196
+
197
+ with gr.Column(scale=4):
198
+ with gr.Row():
199
+ output_model_obj = gr.Model3D(
200
+ label="Output Model (OBJ Format)",
201
+ camera_position=(90.0, 90.0, 3.5),
202
+ interactive=False,
203
+ )
204
+
205
+ with gr.Row():
206
+ view_front = gr.Image(label="Front", interactive=True, show_label=True)
207
+ view_right = gr.Image(label="Right", interactive=True, show_label=True)
208
+ view_back = gr.Image(label="Back", interactive=True, show_label=True)
209
+ view_left = gr.Image(label="Left", interactive=True, show_label=True)
210
+
211
+ # with gr.Accordion('Advanced options', open=False):
212
+ with gr.Row(equal_height=True):
213
+ run_mv_btn = gr.Button('Only Generate 2D', interactive=True)
214
+ run_3d_btn = gr.Button('Only Generate 3D', interactive=True)
215
+
216
+ with gr.Accordion('Advanced options (2D)', open=False):
217
+ with gr.Row():
218
+ crop_size = gr.Number(224, label='Crop size')
219
+ mvimg_model = gr.Dropdown(value="CRM", label="MV Image Model", choices=mvimg_model_config_list)
220
+
221
+ with gr.Row():
222
+ foreground_ratio = gr.Slider(
223
+ label="Foreground Ratio",
224
+ minimum=0.5,
225
+ maximum=1.0,
226
+ value=1.0,
227
+ step=0.05,
228
+ )
229
+
230
+ with gr.Row():
231
+ background_choice = gr.Dropdown(label="Backgroud Choice", value="Auto Remove Background",choices=list(background_choice.keys()))
232
+ rmbg_type = gr.Dropdown(label="Backgroud Remove Type", value="rembg",choices=['sam', "rembg"])
233
+ backgroud_color = gr.ColorPicker(label="Background Color", value="#FFFFFF", interactive=True)
234
+
235
+ with gr.Row():
236
+ mvimg_guidance_scale = gr.Number(value=3.5, minimum=3, maximum=10, label="2D Guidance Scale")
237
+ mvimg_steps = gr.Number(value=30, minimum=20, maximum=100, label="2D Sample Steps", precision=0)
238
+
239
+ with gr.Accordion('Advanced options (3D)', open=False):
240
+ with gr.Row():
241
+ guidance_scale = gr.Number(label="3D Guidance Scale", value=7.5, minimum=3.0, maximum=10.0)
242
+ steps = gr.Number(value=50, minimum=20, maximum=100, label="3D Sample Steps", precision=0)
243
+
244
+ with gr.Row():
245
+ scheduler = gr.Dropdown(label="scheluder", value="DDIMScheduler",choices=list(scheluder_dict.keys()))
246
+ octree_depth = gr.Slider(label="Octree Depth", value=7, minimum=4, maximum=8, step=1)
247
+
248
+ gr.Markdown(_CITE_)
249
+
250
+ outputs = [output_model_obj]
251
+ rmbg = RMBG(device)
252
+
253
+ gen_mvimg = GenMVImage(device)
254
+ model = load_model(ckpt_path, config_path, device)
255
+
256
+ run_btn.click(fn=check_input_image, inputs=[image_input]
257
+ ).success(
258
+ fn=rmbg.run,
259
+ inputs=[rmbg_type, image_input, crop_size, foreground_ratio, background_choice, backgroud_color],
260
+ outputs=[image_input]
261
+ ).success(
262
+ fn=gen_mvimg.run,
263
+ inputs=[mvimg_model, text, image_input, crop_size, seed, mvimg_guidance_scale, mvimg_steps],
264
+ outputs=[view_front, view_right, view_back, view_left]
265
+ ).success(
266
+ fn=image2mesh,
267
+ inputs=[view_front, view_right, view_back, view_left, more, scheduler, guidance_scale, seed, octree_depth],
268
+ outputs=outputs,
269
+ api_name="generate_img2obj")
270
+ run_mv_btn.click(fn=gen_mvimg.run,
271
+ inputs=[mvimg_model, text, image_input, crop_size, seed, mvimg_guidance_scale, mvimg_steps],
272
+ outputs=[view_front, view_right, view_back, view_left]
273
+ )
274
+ run_3d_btn.click(fn=image2mesh,
275
+ inputs=[view_front, view_right, view_back, view_left, more, scheduler, guidance_scale, seed, octree_depth],
276
+ outputs=outputs,
277
+ api_name="generate_img2obj")
278
+
279
+ demo.queue().launch(share=True, allowed_paths=[args.cached_dir])
gradio_app.py CHANGED
@@ -64,9 +64,26 @@ CraftsMan is under [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.en.html), so
64
  πŸ“§ **Contact**
65
  If you have any questions, feel free to open a discussion or contact us at <b>weiyuli.cn@gmail.com</b>.
66
  """
 
67
 
68
  model = None
69
  cached_dir = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
  @spaces.GPU
72
  def image2mesh(view_front: np.ndarray,
@@ -134,7 +151,14 @@ if __name__=="__main__":
134
  os.makedirs(args.cached_dir, exist_ok=True)
135
  device = torch.device(f"cuda:{args.device}" if torch.cuda.is_available() else "cpu")
136
  print(f"using device: {device}")
137
-
 
 
 
 
 
 
 
138
  # for multi-view images generation
139
  background_choice = OrderedDict({
140
  "Alpha as Mask": "Alpha as Mask",
@@ -250,7 +274,7 @@ if __name__=="__main__":
250
  outputs = [output_model_obj]
251
  rmbg = RMBG(device)
252
 
253
- gen_mvimg = GenMVImage(device)
254
  model = load_model(ckpt_path, config_path, device)
255
 
256
  run_btn.click(fn=check_input_image, inputs=[image_input]
@@ -259,7 +283,7 @@ if __name__=="__main__":
259
  inputs=[rmbg_type, image_input, crop_size, foreground_ratio, background_choice, backgroud_color],
260
  outputs=[image_input]
261
  ).success(
262
- fn=gen_mvimg.run,
263
  inputs=[mvimg_model, text, image_input, crop_size, seed, mvimg_guidance_scale, mvimg_steps],
264
  outputs=[view_front, view_right, view_back, view_left]
265
  ).success(
@@ -267,7 +291,7 @@ if __name__=="__main__":
267
  inputs=[view_front, view_right, view_back, view_left, more, scheduler, guidance_scale, seed, octree_depth],
268
  outputs=outputs,
269
  api_name="generate_img2obj")
270
- run_mv_btn.click(fn=gen_mvimg.run,
271
  inputs=[mvimg_model, text, image_input, crop_size, seed, mvimg_guidance_scale, mvimg_steps],
272
  outputs=[view_front, view_right, view_back, view_left]
273
  )
 
64
  πŸ“§ **Contact**
65
  If you have any questions, feel free to open a discussion or contact us at <b>weiyuli.cn@gmail.com</b>.
66
  """
67
+ from apps.third_party.CRM.pipelines import TwoStagePipeline
68
 
69
  model = None
70
  cached_dir = None
71
+ stage1_config = OmegaConf.load(f"{parent_dir}/apps/third_party/CRM/configs/nf7_v3_SNR_rd_size_stroke.yaml").config
72
+ stage1_sampler_config = stage1_config.sampler
73
+ stage1_model_config = stage1_config.models
74
+ stage1_model_config.resume = hf_hub_download(repo_id="Zhengyi/CRM", filename="pixel-diffusion.pth", repo_type="model")
75
+ stage1_model_config.config = f"{parent_dir}/apps/third_party/CRM/" + stage1_model_config.config
76
+ crm_pipeline = None
77
+
78
+ @spaces.GPU
79
+ def gen_mvimg(
80
+ mvimg_model, text, image, crop_size, seed, guidance_scale, step
81
+ ):
82
+ global crm_pipeline
83
+ crm_pipeline.set_seed(seed)
84
+ rt_dict = crm_pipeline(image, scale=guidance_scale, step=step)
85
+ mv_imgs = rt_dict["stage1_images"]
86
+ return mv_imgs[5], mv_imgs[3], mv_imgs[2], mv_imgs[0]
87
 
88
  @spaces.GPU
89
  def image2mesh(view_front: np.ndarray,
 
151
  os.makedirs(args.cached_dir, exist_ok=True)
152
  device = torch.device(f"cuda:{args.device}" if torch.cuda.is_available() else "cpu")
153
  print(f"using device: {device}")
154
+
155
+ crm_pipeline = TwoStagePipeline(
156
+ stage1_model_config,
157
+ stage1_sampler_config,
158
+ device=device,
159
+ dtype=torch.float16
160
+ )
161
+
162
  # for multi-view images generation
163
  background_choice = OrderedDict({
164
  "Alpha as Mask": "Alpha as Mask",
 
274
  outputs = [output_model_obj]
275
  rmbg = RMBG(device)
276
 
277
+ # gen_mvimg = GenMVImage(device)
278
  model = load_model(ckpt_path, config_path, device)
279
 
280
  run_btn.click(fn=check_input_image, inputs=[image_input]
 
283
  inputs=[rmbg_type, image_input, crop_size, foreground_ratio, background_choice, backgroud_color],
284
  outputs=[image_input]
285
  ).success(
286
+ fn=gen_mvimg,
287
  inputs=[mvimg_model, text, image_input, crop_size, seed, mvimg_guidance_scale, mvimg_steps],
288
  outputs=[view_front, view_right, view_back, view_left]
289
  ).success(
 
291
  inputs=[view_front, view_right, view_back, view_left, more, scheduler, guidance_scale, seed, octree_depth],
292
  outputs=outputs,
293
  api_name="generate_img2obj")
294
+ run_mv_btn.click(fn=gen_mvimg,
295
  inputs=[mvimg_model, text, image_input, crop_size, seed, mvimg_guidance_scale, mvimg_steps],
296
  outputs=[view_front, view_right, view_back, view_left]
297
  )