Skip to content

Commit 8b884fa

Browse files
committed
Standalone interface (barely works)
1 parent 6b64fad commit 8b884fa

File tree

7 files changed

+173
-574
lines changed

7 files changed

+173
-574
lines changed

main.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# This launches DepthMap without the AUTOMATIC1111/stable-diffusion-webui
2+
import argparse
3+
import src.common_ui
4+
5+
if __name__ == '__main__':
6+
parser = argparse.ArgumentParser()
7+
parser.add_argument("--listen", help="Create public link")
8+
args = parser.parse_args()
9+
10+
src.common_ui.on_ui_tabs().launch(share=args.listen)

scripts/depthmap.py

Lines changed: 10 additions & 480 deletions
Large diffs are not rendered by default.

src/backbone.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,96 @@
11
# This file contains stable-duiffusion-webui stuff that the plugin relies on.
22
# Eventually, when we have a standalone interface, this will load either standalone backbone or webui backbone.
3+
try:
4+
# stable-duiffusion-webui backbone
5+
from modules.images import save_image # Should fail if not on stable-duiffusion-webui
6+
from modules.devices import torch_gc # TODO: is this really sufficient?
7+
from modules.images import get_next_sequence_number
8+
from modules.call_queue import wrap_gradio_gpu_call
9+
from modules.shared import listfiles
10+
11+
def get_opt(name, default):
12+
from modules.shared import opts
13+
14+
if hasattr(opts, name):
15+
return opts.__getattr__(name)
16+
return default
17+
18+
19+
def gather_ops():
20+
from modules.shared import cmd_opts
21+
ops = {}
22+
if get_opt('depthmap_script_boost_rmax', None) is not None:
23+
ops['boost_whole_size_threshold'] = get_opt('depthmap_script_boost_rmax', None)
24+
ops['precision'] = cmd_opts.precision
25+
ops['no_half'] = cmd_opts.no_half
26+
return ops
27+
28+
29+
def get_outpath():
30+
path = get_opt('outdir_samples', None)
31+
if path is None or len(path) == 0:
32+
path = get_opt('outdir_extras_samples', None)
33+
assert path is not None and len(path) > 0
34+
return path
35+
36+
37+
def unload_sd_model():
38+
from modules import shared, devices
39+
if shared.sd_model is not None:
40+
shared.sd_model.cond_stage_model.to(devices.cpu)
41+
shared.sd_model.first_stage_model.to(devices.cpu)
42+
43+
44+
def reload_sd_model():
45+
from modules import shared, devices
46+
if shared.sd_model is not None:
47+
shared.sd_model.cond_stage_model.to(devices.device)
48+
shared.sd_model.first_stage_model.to(devices.device)
49+
50+
def get_hide_dirs():
51+
import modules.shared
52+
return modules.shared.hide_dirs
53+
except:
54+
# Standalone backbone
55+
print("DepthMap did not detect stable-duiffusion-webui; launching with the standalone backbone.\n"
56+
"The standalone backbone is not on par with the stable-duiffusion-webui backbone.\n"
57+
"Some features may be missing or work differently.\n")
58+
59+
def save_image(image, path, basename, **kwargs):
60+
import os
61+
os.makedirs(path, exist_ok=True)
62+
fullfn = os.path.join(path, f"{get_next_sequence_number()}-{basename}.{kwargs['extension']}")
63+
image.save(fullfn, format=get_opt('samples_format', 'png'))
64+
65+
def torch_gc():
66+
# TODO: is this really sufficient?
67+
import torch
68+
if torch.cuda.is_available():
69+
with torch.cuda.device('cuda'):
70+
torch.cuda.empty_cache()
71+
torch.cuda.ipc_collect()
72+
73+
def get_next_sequence_number():
74+
# Don't really care what the number will be... As long as it is unique.
75+
from datetime import datetime, timezone
76+
import random
77+
return f"{int(datetime.now(timezone.utc).timestamp())}-{random.randint(1000,9999)}"
78+
79+
def wrap_gradio_gpu_call(f): return f # Displaying various stats is not supported
80+
81+
def listfiles(dirname):
82+
import os
83+
filenames = [os.path.join(dirname, x) for x in sorted(os.listdir(dirname)) if not x.startswith(".")]
84+
return [file for file in filenames if os.path.isfile(file)]
85+
86+
def get_opt(name, default): return default # Configuring is not supported
87+
88+
def gather_ops(): return {} # Configuring is not supported
89+
90+
def get_outpath(): return '.'
91+
92+
def unload_sd_model(): pass # Not needed
93+
94+
def reload_sd_model(): pass # Not needed
95+
96+
def get_hide_dirs(): return {} # Directories will not be hidden from traversal

src/common_ui.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ def main_ui_panel(is_depth_tab):
105105
gr.HTML("More options for generating video can be found in the Generate video tab")
106106

107107
with gr.Group():
108-
# TODO: it should be clear from the UI that the background removal does not use the model selected above
108+
# TODO: it should be clear from the UI that there is an option of the background removal
109+
# that does not use the model selected above
109110
with gr.Row():
110111
inp += "background_removal", gr.Checkbox(label="Remove background", value=False)
111112
with gr.Row(visible=False) as bgrem_options_row_1:
@@ -236,7 +237,7 @@ def on_ui_tabs():
236237
**backbone.get_hide_dirs(),
237238
placeholder="A directory on the same machine where the server is running.")
238239
inp += gr.Textbox(elem_id="depthmap_batch_output_dir", label="Output directory",
239-
**backbone.get_hide_dirs,
240+
**backbone.get_hide_dirs(),
240241
placeholder="Leave blank to save images to the default path.")
241242
gr.HTML("Files in the output directory may be overwritten.")
242243
inp += gr.Checkbox(elem_id="depthmap_batch_reuse",
@@ -273,7 +274,7 @@ def on_ui_tabs():
273274
with gr.Column():
274275
vid_html_info_x = gr.HTML()
275276
vid_html_info = gr.HTML()
276-
fn_mesh = gr.Textbox(label="Input Mesh (.ply | .obj)", **shared.hide_dirs,
277+
fn_mesh = gr.Textbox(label="Input Mesh (.ply | .obj)", **backbone.get_hide_dirs(),
277278
placeholder="A file on the same machine where "
278279
"the server is running.")
279280
with gr.Row():
@@ -377,7 +378,7 @@ def run_generate(*inputs):
377378
if depthmap_mode == '2' and depthmap_batch_output_dir != '':
378379
outpath = depthmap_batch_output_dir
379380
else:
380-
outpath = backbone.opts.outdir_samples or backbone.opts.outdir_extras_samples
381+
outpath = backbone.get_outpath()
381382

382383
if depthmap_mode == '0': # Single image
383384
if depthmap_input_image is None:
@@ -399,7 +400,7 @@ def run_generate(*inputs):
399400
inputimages.append(image)
400401
inputnames.append(os.path.splitext(img.orig_name)[0])
401402
elif depthmap_mode == '2': # Batch from Directory
402-
assert not backbone.cmd_opts.hide_ui_dir_config, '--hide-ui-dir-config option must be disabled'
403+
assert not backbone.get_opt('hide_ui_dir_config', False), '--hide-ui-dir-config option must be disabled'
403404
if depthmap_batch_input_dir == '':
404405
return [], None, None, "Please select an input directory."
405406
if depthmap_batch_input_dir == depthmap_batch_output_dir:
@@ -414,9 +415,9 @@ def run_generate(*inputs):
414415
if depthmap_batch_reuse:
415416
basename = Path(path).stem
416417
# Custom names are not used in samples directory
417-
if outpath != backbone.opts.outdir_extras_samples:
418+
if outpath != backbone.get_opt('outdir_extras_samples', None):
418419
# Possible filenames that the custom depthmaps may have
419-
name_candidates = [f'{basename}-0000.{backbone.opts.samples_format}', # current format
420+
name_candidates = [f'{basename}-0000.{backbone.get_opt("samples_format", "png")}', # current format
420421
f'{basename}.png', # human-intuitive format
421422
f'{Path(path).name}'] # human-intuitive format (worse)
422423
for fn_cand in name_candidates:
@@ -430,22 +431,22 @@ def run_generate(*inputs):
430431
inputdepthmaps_n = len([1 for x in inputdepthmaps if x is not None])
431432
print(f'{len(inputimages)} images will be processed, {inputdepthmaps_n} existing depthmaps will be reused')
432433

433-
outputs, mesh_fi, meshsimple_fi = core_generation_funnel(outpath, inputimages, inputdepthmaps, inputnames, inputs, backbone.gather_ops())
434+
outputs, fn_mesh, display_mesh = core_generation_funnel(outpath, inputimages, inputdepthmaps, inputnames, inputs, backbone.gather_ops())
434435

435436
# Saving images
436437
show_images = []
437438
for input_i, imgs in enumerate(outputs):
438439
basename = 'depthmap'
439-
if depthmap_mode == '2' and inputnames[input_i] is not None and outpath != backbone.opts.outdir_extras_samples:
440+
if depthmap_mode == '2' and inputnames[input_i] is not None and outpath != backbone.get_opt('outdir_extras_samples', None):
440441
basename = Path(inputnames[input_i]).stem
441442

442443
for image_type, image in list(imgs.items()):
443444
show_images += [image]
444445
if inputs["save_outputs"]:
445446
try:
446-
suffix = "" if image_type == "depth" else f"_{image_type}"
447+
suffix = "" if image_type == "depth" else f"{image_type}"
447448
backbone.save_image(image, path=outpath, basename=basename, seed=None,
448-
prompt=None, extension=backbone.opts.samples_format, short_filename=True,
449+
prompt=None, extension=backbone.get_opt('samples_format', 'png'), short_filename=True,
449450
no_prompt=True, grid=False, pnginfo_section_name="extras",
450451
suffix=suffix)
451452
except Exception as e:
@@ -454,12 +455,12 @@ def run_generate(*inputs):
454455
print('Catched exception: image has wrong mode!')
455456
traceback.print_exc()
456457

458+
display_mesh = None
457459
# use inpainted 3d mesh to show in 3d model output when enabled in settings
458-
if hasattr(backbone.opts, 'depthmap_script_show_3d_inpaint') and backbone.opts.depthmap_script_show_3d_inpaint \
459-
and mesh_fi is not None and len(mesh_fi) > 0:
460-
meshsimple_fi = mesh_fi
460+
if backbone.get_opt('depthmap_script_show_3d_inpaint', True) and fn_mesh is not None and len(fn_mesh) > 0:
461+
display_mesh = fn_mesh
461462
# however, don't show 3dmodel when disabled in settings
462-
if hasattr(backbone.opts, 'depthmap_script_show_3d') and not backbone.opts.depthmap_script_show_3d:
463-
meshsimple_fi = None
463+
if not backbone.get_opt('depthmap_script_show_3d', True):
464+
display_mesh = None
464465
# TODO: return more info
465-
return show_images, mesh_fi, meshsimple_fi, 'Generated!'
466+
return show_images, fn_mesh, display_mesh, 'Generated!'

src/core.py

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
from pathlib import Path
2-
32
from PIL import Image
43

5-
from modules import shared, devices
6-
from modules.images import get_next_sequence_number
7-
from modules.shared import opts, cmd_opts
8-
94
try:
105
from tqdm import trange
116
except:
@@ -24,6 +19,7 @@
2419
from src.main import *
2520
from src.stereoimage_generation import create_stereoimages
2621
from src.depthmap_generation import ModelHolder
22+
from src import backbone
2723

2824
# 3d-photo-inpainting imports
2925
from inpaint.mesh import write_mesh, read_mesh, output_3d_photo
@@ -47,18 +43,6 @@ def convert_i16_to_rgb(image, like):
4743
return output
4844

4945

50-
def unload_sd_model():
51-
if shared.sd_model is not None:
52-
shared.sd_model.cond_stage_model.to(devices.cpu)
53-
shared.sd_model.first_stage_model.to(devices.cpu)
54-
55-
56-
def reload_sd_model():
57-
if shared.sd_model is not None:
58-
shared.sd_model.cond_stage_model.to(devices.device)
59-
shared.sd_model.first_stage_model.to(devices.device)
60-
61-
6246
def core_generation_funnel(outpath, inputimages, inputdepthmaps, inputnames, inp, ops=None):
6347
if len(inputimages) == 0 or inputimages[0] is None:
6448
return [], '', ''
@@ -97,12 +81,14 @@ def core_generation_funnel(outpath, inputimages, inputdepthmaps, inputnames, inp
9781
stereo_modes = inp["stereo_modes"]
9882
stereo_separation = inp["stereo_separation"]
9983

84+
if ops is None:
85+
ops = {}
10086
model_holder.update_settings(**ops)
10187

10288
# TODO: ideally, run_depthmap should not save meshes - that makes the function not pure
10389
print(SCRIPT_FULL_NAME)
10490

105-
unload_sd_model()
91+
backbone.unload_sd_model()
10692

10793
# TODO: this still should not be here
10894
background_removed_images = []
@@ -308,7 +294,7 @@ def core_generation_funnel(outpath, inputimages, inputdepthmaps, inputnames, inp
308294
else:
309295
raise e
310296
finally:
311-
if hasattr(opts, 'depthmap_script_keepmodels') and opts.depthmap_script_keepmodels:
297+
if backbone.get_opt('depthmap_script_keepmodels', False):
312298
model_holder.offload() # Swap to CPU memory
313299
else:
314300
if 'model' in locals():
@@ -318,7 +304,7 @@ def core_generation_funnel(outpath, inputimages, inputdepthmaps, inputnames, inp
318304
model_holder.unload_models()
319305

320306
gc.collect()
321-
devices.torch_gc()
307+
backbone.torch_gc()
322308

323309
# TODO: This should not be here
324310
mesh_fi = None
@@ -328,14 +314,14 @@ def core_generation_funnel(outpath, inputimages, inputdepthmaps, inputnames, inp
328314
except Exception as e:
329315
print(f'{str(e)}, some issue with generating inpainted mesh')
330316

331-
reload_sd_model()
317+
backbone.reload_sd_model()
332318
print("All done.\n")
333319
return generated_images, mesh_fi, meshsimple_fi
334320

335321

336322
def get_uniquefn(outpath, basename, ext):
337323
# Inefficient and may fail, maybe use unbounded binary search?
338-
basecount = get_next_sequence_number(outpath, basename)
324+
basecount = backbone.get_next_sequence_number(outpath, basename)
339325
if basecount > 0: basecount = basecount - 1
340326
fullfn = None
341327
for i in range(500):
@@ -403,10 +389,7 @@ def run_3dphoto(device, img_rgb, img_depth, inputnames, outpath, inpaint_vids, v
403389
config['repeat_inpaint_edge'] = True
404390
config['ply_fmt'] = "bin"
405391

406-
config['save_ply'] = False
407-
if hasattr(opts, 'depthmap_script_save_ply') and opts.depthmap_script_save_ply:
408-
config['save_ply'] = True
409-
392+
config['save_ply'] = backbone.get_opt('depthmap_script_save_ply', False)
410393
config['save_obj'] = True
411394

412395
if device == torch.device("cpu"):
@@ -473,7 +456,7 @@ def run_3dphoto(device, img_rgb, img_depth, inputnames, outpath, inpaint_vids, v
473456
[-0.05, -0.05, -0.05, -0.05],
474457
['dolly-zoom-in', 'zoom-in', 'circle', 'swing'], False, vid_format, vid_ssaa)
475458

476-
devices.torch_gc()
459+
backbone.torch_gc()
477460

478461
finally:
479462
del rgb_model
@@ -482,7 +465,7 @@ def run_3dphoto(device, img_rgb, img_depth, inputnames, outpath, inpaint_vids, v
482465
depth_edge_model = None
483466
del depth_feat_model
484467
depth_feat_model = None
485-
devices.torch_gc()
468+
backbone.torch_gc()
486469

487470
return mesh_fi
488471

@@ -604,9 +587,9 @@ def run_makevideo(fn_mesh, vid_numframes, vid_fps, vid_traj, vid_shift, vid_bord
604587

605588
# output path and filename mess ..
606589
basename = Path(fn_mesh).stem
607-
outpath = opts.outdir_samples or opts.outdir_extras_samples
590+
outpath = backbone.get_outpath()
608591
# unique filename
609-
basecount = get_next_sequence_number(outpath, basename)
592+
basecount = backbone.get_next_sequence_number(outpath, basename)
610593
if basecount > 0: basecount = basecount - 1
611594
fullfn = None
612595
for i in range(500):
@@ -699,9 +682,7 @@ def depth_edges_mask(depth):
699682
def create_mesh(image, depth, keep_edges=False, spherical=False):
700683
import trimesh
701684
from dzoedepth.utils.geometry import depth_to_points, create_triangles
702-
maxsize = 1024
703-
if hasattr(opts, 'depthmap_script_mesh_maxsize'):
704-
maxsize = opts.depthmap_script_mesh_maxsize
685+
maxsize = backbone.get_opt('depthmap_script_mesh_maxsize', 2048)
705686

706687
# limit the size of the input image
707688
image.thumbnail((maxsize, maxsize))

0 commit comments

Comments
 (0)