"
+ else:
+ return "(" + x[0] + ":" + str(x[1]) + ")"
+
+ value_list = [create_token_str(x) for x in value]
+ value = ",".join(value_list)
+
+ prompts_dict[key] = value
+
+ return prompts_dict
+
+ def load_prompts_dict(self, imgs, default_token):
+ prompts_path = os.path.join(self.prompts_dir, "prompts.txt")
+ if not os.path.isfile(prompts_path):
+ print(prompts_path + " not found.")
+ return {}
+
+ prompts_dict = {}
+
+ print(prompts_path + " found!!")
+ print("skip auto tagging.")
+
+ with open(prompts_path) as f:
+ raw_dict = json.load(f)
+ prev_value = default_token
+ for img in imgs:
+ key = os.path.basename(img)
+
+ if key in raw_dict:
+ prompts_dict[key] = raw_dict[key]
+ prev_value = raw_dict[key]
+ else:
+ prompts_dict[key] = prev_value
+
+ return prompts_dict
+
+ def process_images(self, p, input_img, controlnet_weight, input_img_is_preprocessed):
+ p.control_net_input_image = input_img
+ p.control_net_weight = controlnet_weight
+ if input_img_is_preprocessed:
+ p.control_net_module = "none"
+ return process_images(p)
+
+# This is where the additional processing is implemented. The parameters include
+# self, the model object "p" (a StableDiffusionProcessing class, see
+# processing.py), and the parameters returned by the ui method.
+# Custom functions can be defined here, and additional libraries can be imported
+# to be used in processing. The return value should be a Processed object, which is
+# what is returned by the process_images method.
+ def run(self, p, project_dir, generation_test, mask_mode, inpaint_area, use_depth, img2img_repeat_count, inc_seed, auto_tag_mode, add_tag_to_head, add_tag_replace_underscore, is_facecrop, face_detection_method, face_crop_resolution, max_crop_size, face_denoising_strength, face_area_magnification, enable_face_prompt, face_prompt, controlnet_weight, controlnet_weight_for_face, disable_facecrop_lpbk_last_time, use_preprocess_img):
+ args = locals()
+
+ if generation_test:
+ print("generation_test")
+ test_proj_dir = os.path.join( get_my_dir() , "generation_test_proj")
+ os.makedirs(test_proj_dir, exist_ok=True)
+ test_video_key_path = os.path.join( test_proj_dir , "video_key")
+ os.makedirs(test_video_key_path, exist_ok=True)
+ test_video_mask_path = os.path.join( test_proj_dir , "video_mask")
+ os.makedirs(test_video_mask_path, exist_ok=True)
+
+ controlnet_input_path = os.path.join(test_proj_dir, "controlnet_input")
+ if os.path.isdir(controlnet_input_path):
+ shutil.rmtree(controlnet_input_path)
+
+ remove_pngs_in_dir(test_video_key_path)
+ remove_pngs_in_dir(test_video_mask_path)
+
+ test_base_img = p.init_images[0]
+ test_mask = p.image_mask
+
+ if test_base_img:
+ test_base_img.save( os.path.join( test_video_key_path , "00001.png") )
+ if test_mask:
+ test_mask.save( os.path.join( test_video_mask_path , "00001.png") )
+
+ project_dir = test_proj_dir
+ else:
+ if not os.path.isdir(project_dir):
+ print("project_dir not found")
+ return Processed()
+
+ self.controlnet_weight = controlnet_weight
+ self.controlnet_weight_for_face = controlnet_weight_for_face
+
+ self.add_tag_replace_underscore = add_tag_replace_underscore
+ self.face_crop_resolution = face_crop_resolution
+
+ if p.seed == -1:
+ p.seed = int(random.randrange(4294967294))
+
+ if mask_mode == "Normal":
+ p.inpainting_mask_invert = 0
+ elif mask_mode == "Invert":
+ p.inpainting_mask_invert = 1
+
+ if inpaint_area in (0,1): #"Whole picture","Only masked"
+ p.inpaint_full_res = inpaint_area
+
+ is_invert_mask = False
+ if mask_mode == "Invert":
+ is_invert_mask = True
+
+ inv_path = os.path.join(project_dir, "inv")
+ if not os.path.isdir(inv_path):
+ print("project_dir/inv not found")
+ return Processed()
+
+ org_key_path = os.path.join(inv_path, "video_key")
+ img2img_key_path = os.path.join(inv_path, "img2img_key")
+ depth_path = os.path.join(inv_path, "video_key_depth")
+
+ preprocess_path = os.path.join(inv_path, "controlnet_preprocess")
+
+ controlnet_input_path = os.path.join(inv_path, "controlnet_input")
+
+ self.prompts_dir = inv_path
+ self.is_invert_mask = True
+ else:
+ org_key_path = os.path.join(project_dir, "video_key")
+ img2img_key_path = os.path.join(project_dir, "img2img_key")
+ depth_path = os.path.join(project_dir, "video_key_depth")
+
+ preprocess_path = os.path.join(project_dir, "controlnet_preprocess")
+
+ controlnet_input_path = os.path.join(project_dir, "controlnet_input")
+
+ self.prompts_dir = project_dir
+ self.is_invert_mask = False
+
+ frame_mask_path = os.path.join(project_dir, "video_mask")
+
+ if not use_depth:
+ depth_path = None
+
+ if not os.path.isdir(org_key_path):
+ print(org_key_path + " not found")
+ print("Generate key frames first." if is_invert_mask == False else \
+ "Generate key frames first.(with [Ebsynth Utility] Tab -> [configuration] -> [etc]-> [Mask Mode] = Invert setting)")
+ return Processed()
+
+ if not os.path.isdir(controlnet_input_path):
+ print(controlnet_input_path + " not found")
+ print("copy {0} -> {1}".format(org_key_path,controlnet_input_path))
+
+ os.makedirs(controlnet_input_path, exist_ok=True)
+
+ imgs = glob.glob( os.path.join(org_key_path ,"*.png") )
+ for img in imgs:
+ img_basename = os.path.basename(img)
+ shutil.copy( img , os.path.join(controlnet_input_path, img_basename) )
+
+ remove_pngs_in_dir(img2img_key_path)
+ os.makedirs(img2img_key_path, exist_ok=True)
+
+
+ def get_mask_of_img(img):
+ img_basename = os.path.basename(img)
+
+ if mask_mode != "None":
+ mask_path = os.path.join( frame_mask_path , img_basename )
+ if os.path.isfile( mask_path ):
+ return mask_path
+ return ""
+
+ def get_pair_of_img(img, target_dir):
+ img_basename = os.path.basename(img)
+
+ pair_path = os.path.join( target_dir , img_basename )
+ if os.path.isfile( pair_path ):
+ return pair_path
+ print("!!! pair of "+ img + " not in " + target_dir)
+ return ""
+
+ def get_controlnet_input_img(img):
+ pair_img = get_pair_of_img(img, controlnet_input_path)
+ if not pair_img:
+ pair_img = get_pair_of_img(img, org_key_path)
+ return pair_img
+
+ imgs = glob.glob( os.path.join(org_key_path ,"*.png") )
+ masks = [ get_mask_of_img(i) for i in imgs ]
+ controlnet_input_imgs = [ get_controlnet_input_img(i) for i in imgs ]
+
+ for mask in masks:
+ m = cv2.imread(mask) if mask else None
+ if m is not None:
+ if m.max() == 0:
+ print("{0} blank mask found".format(mask))
+ if m.ndim == 2:
+ m[0,0] = 255
+ else:
+ m = m[:,:,:3]
+ m[0,0,0:3] = 255
+ cv2.imwrite(mask, m)
+
+ ######################
+ # face crop
+ face_coords_dict={}
+ for img,mask in zip(imgs,masks):
+ face_detected = False
+ if is_facecrop:
+ image = Image.open(img)
+ mask_image = Image.open(mask) if mask else None
+ face_coords = self.detect_face(image, mask_image, face_detection_method, max_crop_size)
+ if face_coords is None or len(face_coords) == 0:
+ print("no face detected")
+ else:
+ print("face detected")
+ face_detected = True
+
+ key = os.path.basename(img)
+ face_coords_dict[key] = face_coords if face_detected else []
+
+ with open( os.path.join( project_dir if is_invert_mask == False else inv_path,"faces.txt" ), "w") as f:
+ f.write(json.dumps(face_coords_dict,indent=4))
+
+ ######################
+ # prompts
+ prompts_dict = self.load_prompts_dict(imgs, p.prompt)
+
+ if not prompts_dict:
+ if auto_tag_mode != "None":
+ prompts_dict = self.create_prompts_dict(imgs, masks, auto_tag_mode)
+
+ for key, value in prompts_dict.items():
+ prompts_dict[key] = (value + "," + p.prompt) if add_tag_to_head else (p.prompt + "," + value)
+
+ else:
+ for img in imgs:
+ key = os.path.basename(img)
+ prompts_dict[key] = p.prompt
+
+ with open( os.path.join( project_dir if is_invert_mask == False else inv_path, time.strftime("%Y%m%d-%H%M%S_") + "prompts.txt" ), "w") as f:
+ f.write(json.dumps(prompts_dict,indent=4))
+
+
+ ######################
+ # img2img
+ for img, mask, controlnet_input_img, face_coords, prompts in zip(imgs, masks, controlnet_input_imgs, face_coords_dict.values(), prompts_dict.values()):
+
+ # Generation cancelled.
+ if shared.state.interrupted:
+ print("Generation cancelled.")
+ break
+
+ image = Image.open(img)
+ mask_image = Image.open(mask) if mask else None
+
+ img_basename = os.path.basename(img)
+
+ _p = copy.copy(p)
+
+ _p.init_images=[image]
+ _p.image_mask = mask_image
+ _p.prompt = prompts
+ resized_mask = None
+
+ repeat_count = img2img_repeat_count
+
+ if mask_mode != "None" or use_depth:
+ if use_depth:
+ depth_found, _p.image_mask = self.get_depth_map( mask_image, depth_path ,img_basename, is_invert_mask )
+ mask_image = _p.image_mask
+ if depth_found:
+ _p.inpainting_mask_invert = 0
+
+ preprocess_img_exist = False
+ controlnet_input_base_img = Image.open(controlnet_input_img) if controlnet_input_img else None
+
+ if use_preprocess_img:
+ preprocess_img = os.path.join(preprocess_path, img_basename)
+ if os.path.isfile( preprocess_img ):
+ controlnet_input_base_img = Image.open(preprocess_img)
+ preprocess_img_exist = True
+
+ if face_coords:
+ controlnet_input_face_imgs, _ = self.face_img_crop(controlnet_input_base_img, face_coords, face_area_magnification)
+
+ while repeat_count > 0:
+
+ if disable_facecrop_lpbk_last_time:
+ if img2img_repeat_count > 1:
+ if repeat_count == 1:
+ face_coords = None
+
+ if face_coords:
+ proc = self.face_crop_img2img(_p, face_coords, face_denoising_strength, face_area_magnification, enable_face_prompt, face_prompt, controlnet_input_base_img, controlnet_input_face_imgs, preprocess_img_exist)
+ else:
+ proc = self.process_images(_p, controlnet_input_base_img, self.controlnet_weight, preprocess_img_exist)
+ print(proc.seed)
+
+ repeat_count -= 1
+
+ if repeat_count > 0:
+ _p.init_images=[proc.images[0]]
+
+ if mask_image is not None and resized_mask is None:
+ resized_mask = resize_img(np.array(mask_image) , proc.images[0].width, proc.images[0].height)
+ resized_mask = Image.fromarray(resized_mask)
+ _p.image_mask = resized_mask
+ _p.seed += inc_seed
+
+ proc.images[0].save( os.path.join( img2img_key_path , img_basename ) )
+
+ with open( os.path.join( project_dir if is_invert_mask == False else inv_path,"param.txt" ), "w") as f:
+ f.write(pprint.pformat(proc.info))
+ with open( os.path.join( project_dir if is_invert_mask == False else inv_path ,"args.txt" ), "w") as f:
+ f.write(pprint.pformat(args))
+
+ return proc
diff --git a/ebsynth_utility/scripts/ui.py b/ebsynth_utility/scripts/ui.py
new file mode 100644
index 0000000000000000000000000000000000000000..0fdc58bdb09ea33dbe899072be80d97ffb4d888b
--- /dev/null
+++ b/ebsynth_utility/scripts/ui.py
@@ -0,0 +1,199 @@
+
+import gradio as gr
+
+from ebsynth_utility import ebsynth_utility_process
+from modules import script_callbacks
+from modules.call_queue import wrap_gradio_gpu_call
+
+def on_ui_tabs():
+
+ with gr.Blocks(analytics_enabled=False) as ebs_interface:
+ with gr.Row().style(equal_height=False):
+ with gr.Column(variant='panel'):
+
+ with gr.Row():
+ with gr.Tabs(elem_id="ebs_settings"):
+ with gr.TabItem('project setting', elem_id='ebs_project_setting'):
+ project_dir = gr.Textbox(label='Project directory', lines=1)
+ original_movie_path = gr.Textbox(label='Original Movie Path', lines=1)
+
+ org_video = gr.Video(interactive=True, mirror_webcam=False)
+ def fn_upload_org_video(video):
+ return video
+ org_video.upload(fn_upload_org_video, org_video, original_movie_path)
+ gr.HTML(value="\
+ If you have trouble entering the video path manually, you can also use drag and drop.For large videos, please enter the path manually. \
+
")
+
+ with gr.TabItem('configuration', elem_id='ebs_configuration'):
+ with gr.Tabs(elem_id="ebs_configuration_tab"):
+ with gr.TabItem(label="stage 1",elem_id='ebs_configuration_tab1'):
+ with gr.Row():
+ frame_width = gr.Number(value=-1, label="Frame Width", precision=0, interactive=True)
+ frame_height = gr.Number(value=-1, label="Frame Height", precision=0, interactive=True)
+ gr.HTML(value="\
+ -1 means that it is calculated automatically. If both are -1, the size will be the same as the source size. \
+
")
+
+ st1_masking_method_index = gr.Radio(label='Masking Method', choices=["transparent-background","clipseg","transparent-background AND clipseg"], value="transparent-background", type="index")
+
+ with gr.Accordion(label="transparent-background options"):
+ st1_mask_threshold = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Mask Threshold', value=0.0)
+
+ # https://pypi.org/project/transparent-background/
+ gr.HTML(value="\
+ configuration for \
+ [transparent-background]\
+
")
+ tb_use_fast_mode = gr.Checkbox(label="Use Fast Mode(It will be faster, but the quality of the mask will be lower.)", value=False)
+ tb_use_jit = gr.Checkbox(label="Use Jit", value=False)
+
+ with gr.Accordion(label="clipseg options"):
+ clipseg_mask_prompt = gr.Textbox(label='Mask Target (e.g., girl, cats)', lines=1)
+ clipseg_exclude_prompt = gr.Textbox(label='Exclude Target (e.g., finger, book)', lines=1)
+ clipseg_mask_threshold = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Mask Threshold', value=0.4)
+ clipseg_mask_blur_size = gr.Slider(minimum=0, maximum=150, step=1, label='Mask Blur Kernel Size(MedianBlur)', value=11)
+ clipseg_mask_blur_size2 = gr.Slider(minimum=0, maximum=150, step=1, label='Mask Blur Kernel Size(GaussianBlur)', value=11)
+
+ with gr.TabItem(label="stage 2", elem_id='ebs_configuration_tab2'):
+ key_min_gap = gr.Slider(minimum=0, maximum=500, step=1, label='Minimum keyframe gap', value=10)
+ key_max_gap = gr.Slider(minimum=0, maximum=1000, step=1, label='Maximum keyframe gap', value=300)
+ key_th = gr.Slider(minimum=0.0, maximum=100.0, step=0.1, label='Threshold of delta frame edge', value=8.5)
+ key_add_last_frame = gr.Checkbox(label="Add last frame to keyframes", value=True)
+
+ with gr.TabItem(label="stage 3.5", elem_id='ebs_configuration_tab3_5'):
+ gr.HTML(value="\
+ [color-matcher]\
+
")
+
+ color_matcher_method = gr.Radio(label='Color Transfer Method', choices=['default', 'hm', 'reinhard', 'mvgd', 'mkl', 'hm-mvgd-hm', 'hm-mkl-hm'], value="hm-mkl-hm", type="value")
+ color_matcher_ref_type = gr.Radio(label='Color Matcher Ref Image Type', choices=['original video frame', 'first frame of img2img result'], value="original video frame", type="index")
+ gr.HTML(value="\
+ If an image is specified below, it will be used with highest priority.\
+
")
+ color_matcher_ref_image = gr.Image(label="Color Matcher Ref Image", source='upload', mirror_webcam=False, type='pil')
+ st3_5_use_mask = gr.Checkbox(label="Apply mask to the result", value=True)
+ st3_5_use_mask_ref = gr.Checkbox(label="Apply mask to the Ref Image", value=False)
+ st3_5_use_mask_org = gr.Checkbox(label="Apply mask to original image", value=False)
+ #st3_5_number_of_itr = gr.Slider(minimum=1, maximum=10, step=1, label='Number of iterations', value=1)
+
+ with gr.TabItem(label="stage 7", elem_id='ebs_configuration_tab7'):
+ blend_rate = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Crossfade blend rate', value=1.0)
+ export_type = gr.Dropdown(choices=["mp4","webm","gif","rawvideo"], value="mp4" ,label="Export type")
+
+ with gr.TabItem(label="stage 8", elem_id='ebs_configuration_tab8'):
+ bg_src = gr.Textbox(label='Background source(mp4 or directory containing images)', lines=1)
+ bg_type = gr.Dropdown(choices=["Fit video length","Loop"], value="Fit video length" ,label="Background type")
+ mask_blur_size = gr.Slider(minimum=0, maximum=150, step=1, label='Mask Blur Kernel Size', value=5)
+ mask_threshold = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Mask Threshold', value=0.0)
+ #is_transparent = gr.Checkbox(label="Is Transparent", value=True, visible = False)
+ fg_transparency = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Foreground Transparency', value=0.0)
+
+ with gr.TabItem(label="etc", elem_id='ebs_configuration_tab_etc'):
+ mask_mode = gr.Dropdown(choices=["Normal","Invert","None"], value="Normal" ,label="Mask Mode")
+
+ with gr.Column(variant='panel'):
+ with gr.Column(scale=1):
+ with gr.Group():
+ debug_info = gr.HTML(elem_id="ebs_info_area", value=".")
+
+ with gr.Column(scale=2):
+ stage_index = gr.Radio(label='Process Stage', choices=["stage 1","stage 2","stage 3","stage 3.5","stage 4","stage 5","stage 6","stage 7","stage 8"], value="stage 1", type="index")
+ gr.HTML(value="\
+ The process of creating a video can be divided into the following stages.
\
+ (Stage 3, 4, and 6 only show a guide and do nothing actual processing.)
\
+ stage 1
\
+ Extract frames from the original video.
\
+ Generate a mask image.
\
+ stage 2
\
+ Select keyframes to be given to ebsynth.
\
+ stage 3
\
+ img2img keyframes.
\
+ stage 3.5
\
+ (this is optional. Perform color correction on the img2img results and expect flickering to decrease. Or, you can simply change the color tone from the generated result.)
\
+ stage 4
\
+ and upscale to the size of the original video.
\
+ stage 5
\
+ Rename keyframes.
\
+ Generate .ebs file.(ebsynth project file)
\
+ stage 6
\
+ Running ebsynth.(on your self)
\
+ Open the generated .ebs under project directory and press [Run All] button.
\
+ If ""out-*"" directory already exists in the Project directory, delete it manually before executing.
\
+ If multiple .ebs files are generated, run them all.
\
+ stage 7
\
+ Concatenate each frame while crossfading.
\
+ Composite audio files extracted from the original video onto the concatenated video.
\
+ stage 8
\
+ This is an extra stage.
\
+ You can put any image or images or video you like in the background.
\
+ You can specify in this field -> [Ebsynth Utility]->[configuration]->[stage 8]->[Background source]
\
+ If you have already created a background video in Invert Mask Mode([Ebsynth Utility]->[configuration]->[etc]->[Mask Mode]),
\
+ You can specify \"path_to_project_dir/inv/crossfade_tmp\".
\
+
")
+
+ with gr.Row():
+ generate_btn = gr.Button('Generate', elem_id="ebs_generate_btn", variant='primary')
+
+ with gr.Group():
+ html_info = gr.HTML()
+
+
+ ebs_args = dict(
+ fn=wrap_gradio_gpu_call(ebsynth_utility_process),
+ inputs=[
+ stage_index,
+
+ project_dir,
+ original_movie_path,
+
+ frame_width,
+ frame_height,
+ st1_masking_method_index,
+ st1_mask_threshold,
+ tb_use_fast_mode,
+ tb_use_jit,
+ clipseg_mask_prompt,
+ clipseg_exclude_prompt,
+ clipseg_mask_threshold,
+ clipseg_mask_blur_size,
+ clipseg_mask_blur_size2,
+
+ key_min_gap,
+ key_max_gap,
+ key_th,
+ key_add_last_frame,
+
+ color_matcher_method,
+ st3_5_use_mask,
+ st3_5_use_mask_ref,
+ st3_5_use_mask_org,
+ color_matcher_ref_type,
+ color_matcher_ref_image,
+
+ blend_rate,
+ export_type,
+
+ bg_src,
+ bg_type,
+ mask_blur_size,
+ mask_threshold,
+ fg_transparency,
+
+ mask_mode,
+
+ ],
+ outputs=[
+ debug_info,
+ html_info,
+ ],
+ show_progress=False,
+ )
+ generate_btn.click(**ebs_args)
+
+ return (ebs_interface, "Ebsynth Utility", "ebs_interface"),
+
+
+
+script_callbacks.on_ui_tabs(on_ui_tabs)
+
diff --git a/ebsynth_utility/stage1.py b/ebsynth_utility/stage1.py
new file mode 100644
index 0000000000000000000000000000000000000000..90acf441395d6c10320b75112d28ccd0c2475e94
--- /dev/null
+++ b/ebsynth_utility/stage1.py
@@ -0,0 +1,258 @@
+import os
+import subprocess
+import glob
+import cv2
+import re
+
+from transformers import AutoProcessor, CLIPSegForImageSegmentation
+from PIL import Image
+import torch
+import numpy as np
+
+
+def resize_img(img, w, h):
+ if img.shape[0] + img.shape[1] < h + w:
+ interpolation = interpolation=cv2.INTER_CUBIC
+ else:
+ interpolation = interpolation=cv2.INTER_AREA
+
+ return cv2.resize(img, (w, h), interpolation=interpolation)
+
+def resize_all_img(path, frame_width, frame_height):
+ if not os.path.isdir(path):
+ return
+
+ pngs = glob.glob( os.path.join(path, "*.png") )
+ img = cv2.imread(pngs[0])
+ org_h,org_w = img.shape[0],img.shape[1]
+
+ if frame_width == -1 and frame_height == -1:
+ return
+ elif frame_width == -1 and frame_height != -1:
+ frame_width = int(frame_height * org_w / org_h)
+ elif frame_width != -1 and frame_height == -1:
+ frame_height = int(frame_width * org_h / org_w)
+ else:
+ pass
+ print("({0},{1}) resize to ({2},{3})".format(org_w, org_h, frame_width, frame_height))
+
+ for png in pngs:
+ img = cv2.imread(png)
+ img = resize_img(img, frame_width, frame_height)
+ cv2.imwrite(png, img)
+
+def remove_pngs_in_dir(path):
+ if not os.path.isdir(path):
+ return
+
+ pngs = glob.glob( os.path.join(path, "*.png") )
+ for png in pngs:
+ os.remove(png)
+
+def create_and_mask(mask_dir1, mask_dir2, output_dir):
+ masks = glob.glob( os.path.join(mask_dir1, "*.png") )
+
+ for mask1 in masks:
+ base_name = os.path.basename(mask1)
+ print("combine {0}".format(base_name))
+
+ mask2 = os.path.join(mask_dir2, base_name)
+ if not os.path.isfile(mask2):
+ print("{0} not found!!! -> skip".format(mask2))
+ continue
+
+ img_1 = cv2.imread(mask1)
+ img_2 = cv2.imread(mask2)
+ img_1 = np.minimum(img_1,img_2)
+
+ out_path = os.path.join(output_dir, base_name)
+ cv2.imwrite(out_path, img_1)
+
+
+def create_mask_clipseg(input_dir, output_dir, clipseg_mask_prompt, clipseg_exclude_prompt, clipseg_mask_threshold, mask_blur_size, mask_blur_size2):
+ from modules import devices
+
+ devices.torch_gc()
+
+ device = devices.get_optimal_device_name()
+
+ processor = AutoProcessor.from_pretrained("CIDAS/clipseg-rd64-refined")
+ model = CLIPSegForImageSegmentation.from_pretrained("CIDAS/clipseg-rd64-refined")
+ model.to(device)
+
+ imgs = glob.glob( os.path.join(input_dir, "*.png") )
+ texts = [x.strip() for x in clipseg_mask_prompt.split(',')]
+ exclude_texts = [x.strip() for x in clipseg_exclude_prompt.split(',')] if clipseg_exclude_prompt else None
+
+ if exclude_texts:
+ all_texts = texts + exclude_texts
+ else:
+ all_texts = texts
+
+
+ for img_count,img in enumerate(imgs):
+ image = Image.open(img)
+ base_name = os.path.basename(img)
+
+ inputs = processor(text=all_texts, images=[image] * len(all_texts), padding="max_length", return_tensors="pt")
+ inputs = inputs.to(device)
+
+ with torch.no_grad(), devices.autocast():
+ outputs = model(**inputs)
+
+ if len(all_texts) == 1:
+ preds = outputs.logits.unsqueeze(0)
+ else:
+ preds = outputs.logits
+
+ mask_img = None
+
+ for i in range(len(all_texts)):
+ x = torch.sigmoid(preds[i])
+ x = x.to('cpu').detach().numpy()
+
+# x[x < clipseg_mask_threshold] = 0
+ x = x > clipseg_mask_threshold
+
+ if i < len(texts):
+ if mask_img is None:
+ mask_img = x
+ else:
+ mask_img = np.maximum(mask_img,x)
+ else:
+ mask_img[x > 0] = 0
+
+ mask_img = mask_img*255
+ mask_img = mask_img.astype(np.uint8)
+
+ if mask_blur_size > 0:
+ mask_blur_size = mask_blur_size//2 * 2 + 1
+ mask_img = cv2.medianBlur(mask_img, mask_blur_size)
+
+ if mask_blur_size2 > 0:
+ mask_blur_size2 = mask_blur_size2//2 * 2 + 1
+ mask_img = cv2.GaussianBlur(mask_img, (mask_blur_size2, mask_blur_size2), 0)
+
+ mask_img = resize_img(mask_img, image.width, image.height)
+
+ mask_img = cv2.cvtColor(mask_img, cv2.COLOR_GRAY2RGB)
+ save_path = os.path.join(output_dir, base_name)
+ cv2.imwrite(save_path, mask_img)
+
+ print("{0} / {1}".format( img_count+1,len(imgs) ))
+
+ devices.torch_gc()
+
+
+def create_mask_transparent_background(input_dir, output_dir, tb_use_fast_mode, tb_use_jit, st1_mask_threshold):
+ fast_str = " --fast" if tb_use_fast_mode else ""
+ jit_str = " --jit" if tb_use_jit else ""
+ venv = "venv"
+ if 'VIRTUAL_ENV' in os.environ:
+ venv = os.environ['VIRTUAL_ENV']
+ bin_path = os.path.join(venv, "Scripts")
+ bin_path = os.path.join(bin_path, "transparent-background")
+
+ if os.path.isfile(bin_path) or os.path.isfile(bin_path + ".exe"):
+ subprocess.call(bin_path + " --source " + input_dir + " --dest " + output_dir + " --type map" + fast_str + jit_str, shell=True)
+ else:
+ subprocess.call("transparent-background --source " + input_dir + " --dest " + output_dir + " --type map" + fast_str + jit_str, shell=True)
+
+ mask_imgs = glob.glob( os.path.join(output_dir, "*.png") )
+
+ for m in mask_imgs:
+ img = cv2.imread(m)
+ img[img < int( 255 * st1_mask_threshold )] = 0
+ cv2.imwrite(m, img)
+
+ p = re.compile(r'([0-9]+)_[a-z]*\.png')
+
+ for mask in mask_imgs:
+ base_name = os.path.basename(mask)
+ m = p.fullmatch(base_name)
+ if m:
+ os.rename(mask, os.path.join(output_dir, m.group(1) + ".png"))
+
+def ebsynth_utility_stage1(dbg, project_args, frame_width, frame_height, st1_masking_method_index, st1_mask_threshold, tb_use_fast_mode, tb_use_jit, clipseg_mask_prompt, clipseg_exclude_prompt, clipseg_mask_threshold, clipseg_mask_blur_size, clipseg_mask_blur_size2, is_invert_mask):
+ dbg.print("stage1")
+ dbg.print("")
+
+ if st1_masking_method_index == 1 and (not clipseg_mask_prompt):
+ dbg.print("Error: clipseg_mask_prompt is Empty")
+ return
+
+ project_dir, original_movie_path, frame_path, frame_mask_path, _, _, _ = project_args
+
+ if is_invert_mask:
+ if os.path.isdir( frame_path ) and os.path.isdir( frame_mask_path ):
+ dbg.print("Skip as it appears that the frame and normal masks have already been generated.")
+ return
+
+ # remove_pngs_in_dir(frame_path)
+
+ if frame_mask_path:
+ remove_pngs_in_dir(frame_mask_path)
+
+ if frame_mask_path:
+ os.makedirs(frame_mask_path, exist_ok=True)
+
+ if os.path.isdir( frame_path ):
+ dbg.print("Skip frame extraction")
+ else:
+ os.makedirs(frame_path, exist_ok=True)
+
+ png_path = os.path.join(frame_path , "%05d.png")
+ # ffmpeg.exe -ss 00:00:00 -y -i %1 -qscale 0 -f image2 -c:v png "%05d.png"
+ subprocess.call("ffmpeg -ss 00:00:00 -y -i " + original_movie_path + " -qscale 0 -f image2 -c:v png " + png_path, shell=True)
+
+ dbg.print("frame extracted")
+
+ frame_width = max(frame_width,-1)
+ frame_height = max(frame_height,-1)
+
+ if frame_width != -1 or frame_height != -1:
+ resize_all_img(frame_path, frame_width, frame_height)
+
+ if frame_mask_path:
+ if st1_masking_method_index == 0:
+ create_mask_transparent_background(frame_path, frame_mask_path, tb_use_fast_mode, tb_use_jit, st1_mask_threshold)
+ elif st1_masking_method_index == 1:
+ create_mask_clipseg(frame_path, frame_mask_path, clipseg_mask_prompt, clipseg_exclude_prompt, clipseg_mask_threshold, clipseg_mask_blur_size, clipseg_mask_blur_size2)
+ elif st1_masking_method_index == 2:
+ tb_tmp_path = os.path.join(project_dir , "tb_mask_tmp")
+ if not os.path.isdir( tb_tmp_path ):
+ os.makedirs(tb_tmp_path, exist_ok=True)
+ create_mask_transparent_background(frame_path, tb_tmp_path, tb_use_fast_mode, tb_use_jit, st1_mask_threshold)
+ create_mask_clipseg(frame_path, frame_mask_path, clipseg_mask_prompt, clipseg_exclude_prompt, clipseg_mask_threshold, clipseg_mask_blur_size, clipseg_mask_blur_size2)
+ create_and_mask(tb_tmp_path,frame_mask_path,frame_mask_path)
+
+
+ dbg.print("mask created")
+
+ dbg.print("")
+ dbg.print("completed.")
+
+
+def ebsynth_utility_stage1_invert(dbg, frame_mask_path, inv_mask_path):
+ dbg.print("stage 1 create_invert_mask")
+ dbg.print("")
+
+ if not os.path.isdir( frame_mask_path ):
+ dbg.print( frame_mask_path + " not found")
+ dbg.print("Normal masks must be generated previously.")
+ dbg.print("Do stage 1 with [Ebsynth Utility] Tab -> [configuration] -> [etc]-> [Mask Mode] = Normal setting first")
+ return
+
+ os.makedirs(inv_mask_path, exist_ok=True)
+
+ mask_imgs = glob.glob( os.path.join(frame_mask_path, "*.png") )
+
+ for m in mask_imgs:
+ img = cv2.imread(m)
+ inv = cv2.bitwise_not(img)
+
+ base_name = os.path.basename(m)
+ cv2.imwrite(os.path.join(inv_mask_path,base_name), inv)
+
+ dbg.print("")
+ dbg.print("completed.")
diff --git a/ebsynth_utility/stage2.py b/ebsynth_utility/stage2.py
new file mode 100644
index 0000000000000000000000000000000000000000..762affbb829785029ceb93c553eef6ce42665658
--- /dev/null
+++ b/ebsynth_utility/stage2.py
@@ -0,0 +1,173 @@
+import cv2
+import os
+import glob
+import shutil
+import numpy as np
+import math
+
+#---------------------------------
+# Copied from PySceneDetect
+def mean_pixel_distance(left: np.ndarray, right: np.ndarray) -> float:
+ """Return the mean average distance in pixel values between `left` and `right`.
+ Both `left and `right` should be 2 dimensional 8-bit images of the same shape.
+ """
+ assert len(left.shape) == 2 and len(right.shape) == 2
+ assert left.shape == right.shape
+ num_pixels: float = float(left.shape[0] * left.shape[1])
+ return (np.sum(np.abs(left.astype(np.int32) - right.astype(np.int32))) / num_pixels)
+
+
+def estimated_kernel_size(frame_width: int, frame_height: int) -> int:
+ """Estimate kernel size based on video resolution."""
+ size: int = 4 + round(math.sqrt(frame_width * frame_height) / 192)
+ if size % 2 == 0:
+ size += 1
+ return size
+
+_kernel = None
+
+def _detect_edges(lum: np.ndarray) -> np.ndarray:
+ global _kernel
+ """Detect edges using the luma channel of a frame.
+ Arguments:
+ lum: 2D 8-bit image representing the luma channel of a frame.
+ Returns:
+ 2D 8-bit image of the same size as the input, where pixels with values of 255
+ represent edges, and all other pixels are 0.
+ """
+ # Initialize kernel.
+ if _kernel is None:
+ kernel_size = estimated_kernel_size(lum.shape[1], lum.shape[0])
+ _kernel = np.ones((kernel_size, kernel_size), np.uint8)
+
+ # Estimate levels for thresholding.
+ sigma: float = 1.0 / 3.0
+ median = np.median(lum)
+ low = int(max(0, (1.0 - sigma) * median))
+ high = int(min(255, (1.0 + sigma) * median))
+
+ # Calculate edges using Canny algorithm, and reduce noise by dilating the edges.
+ # This increases edge overlap leading to improved robustness against noise and slow
+ # camera movement. Note that very large kernel sizes can negatively affect accuracy.
+ edges = cv2.Canny(lum, low, high)
+ return cv2.dilate(edges, _kernel)
+
+#---------------------------------
+
+def detect_edges(img_path, mask_path, is_invert_mask):
+ im = cv2.imread(img_path)
+ if mask_path:
+ mask = cv2.imread(mask_path)[:,:,0]
+ mask = mask[:, :, np.newaxis]
+ im = im * ( (mask == 0) if is_invert_mask else (mask > 0) )
+# im = im * (mask/255)
+# im = im.astype(np.uint8)
+# cv2.imwrite( os.path.join( os.path.dirname(mask_path) , "tmp.png" ) , im)
+
+ hue, sat, lum = cv2.split(cv2.cvtColor( im , cv2.COLOR_BGR2HSV))
+ return _detect_edges(lum)
+
+def get_mask_path_of_img(img_path, mask_dir):
+ img_basename = os.path.basename(img_path)
+ mask_path = os.path.join( mask_dir , img_basename )
+ return mask_path if os.path.isfile( mask_path ) else None
+
+def analyze_key_frames(png_dir, mask_dir, th, min_gap, max_gap, add_last_frame, is_invert_mask):
+ keys = []
+
+ frames = sorted(glob.glob( os.path.join(png_dir, "[0-9]*.png") ))
+
+ key_frame = frames[0]
+ keys.append( int(os.path.splitext(os.path.basename(key_frame))[0]) )
+ key_edges = detect_edges( key_frame, get_mask_path_of_img( key_frame, mask_dir ), is_invert_mask )
+ gap = 0
+
+ for frame in frames:
+ gap += 1
+ if gap < min_gap:
+ continue
+
+ edges = detect_edges( frame, get_mask_path_of_img( frame, mask_dir ), is_invert_mask )
+
+ delta = mean_pixel_distance( edges, key_edges )
+
+ _th = th * (max_gap - gap)/max_gap
+
+ if _th < delta:
+ basename_without_ext = os.path.splitext(os.path.basename(frame))[0]
+ keys.append( int(basename_without_ext) )
+ key_frame = frame
+ key_edges = edges
+ gap = 0
+
+ if add_last_frame:
+ basename_without_ext = os.path.splitext(os.path.basename(frames[-1]))[0]
+ last_frame = int(basename_without_ext)
+ if not last_frame in keys:
+ keys.append( last_frame )
+
+ return keys
+
+def remove_pngs_in_dir(path):
+ if not os.path.isdir(path):
+ return
+
+ pngs = glob.glob( os.path.join(path, "*.png") )
+ for png in pngs:
+ os.remove(png)
+
+def ebsynth_utility_stage2(dbg, project_args, key_min_gap, key_max_gap, key_th, key_add_last_frame, is_invert_mask):
+ dbg.print("stage2")
+ dbg.print("")
+
+ _, original_movie_path, frame_path, frame_mask_path, org_key_path, _, _ = project_args
+
+ remove_pngs_in_dir(org_key_path)
+ os.makedirs(org_key_path, exist_ok=True)
+
+ fps = 30
+ clip = cv2.VideoCapture(original_movie_path)
+ if clip:
+ fps = clip.get(cv2.CAP_PROP_FPS)
+ clip.release()
+
+ if key_min_gap == -1:
+ key_min_gap = int(10 * fps/30)
+ else:
+ key_min_gap = max(1, key_min_gap)
+ key_min_gap = int(key_min_gap * fps/30)
+
+ if key_max_gap == -1:
+ key_max_gap = int(300 * fps/30)
+ else:
+ key_max_gap = max(10, key_max_gap)
+ key_max_gap = int(key_max_gap * fps/30)
+
+ key_min_gap,key_max_gap = (key_min_gap,key_max_gap) if key_min_gap < key_max_gap else (key_max_gap,key_min_gap)
+
+ dbg.print("fps: {}".format(fps))
+ dbg.print("key_min_gap: {}".format(key_min_gap))
+ dbg.print("key_max_gap: {}".format(key_max_gap))
+ dbg.print("key_th: {}".format(key_th))
+
+ keys = analyze_key_frames(frame_path, frame_mask_path, key_th, key_min_gap, key_max_gap, key_add_last_frame, is_invert_mask)
+
+ dbg.print("keys : " + str(keys))
+
+ for k in keys:
+ filename = str(k).zfill(5) + ".png"
+ shutil.copy( os.path.join( frame_path , filename) , os.path.join(org_key_path, filename) )
+
+
+ dbg.print("")
+ dbg.print("Keyframes are output to [" + org_key_path + "]")
+ dbg.print("")
+ dbg.print("[Ebsynth Utility]->[configuration]->[stage 2]->[Threshold of delta frame edge]")
+ dbg.print("The smaller this value, the narrower the keyframe spacing, and if set to 0, the keyframes will be equally spaced at the value of [Minimum keyframe gap].")
+ dbg.print("")
+ dbg.print("If you do not like the selection, you can modify it manually.")
+ dbg.print("(Delete keyframe, or Add keyframe from ["+frame_path+"])")
+
+ dbg.print("")
+ dbg.print("completed.")
+
diff --git a/ebsynth_utility/stage3_5.py b/ebsynth_utility/stage3_5.py
new file mode 100644
index 0000000000000000000000000000000000000000..26607a7465c43c6d5c3aaf9477f5e1d664eeb4b8
--- /dev/null
+++ b/ebsynth_utility/stage3_5.py
@@ -0,0 +1,178 @@
+import cv2
+import os
+import glob
+import shutil
+import numpy as np
+from PIL import Image
+
+from color_matcher import ColorMatcher
+from color_matcher.normalizer import Normalizer
+
+def resize_img(img, w, h):
+ if img.shape[0] + img.shape[1] < h + w:
+ interpolation = interpolation=cv2.INTER_CUBIC
+ else:
+ interpolation = interpolation=cv2.INTER_AREA
+
+ return cv2.resize(img, (w, h), interpolation=interpolation)
+
+def get_pair_of_img(img_path, target_dir):
+ img_basename = os.path.basename(img_path)
+ target_path = os.path.join( target_dir , img_basename )
+ return target_path if os.path.isfile( target_path ) else None
+
+def remove_pngs_in_dir(path):
+ if not os.path.isdir(path):
+ return
+
+ pngs = glob.glob( os.path.join(path, "*.png") )
+ for png in pngs:
+ os.remove(png)
+
+def get_pair_of_img(img, target_dir):
+ img_basename = os.path.basename(img)
+
+ pair_path = os.path.join( target_dir , img_basename )
+ if os.path.isfile( pair_path ):
+ return pair_path
+ print("!!! pair of "+ img + " not in " + target_dir)
+ return ""
+
+def get_mask_array(mask_path):
+ if not mask_path:
+ return None
+ mask_array = np.asarray(Image.open( mask_path ))
+ if mask_array.ndim == 2:
+ mask_array = mask_array[:, :, np.newaxis]
+ mask_array = mask_array[:,:,:1]
+ mask_array = mask_array/255
+ return mask_array
+
+def color_match(imgs, ref_image, color_matcher_method, dst_path):
+ cm = ColorMatcher(method=color_matcher_method)
+
+ i = 0
+ total = len(imgs)
+
+ for fname in imgs:
+
+ img_src = Image.open(fname)
+ img_src = Normalizer(np.asarray(img_src)).type_norm()
+
+ img_src = cm.transfer(src=img_src, ref=ref_image, method=color_matcher_method)
+
+ img_src = Normalizer(img_src).uint8_norm()
+ Image.fromarray(img_src).save(os.path.join(dst_path, os.path.basename(fname)))
+
+ i += 1
+ print("{0}/{1}".format(i, total))
+
+ imgs = sorted( glob.glob( os.path.join(dst_path, "*.png") ) )
+
+
+def ebsynth_utility_stage3_5(dbg, project_args, color_matcher_method, st3_5_use_mask, st3_5_use_mask_ref, st3_5_use_mask_org, color_matcher_ref_type, color_matcher_ref_image):
+ dbg.print("stage3.5")
+ dbg.print("")
+
+ _, _, frame_path, frame_mask_path, org_key_path, img2img_key_path, _ = project_args
+
+ backup_path = os.path.join( os.path.join( img2img_key_path, "..") , "st3_5_backup_img2img_key")
+ backup_path = os.path.normpath(backup_path)
+
+ if not os.path.isdir( backup_path ):
+ dbg.print("{0} not found -> create backup.".format(backup_path))
+ os.makedirs(backup_path, exist_ok=True)
+
+ imgs = glob.glob( os.path.join(img2img_key_path, "*.png") )
+
+ for img in imgs:
+ img_basename = os.path.basename(img)
+ pair_path = os.path.join( backup_path , img_basename )
+ shutil.copy( img , pair_path)
+
+ else:
+ dbg.print("{0} found -> Treat the images here as originals.".format(backup_path))
+
+ org_imgs = sorted( glob.glob( os.path.join(backup_path, "*.png") ) )
+ head_of_keyframe = org_imgs[0]
+
+ # open ref img
+ ref_image = color_matcher_ref_image
+ if not ref_image:
+ dbg.print("color_matcher_ref_image not set")
+
+ if color_matcher_ref_type == 0:
+ #'original video frame'
+ dbg.print("select -> original video frame")
+ ref_image = Image.open( get_pair_of_img(head_of_keyframe, frame_path) )
+ else:
+ #'first frame of img2img result'
+ dbg.print("select -> first frame of img2img result")
+ ref_image = Image.open( get_pair_of_img(head_of_keyframe, backup_path) )
+
+ ref_image = np.asarray(ref_image)
+
+ if st3_5_use_mask_ref:
+ mask = get_pair_of_img(head_of_keyframe, frame_mask_path)
+ if mask:
+ mask_array = get_mask_array( mask )
+ ref_image = ref_image * mask_array
+ ref_image = ref_image.astype(np.uint8)
+
+ else:
+ dbg.print("select -> color_matcher_ref_image")
+ ref_image = np.asarray(ref_image)
+
+
+ if color_matcher_method in ('mvgd', 'hm-mvgd-hm'):
+ sample_img = Image.open(head_of_keyframe)
+ ref_image = resize_img( ref_image, sample_img.width, sample_img.height )
+
+ ref_image = Normalizer(ref_image).type_norm()
+
+
+ if st3_5_use_mask_org:
+ tmp_path = os.path.join( os.path.join( img2img_key_path, "..") , "st3_5_tmp")
+ tmp_path = os.path.normpath(tmp_path)
+ dbg.print("create {0} for masked original image".format(tmp_path))
+
+ remove_pngs_in_dir(tmp_path)
+ os.makedirs(tmp_path, exist_ok=True)
+
+ for org_img in org_imgs:
+ image_basename = os.path.basename(org_img)
+
+ org_image = np.asarray(Image.open(org_img))
+
+ mask = get_pair_of_img(org_img, frame_mask_path)
+ if mask:
+ mask_array = get_mask_array( mask )
+ org_image = org_image * mask_array
+ org_image = org_image.astype(np.uint8)
+
+ Image.fromarray(org_image).save( os.path.join( tmp_path, image_basename ) )
+
+ org_imgs = sorted( glob.glob( os.path.join(tmp_path, "*.png") ) )
+
+
+ color_match(org_imgs, ref_image, color_matcher_method, img2img_key_path)
+
+
+ if st3_5_use_mask or st3_5_use_mask_org:
+ imgs = sorted( glob.glob( os.path.join(img2img_key_path, "*.png") ) )
+ for img in imgs:
+ mask = get_pair_of_img(img, frame_mask_path)
+ if mask:
+ mask_array = get_mask_array( mask )
+ bg = get_pair_of_img(img, frame_path)
+ bg_image = np.asarray(Image.open( bg ))
+ fg_image = np.asarray(Image.open( img ))
+
+ final_img = fg_image * mask_array + bg_image * (1-mask_array)
+ final_img = final_img.astype(np.uint8)
+
+ Image.fromarray(final_img).save(img)
+
+ dbg.print("")
+ dbg.print("completed.")
+
diff --git a/ebsynth_utility/stage5.py b/ebsynth_utility/stage5.py
new file mode 100644
index 0000000000000000000000000000000000000000..c70b358a3f06b946ca2344c8e0a384da7e5f3ba8
--- /dev/null
+++ b/ebsynth_utility/stage5.py
@@ -0,0 +1,279 @@
+import cv2
+import re
+import os
+import glob
+import time
+
+from sys import byteorder
+import binascii
+import numpy as np
+
+SYNTHS_PER_PROJECT = 15
+
+def to_float_bytes(f):
+ if byteorder == 'little':
+ return np.array([ float(f) ], dtype=' cur_clip+1 else -1
+
+ current_frame = 0
+
+ print(str(start) + " -> " + str(end+1))
+
+ black_img = np.zeros_like( cv2.imread( os.path.join(out_dirs[cur_clip]['path'], str(start).zfill(number_of_digits) + ".png") ) )
+
+ for i in range(start, end+1):
+
+ print(str(i) + " / " + str(end))
+
+ if next_clip == -1:
+ break
+
+ if i in range( out_dirs[cur_clip]['startframe'], out_dirs[cur_clip]['endframe'] +1):
+ pass
+ elif i in range( out_dirs[next_clip]['startframe'], out_dirs[next_clip]['endframe'] +1):
+ cur_clip = next_clip
+ next_clip = cur_clip+1 if len(out_dirs) > cur_clip+1 else -1
+ if next_clip == -1:
+ break
+ else:
+ ### black
+ # front ... none
+ # back ... none
+ cv2.imwrite( os.path.join(tmp_dir, filename) , black_img)
+ current_frame = i
+ continue
+
+ filename = str(i).zfill(number_of_digits) + ".png"
+
+ # front ... cur_clip
+ # back ... next_clip or none
+
+ if i in range( out_dirs[next_clip]['startframe'], out_dirs[next_clip]['endframe'] +1):
+ # front ... cur_clip
+ # back ... next_clip
+ img_f = cv2.imread( os.path.join(out_dirs[cur_clip]['path'] , filename) )
+ img_b = cv2.imread( os.path.join(out_dirs[next_clip]['path'] , filename) )
+
+ back_rate = (i - out_dirs[next_clip]['startframe'])/ max( 1 , (out_dirs[cur_clip]['endframe'] - out_dirs[next_clip]['startframe']) )
+
+ img = cv2.addWeighted(img_f, 1.0 - back_rate, img_b, back_rate, 0)
+
+ cv2.imwrite( os.path.join(tmp_dir , filename) , img)
+ else:
+ # front ... cur_clip
+ # back ... none
+ filename = str(i).zfill(number_of_digits) + ".png"
+ shutil.copy( os.path.join(out_dirs[cur_clip]['path'] , filename) , os.path.join(tmp_dir , filename) )
+
+ current_frame = i
+
+
+ start2 = current_frame+1
+
+ print(str(start2) + " -> " + str(end+1))
+
+ for i in range(start2, end+1):
+ filename = str(i).zfill(number_of_digits) + ".png"
+ shutil.copy( os.path.join(out_dirs[cur_clip]['path'] , filename) , os.path.join(tmp_dir , filename) )
+
+ ### create movie
+ movie_base_name = time.strftime("%Y%m%d-%H%M%S")
+ if is_invert_mask:
+ movie_base_name = "inv_" + movie_base_name
+
+ nosnd_path = os.path.join(project_dir , movie_base_name + get_ext(export_type))
+
+ start = out_dirs[0]['startframe']
+ end = out_dirs[-1]['endframe']
+
+ create_movie_from_frames( tmp_dir, start, end, number_of_digits, fps, nosnd_path, export_type)
+
+ dbg.print("exported : " + nosnd_path)
+
+ if export_type == "mp4":
+
+ with_snd_path = os.path.join(project_dir , movie_base_name + '_with_snd.mp4')
+
+ if trying_to_add_audio(original_movie_path, nosnd_path, with_snd_path, tmp_dir):
+ dbg.print("exported : " + with_snd_path)
+
+ dbg.print("")
+ dbg.print("completed.")
+
diff --git a/ebsynth_utility/stage8.py b/ebsynth_utility/stage8.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f0f1121d5a13996452cb513967d5642eb7d6a4a
--- /dev/null
+++ b/ebsynth_utility/stage8.py
@@ -0,0 +1,146 @@
+import os
+import re
+import subprocess
+import glob
+import shutil
+import time
+import cv2
+import numpy as np
+import itertools
+from extensions.ebsynth_utility.stage7 import create_movie_from_frames, get_ext, trying_to_add_audio
+
+def clamp(n, smallest, largest):
+ return sorted([smallest, n, largest])[1]
+
+def resize_img(img, w, h):
+ if img.shape[0] + img.shape[1] < h + w:
+ interpolation = interpolation=cv2.INTER_CUBIC
+ else:
+ interpolation = interpolation=cv2.INTER_AREA
+
+ return cv2.resize(img, (w, h), interpolation=interpolation)
+
+def merge_bg_src(base_frame_dir, bg_dir, frame_mask_path, tmp_dir, bg_type, mask_blur_size, mask_threshold, fg_transparency):
+
+ base_frames = sorted(glob.glob( os.path.join(base_frame_dir, "[0-9]*.png"), recursive=False) )
+
+ bg_frames = sorted(glob.glob( os.path.join(bg_dir, "*.png"), recursive=False) )
+
+ def bg_frame(total_frames):
+ bg_len = len(bg_frames)
+
+ if bg_type == "Loop":
+ itr = itertools.cycle(bg_frames)
+ while True:
+ yield next(itr)
+ else:
+ for i in range(total_frames):
+ yield bg_frames[ int(bg_len * (i/total_frames))]
+
+ bg_itr = bg_frame(len(base_frames))
+
+ for base_frame in base_frames:
+ im = cv2.imread(base_frame)
+ bg = cv2.imread( next(bg_itr) )
+ bg = resize_img(bg, im.shape[1], im.shape[0] )
+
+ basename = os.path.basename(base_frame)
+ mask_path = os.path.join(frame_mask_path, basename)
+ mask = cv2.imread(mask_path)[:,:,0]
+
+ mask[mask < int( 255 * mask_threshold )] = 0
+
+ if mask_blur_size > 0:
+ mask_blur_size = mask_blur_size//2 * 2 + 1
+ mask = cv2.GaussianBlur(mask, (mask_blur_size, mask_blur_size), 0)
+ mask = mask[:, :, np.newaxis]
+
+ fore_rate = (mask/255) * (1 - fg_transparency)
+
+ im = im * fore_rate + bg * (1- fore_rate)
+ im = im.astype(np.uint8)
+ cv2.imwrite( os.path.join( tmp_dir , basename ) , im)
+
+def extract_frames(movie_path , output_dir, fps):
+ png_path = os.path.join(output_dir , "%05d.png")
+ # ffmpeg.exe -ss 00:00:00 -y -i %1 -qscale 0 -f image2 -c:v png "%05d.png"
+ subprocess.call("ffmpeg -ss 00:00:00 -y -i " + movie_path + " -vf fps=" + str( round(fps, 2)) + " -qscale 0 -f image2 -c:v png " + png_path, shell=True)
+
+def ebsynth_utility_stage8(dbg, project_args, bg_src, bg_type, mask_blur_size, mask_threshold, fg_transparency, export_type):
+ dbg.print("stage8")
+ dbg.print("")
+
+ if not bg_src:
+ dbg.print("Fill [configuration] -> [stage 8] -> [Background source]")
+ return
+
+ project_dir, original_movie_path, _, frame_mask_path, _, _, _ = project_args
+
+ fps = 30
+ clip = cv2.VideoCapture(original_movie_path)
+ if clip:
+ fps = clip.get(cv2.CAP_PROP_FPS)
+ clip.release()
+
+ dbg.print("bg_src: {}".format(bg_src))
+ dbg.print("bg_type: {}".format(bg_type))
+ dbg.print("mask_blur_size: {}".format(mask_blur_size))
+ dbg.print("export_type: {}".format(export_type))
+ dbg.print("fps: {}".format(fps))
+
+ base_frame_dir = os.path.join( project_dir , "crossfade_tmp")
+
+ if not os.path.isdir(base_frame_dir):
+ dbg.print(base_frame_dir + " base frame not found")
+ return
+
+ tmp_dir = os.path.join( project_dir , "bg_merge_tmp")
+ if os.path.isdir(tmp_dir):
+ shutil.rmtree(tmp_dir)
+ os.mkdir(tmp_dir)
+
+ ### create frame imgs
+ if os.path.isfile(bg_src):
+ bg_ext = os.path.splitext(os.path.basename(bg_src))[1]
+ if bg_ext == ".mp4":
+ bg_tmp_dir = os.path.join( project_dir , "bg_extract_tmp")
+ if os.path.isdir(bg_tmp_dir):
+ shutil.rmtree(bg_tmp_dir)
+ os.mkdir(bg_tmp_dir)
+
+ extract_frames(bg_src, bg_tmp_dir, fps)
+
+ bg_src = bg_tmp_dir
+ else:
+ dbg.print(bg_src + " must be mp4 or directory")
+ return
+ elif not os.path.isdir(bg_src):
+ dbg.print(bg_src + " must be mp4 or directory")
+ return
+
+ merge_bg_src(base_frame_dir, bg_src, frame_mask_path, tmp_dir, bg_type, mask_blur_size, mask_threshold, fg_transparency)
+
+ ### create movie
+ movie_base_name = time.strftime("%Y%m%d-%H%M%S")
+ movie_base_name = "merge_" + movie_base_name
+
+ nosnd_path = os.path.join(project_dir , movie_base_name + get_ext(export_type))
+
+ merged_frames = sorted(glob.glob( os.path.join(tmp_dir, "[0-9]*.png"), recursive=False) )
+ start = int(os.path.splitext(os.path.basename(merged_frames[0]))[0])
+ end = int(os.path.splitext(os.path.basename(merged_frames[-1]))[0])
+
+ create_movie_from_frames(tmp_dir,start,end,5,fps,nosnd_path,export_type)
+
+ dbg.print("exported : " + nosnd_path)
+
+ if export_type == "mp4":
+
+ with_snd_path = os.path.join(project_dir , movie_base_name + '_with_snd.mp4')
+
+ if trying_to_add_audio(original_movie_path, nosnd_path, with_snd_path, tmp_dir):
+ dbg.print("exported : " + with_snd_path)
+
+ dbg.print("")
+ dbg.print("completed.")
+
diff --git a/ebsynth_utility/style.css b/ebsynth_utility/style.css
new file mode 100644
index 0000000000000000000000000000000000000000..611823d399aee6bc253026433ff3d7b9f8149e76
--- /dev/null
+++ b/ebsynth_utility/style.css
@@ -0,0 +1,39 @@
+#ebs_info_area {
+ border: black 2px solid;
+ border-radius: 5px;
+ font-size: 15px;
+ margin: 10px;
+ padding: 10px;
+}
+
+#ebs_configuration_tab1>div{
+ margin: 5px;
+ padding: 5px;
+}
+
+#ebs_configuration_tab2>div{
+ margin: 5px;
+ padding: 5px;
+}
+
+#ebs_configuration_tab3_5>div{
+ margin: 5px;
+ padding: 5px;
+}
+
+#ebs_configuration_tab7>div{
+ margin: 5px;
+ padding: 5px;
+}
+
+#ebs_configuration_tab8>div{
+ margin: 5px;
+ padding: 5px;
+}
+
+#ebs_configuration_tab_etc>div{
+ margin: 5px;
+ padding: 5px;
+}
+
+
diff --git a/microsoftexcel-controlnet/__pycache__/preload.cpython-310.pyc b/microsoftexcel-controlnet/__pycache__/preload.cpython-310.pyc
index 62f8c63cdd5cadb60cddf7915982f79e22a5b474..bf59e705d5dfbc2579eaf42c374c3b81702f1313 100644
Binary files a/microsoftexcel-controlnet/__pycache__/preload.cpython-310.pyc and b/microsoftexcel-controlnet/__pycache__/preload.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/annotator/__pycache__/util.cpython-310.pyc b/microsoftexcel-controlnet/annotator/__pycache__/util.cpython-310.pyc
index c589ccb9d9efe8cc25cce1886d501be067cfe1a2..bd4cdfd38b97b32babd5d08ae00e89062ed7af98 100644
Binary files a/microsoftexcel-controlnet/annotator/__pycache__/util.cpython-310.pyc and b/microsoftexcel-controlnet/annotator/__pycache__/util.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/adapter.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/adapter.cpython-310.pyc
index d22c524e0bf5ce8c3627a4b2c42ecc06677d94d1..cfe6e7212701dc0c4bc5ae6de9cdc950a39afa6a 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/adapter.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/adapter.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/api.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/api.cpython-310.pyc
index d099bba12ab3d15d5aa79ebd633b518f0f535ce8..59f8074bc10de40ef6bfe98bc8ab9074f4921b17 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/api.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/api.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/batch_hijack.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/batch_hijack.cpython-310.pyc
index 1512d2123e9ea4b464ea2273f4d3822a25f82f13..5e1045086797819098cbc7e1146de6ccbda5389c 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/batch_hijack.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/batch_hijack.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/cldm.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/cldm.cpython-310.pyc
index 129b6e9415e0eb10ea5007b9eaa773f1114662b7..38947cf90e2719e5cb7252c0849b5167ba20fdcf 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/cldm.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/cldm.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/controlnet.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/controlnet.cpython-310.pyc
index daf338f3a4c20f067ca653179ace042d44e4d6d9..7d82497607d48844387ec351f560b0617ea97d10 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/controlnet.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/controlnet.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/controlnet_version.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/controlnet_version.cpython-310.pyc
index 938afb622309b466e2c3c741232d06dc0b5fc862..3d9a71c322fc440d2d5e19db9b3ca4848645d3a4 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/controlnet_version.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/controlnet_version.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/external_code.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/external_code.cpython-310.pyc
index bc5aa33c03f2ecdc17c10ceaf22df3c0395eb029..c215eb51f556afb0fab1279b13f9d5c2dfe332fe 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/external_code.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/external_code.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/global_state.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/global_state.cpython-310.pyc
index e72eaf3f8615b4449228b01e34e8eb74eddb77ea..d0d0ff69b1d95e635c0d648c7d0112a9ee0b76db 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/global_state.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/global_state.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/hook.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/hook.cpython-310.pyc
index 8dca8f603dcfd9852495cbbb24b240fe7b48479d..75bc3ccd03cec854a1b3988e6653a754f425476f 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/hook.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/hook.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/lvminthin.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/lvminthin.cpython-310.pyc
index b01561ee6f0b54f08c04af47f2c547f7336e41c3..c8467ff499dc5b8294ee564d1f847e80bdd825a0 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/lvminthin.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/lvminthin.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/movie2movie.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/movie2movie.cpython-310.pyc
index ad5f3393a4cd28ebfe9d417185d6e193b9f3fa7c..e56669315d9735ea5cf827b45bf72386b2517099 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/movie2movie.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/movie2movie.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/processor.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/processor.cpython-310.pyc
index 0c4998b2a9df23d32a5f329385d2e32a50f18d79..4b85b9d43bcb823e1dc0bed16d48758e68149622 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/processor.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/processor.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/utils.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/utils.cpython-310.pyc
index d214f9ccebf8691304b2ee40d122948777ed2e69..51df97080f3a2aa8865e6786d8511fd8e999a0b3 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/utils.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/utils.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/__pycache__/xyz_grid_support.cpython-310.pyc b/microsoftexcel-controlnet/scripts/__pycache__/xyz_grid_support.cpython-310.pyc
index a90b2f2b66bb3a66a761949dac87f611046409b6..410b13bd0b51324428a809da1f4e48d943bb9555 100644
Binary files a/microsoftexcel-controlnet/scripts/__pycache__/xyz_grid_support.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/__pycache__/xyz_grid_support.cpython-310.pyc differ
diff --git a/microsoftexcel-controlnet/scripts/ui/__pycache__/controlnet_ui_group.cpython-310.pyc b/microsoftexcel-controlnet/scripts/ui/__pycache__/controlnet_ui_group.cpython-310.pyc
index df6c653668ddd097ef98c5c2c235f122c9b0aae2..d4bd318032f6f23650a894f38f352cd2a62efeb2 100644
Binary files a/microsoftexcel-controlnet/scripts/ui/__pycache__/controlnet_ui_group.cpython-310.pyc and b/microsoftexcel-controlnet/scripts/ui/__pycache__/controlnet_ui_group.cpython-310.pyc differ
diff --git a/microsoftexcel-supermerger/scripts/__pycache__/supermerger.cpython-310.pyc b/microsoftexcel-supermerger/scripts/__pycache__/supermerger.cpython-310.pyc
index 70008de725465132965d0b53a29e04b9f93b829f..722b392b9547c67d7f426b9d9f0f3524ecdb01de 100644
Binary files a/microsoftexcel-supermerger/scripts/__pycache__/supermerger.cpython-310.pyc and b/microsoftexcel-supermerger/scripts/__pycache__/supermerger.cpython-310.pyc differ
diff --git a/microsoftexcel-supermerger/scripts/mergers/__pycache__/mergers.cpython-310.pyc b/microsoftexcel-supermerger/scripts/mergers/__pycache__/mergers.cpython-310.pyc
index 05d1f968249a940ad79673898f1df17182dbc4b9..c3bb2b807085f5b05b102c7d0dba119d316080a0 100644
Binary files a/microsoftexcel-supermerger/scripts/mergers/__pycache__/mergers.cpython-310.pyc and b/microsoftexcel-supermerger/scripts/mergers/__pycache__/mergers.cpython-310.pyc differ
diff --git a/microsoftexcel-supermerger/scripts/mergers/__pycache__/model_util.cpython-310.pyc b/microsoftexcel-supermerger/scripts/mergers/__pycache__/model_util.cpython-310.pyc
index 8bc5439b9a095278bc83375269ff75a2cbf5d2d4..4ae198789464ecbc5829bafe79e0925d04a55931 100644
Binary files a/microsoftexcel-supermerger/scripts/mergers/__pycache__/model_util.cpython-310.pyc and b/microsoftexcel-supermerger/scripts/mergers/__pycache__/model_util.cpython-310.pyc differ
diff --git a/microsoftexcel-supermerger/scripts/mergers/__pycache__/pluslora.cpython-310.pyc b/microsoftexcel-supermerger/scripts/mergers/__pycache__/pluslora.cpython-310.pyc
index 543be050237e0ff3080c36c9e27ff419cdd6eada..9babbb7bfe5e7d0c9408417275f719c094f5bcb2 100644
Binary files a/microsoftexcel-supermerger/scripts/mergers/__pycache__/pluslora.cpython-310.pyc and b/microsoftexcel-supermerger/scripts/mergers/__pycache__/pluslora.cpython-310.pyc differ
diff --git a/microsoftexcel-supermerger/scripts/mergers/__pycache__/xyplot.cpython-310.pyc b/microsoftexcel-supermerger/scripts/mergers/__pycache__/xyplot.cpython-310.pyc
index af6bf122071ee1fde7b97257b2a7b47b73287129..756f9d98289c98cbcb98c1d010e232afc10715b1 100644
Binary files a/microsoftexcel-supermerger/scripts/mergers/__pycache__/xyplot.cpython-310.pyc and b/microsoftexcel-supermerger/scripts/mergers/__pycache__/xyplot.cpython-310.pyc differ
diff --git a/microsoftexcel-tunnels/__pycache__/preload.cpython-310.pyc b/microsoftexcel-tunnels/__pycache__/preload.cpython-310.pyc
index 1933b19792290e3b5f64a7d2b984d62866a579bf..0b6f93df32806769c77fa79efb6484bd602679d4 100644
Binary files a/microsoftexcel-tunnels/__pycache__/preload.cpython-310.pyc and b/microsoftexcel-tunnels/__pycache__/preload.cpython-310.pyc differ
diff --git a/microsoftexcel-tunnels/scripts/__pycache__/ssh_tunnel.cpython-310.pyc b/microsoftexcel-tunnels/scripts/__pycache__/ssh_tunnel.cpython-310.pyc
index d299dc8875b10ffae11ba4497867bf3e8d9bee04..df6619b69b17ae60018c552abab6ede089fada58 100644
Binary files a/microsoftexcel-tunnels/scripts/__pycache__/ssh_tunnel.cpython-310.pyc and b/microsoftexcel-tunnels/scripts/__pycache__/ssh_tunnel.cpython-310.pyc differ
diff --git a/microsoftexcel-tunnels/scripts/__pycache__/try_cloudflare.cpython-310.pyc b/microsoftexcel-tunnels/scripts/__pycache__/try_cloudflare.cpython-310.pyc
index 00c027e72e63848d96457940a635190ed1e191fa..53f4605d739eb3c25c171d7db5b8cedf44d12442 100644
Binary files a/microsoftexcel-tunnels/scripts/__pycache__/try_cloudflare.cpython-310.pyc and b/microsoftexcel-tunnels/scripts/__pycache__/try_cloudflare.cpython-310.pyc differ
diff --git a/openpose-editor/scripts/__pycache__/main.cpython-310.pyc b/openpose-editor/scripts/__pycache__/main.cpython-310.pyc
index 65853f4ada9fccf4bc796dfbb95e0b10cda64bd6..41ca9efa88a5248b948f0adb49250afe731e2dac 100644
Binary files a/openpose-editor/scripts/__pycache__/main.cpython-310.pyc and b/openpose-editor/scripts/__pycache__/main.cpython-310.pyc differ
diff --git a/openpose-editor/scripts/openpose/__pycache__/body.cpython-310.pyc b/openpose-editor/scripts/openpose/__pycache__/body.cpython-310.pyc
index fdb48d3157511fa6e4b6290e2fd8e6ae68c91742..da51746e0067d6797fbf20a0131bdee0f5201ac6 100644
Binary files a/openpose-editor/scripts/openpose/__pycache__/body.cpython-310.pyc and b/openpose-editor/scripts/openpose/__pycache__/body.cpython-310.pyc differ
diff --git a/openpose-editor/scripts/openpose/__pycache__/model.cpython-310.pyc b/openpose-editor/scripts/openpose/__pycache__/model.cpython-310.pyc
index 1b42a54324f3a701e7ad47fd2320a73334018420..bffc7e6490f2882ec93043e81960b29da496558d 100644
Binary files a/openpose-editor/scripts/openpose/__pycache__/model.cpython-310.pyc and b/openpose-editor/scripts/openpose/__pycache__/model.cpython-310.pyc differ
diff --git a/openpose-editor/scripts/openpose/__pycache__/util.cpython-310.pyc b/openpose-editor/scripts/openpose/__pycache__/util.cpython-310.pyc
index c504d97f9867de8841c66e19daff166ad8628d62..3d53d4786459d55b71a13318cf04494b24dbbc5d 100644
Binary files a/openpose-editor/scripts/openpose/__pycache__/util.cpython-310.pyc and b/openpose-editor/scripts/openpose/__pycache__/util.cpython-310.pyc differ
diff --git a/posex/common/__pycache__/posex_utils.cpython-310.pyc b/posex/common/__pycache__/posex_utils.cpython-310.pyc
index 3a97fa546c0d98da62a07f8dae8a03c5291430ba..4e0336995bdf05f41b5c5e1f28bc9efe1861c006 100644
Binary files a/posex/common/__pycache__/posex_utils.cpython-310.pyc and b/posex/common/__pycache__/posex_utils.cpython-310.pyc differ
diff --git a/posex/scripts/__pycache__/posex.cpython-310.pyc b/posex/scripts/__pycache__/posex.cpython-310.pyc
index 38cd18f138bfde76fb3a8fbc1d4135ebe486df58..8195f3f1744384d112575b5d595d429916c2df65 100644
Binary files a/posex/scripts/__pycache__/posex.cpython-310.pyc and b/posex/scripts/__pycache__/posex.cpython-310.pyc differ
diff --git a/sd-3dmodel-loader/scripts/__pycache__/main.cpython-310.pyc b/sd-3dmodel-loader/scripts/__pycache__/main.cpython-310.pyc
index 0167f187cfb6f9aec9b024fa5e6a2ce113bb0af6..917491a3645119a9a5764b830c0a3c73269a844a 100644
Binary files a/sd-3dmodel-loader/scripts/__pycache__/main.cpython-310.pyc and b/sd-3dmodel-loader/scripts/__pycache__/main.cpython-310.pyc differ
diff --git a/sd-webui-3d-open-pose-editor/downloads/config.json b/sd-webui-3d-open-pose-editor/downloads/config.json
index 1ee2a873ae8448a04897adc042f577f34c2693e3..738bf49f41ce38b35f58d5d595a3ff0f96636ae0 100644
--- a/sd-webui-3d-open-pose-editor/downloads/config.json
+++ b/sd-webui-3d-open-pose-editor/downloads/config.json
@@ -1 +1 @@
-{"assets": {"models/hand.fbx": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/models/hand.fbx?v=1685857223.112788", "models/foot.fbx": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/models/foot.fbx?v=1685857223.1107879", "src/poses/data.bin": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/src/poses/data.bin?v=1685857223.1317894", "pose_landmark_full.tflite": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_landmark_full.tflite?v=1685857223.7808428", "pose_web.binarypb": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_web.binarypb?v=1685857223.8048449", "pose_solution_packed_assets.data": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_solution_packed_assets.data?v=1685857223.8708503", "pose_solution_simd_wasm_bin.wasm": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_solution_simd_wasm_bin.wasm?v=1685857223.954857", "pose_solution_packed_assets_loader.js": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_solution_packed_assets_loader.js?v=1685857223.977859", "pose_solution_simd_wasm_bin.js": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_solution_simd_wasm_bin.js?v=1685857224.012862"}}
\ No newline at end of file
+{"assets": {"models/hand.fbx": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/models/hand.fbx?v=1687338775.0501518", "models/foot.fbx": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/models/foot.fbx?v=1687338775.0471516", "src/poses/data.bin": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/src/poses/data.bin?v=1687338868.781117", "pose_landmark_full.tflite": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_landmark_full.tflite?v=1687338817.7202463", "pose_web.binarypb": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_web.binarypb?v=1687338775.0451515", "pose_solution_packed_assets.data": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_solution_packed_assets.data?v=1687338822.8687432", "pose_solution_simd_wasm_bin.wasm": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_solution_simd_wasm_bin.wasm?v=1687338819.4364119", "pose_solution_packed_assets_loader.js": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_solution_packed_assets_loader.js?v=1687338775.0431511", "pose_solution_simd_wasm_bin.js": "/file=/content/microsoftexcel/extensions/sd-webui-3d-open-pose-editor/downloads/pose/0.5.1675469404/pose_solution_simd_wasm_bin.js?v=1687338775.0441513"}}
\ No newline at end of file
diff --git a/sd-webui-3d-open-pose-editor/scripts/__pycache__/openpose_editor.cpython-310.pyc b/sd-webui-3d-open-pose-editor/scripts/__pycache__/openpose_editor.cpython-310.pyc
index a8458e1bc461ceea921f55c9560eca694b25b605..80bb7fe6fe7baa64fa5a758f9e6128c250d5c805 100644
Binary files a/sd-webui-3d-open-pose-editor/scripts/__pycache__/openpose_editor.cpython-310.pyc and b/sd-webui-3d-open-pose-editor/scripts/__pycache__/openpose_editor.cpython-310.pyc differ
diff --git a/sd-webui-lora-block-weight/scripts/__pycache__/lora_block_weight.cpython-310.pyc b/sd-webui-lora-block-weight/scripts/__pycache__/lora_block_weight.cpython-310.pyc
index ab0e94633241e1e623f0d904007dd1350387d412..5d97d5c4922cb50f7ce14e09d55212298d65648d 100644
Binary files a/sd-webui-lora-block-weight/scripts/__pycache__/lora_block_weight.cpython-310.pyc and b/sd-webui-lora-block-weight/scripts/__pycache__/lora_block_weight.cpython-310.pyc differ
diff --git a/sd-webui-stablesr/scripts/__pycache__/stablesr.cpython-310.pyc b/sd-webui-stablesr/scripts/__pycache__/stablesr.cpython-310.pyc
index 45cd2a9529321fd9741898a1207857f8bedcb836..8211d8d1f99ed6f16d8d2a697ca259bc053e8142 100644
Binary files a/sd-webui-stablesr/scripts/__pycache__/stablesr.cpython-310.pyc and b/sd-webui-stablesr/scripts/__pycache__/stablesr.cpython-310.pyc differ
diff --git a/sd-webui-stablesr/srmodule/__pycache__/attn.cpython-310.pyc b/sd-webui-stablesr/srmodule/__pycache__/attn.cpython-310.pyc
index 6047b4349ddf48719d75fa6cedffcf168ca87b7b..29712e7125f54136d2061d501a6bde82584f4da1 100644
Binary files a/sd-webui-stablesr/srmodule/__pycache__/attn.cpython-310.pyc and b/sd-webui-stablesr/srmodule/__pycache__/attn.cpython-310.pyc differ
diff --git a/sd-webui-stablesr/srmodule/__pycache__/colorfix.cpython-310.pyc b/sd-webui-stablesr/srmodule/__pycache__/colorfix.cpython-310.pyc
index ca13bff8f7ebb770a97b46a593e42ef44a3e845f..b6d082cdbe5a4fbc37182ce478e0f934d03c2eeb 100644
Binary files a/sd-webui-stablesr/srmodule/__pycache__/colorfix.cpython-310.pyc and b/sd-webui-stablesr/srmodule/__pycache__/colorfix.cpython-310.pyc differ
diff --git a/sd-webui-stablesr/srmodule/__pycache__/spade.cpython-310.pyc b/sd-webui-stablesr/srmodule/__pycache__/spade.cpython-310.pyc
index 621238acdbac296649cd2f0b928310f9ea081cda..f47eb89343e493e7c601ca24ddf3421806546bb0 100644
Binary files a/sd-webui-stablesr/srmodule/__pycache__/spade.cpython-310.pyc and b/sd-webui-stablesr/srmodule/__pycache__/spade.cpython-310.pyc differ
diff --git a/sd-webui-stablesr/srmodule/__pycache__/struct_cond.cpython-310.pyc b/sd-webui-stablesr/srmodule/__pycache__/struct_cond.cpython-310.pyc
index 0837c2bb3e7946bd110d4e91d499129ab73c5bef..7762aad510263282281529ea71219bfe39d45860 100644
Binary files a/sd-webui-stablesr/srmodule/__pycache__/struct_cond.cpython-310.pyc and b/sd-webui-stablesr/srmodule/__pycache__/struct_cond.cpython-310.pyc differ
diff --git a/sd_feed/newtype_v3/__pycache__/__init__.cpython-310.pyc b/sd_feed/newtype_v3/__pycache__/__init__.cpython-310.pyc
index 0f821a50a6bc1c6f479dcf1fc380188100efd47a..e4a8a23ec20d71989ae27f4ff7d56efe0265804a 100644
Binary files a/sd_feed/newtype_v3/__pycache__/__init__.cpython-310.pyc and b/sd_feed/newtype_v3/__pycache__/__init__.cpython-310.pyc differ
diff --git a/sd_feed/newtype_v3/__pycache__/images.cpython-310.pyc b/sd_feed/newtype_v3/__pycache__/images.cpython-310.pyc
index 0ea2f9b5bda336389990c292a2de2533743e8d6f..44c8389a56a7984f7be87773a1f965a43e62af19 100644
Binary files a/sd_feed/newtype_v3/__pycache__/images.cpython-310.pyc and b/sd_feed/newtype_v3/__pycache__/images.cpython-310.pyc differ
diff --git a/sd_feed/newtype_v3/__pycache__/locs.cpython-310.pyc b/sd_feed/newtype_v3/__pycache__/locs.cpython-310.pyc
index 181e9baf27bdf57b70da63d05565b1e341f94a5f..5202f398280ddc906a118d6ee9e87020a9154db3 100644
Binary files a/sd_feed/newtype_v3/__pycache__/locs.cpython-310.pyc and b/sd_feed/newtype_v3/__pycache__/locs.cpython-310.pyc differ
diff --git a/sd_feed/newtype_v3/__pycache__/lora.cpython-310.pyc b/sd_feed/newtype_v3/__pycache__/lora.cpython-310.pyc
index bf02685ab213ec6df8fb3bbbb88ac0540f718b1b..5f74478a6bbd17a4997f059291fdb1eb3ef12228 100644
Binary files a/sd_feed/newtype_v3/__pycache__/lora.cpython-310.pyc and b/sd_feed/newtype_v3/__pycache__/lora.cpython-310.pyc differ
diff --git a/sd_feed/newtype_v3/__pycache__/lora_types.cpython-310.pyc b/sd_feed/newtype_v3/__pycache__/lora_types.cpython-310.pyc
index 60a96b27eaf9e3a1c3edd6aedc7477fdf5d6b291..6caa0687f1219d3d2ccfe15724e2d6fc09981a54 100644
Binary files a/sd_feed/newtype_v3/__pycache__/lora_types.cpython-310.pyc and b/sd_feed/newtype_v3/__pycache__/lora_types.cpython-310.pyc differ
diff --git a/sd_feed/newtype_v3/__pycache__/newtype_v3.cpython-310.pyc b/sd_feed/newtype_v3/__pycache__/newtype_v3.cpython-310.pyc
index de3fb5276a98950334da9fdbca7bbf7b4961f095..e21e423d137aa71fbf908369325ac77a32bd0c2f 100644
Binary files a/sd_feed/newtype_v3/__pycache__/newtype_v3.cpython-310.pyc and b/sd_feed/newtype_v3/__pycache__/newtype_v3.cpython-310.pyc differ
diff --git a/sd_feed/newtype_v3/__pycache__/users.cpython-310.pyc b/sd_feed/newtype_v3/__pycache__/users.cpython-310.pyc
index 04bb2dfdec912a94b35560981850a7bc382f81c3..76a2130851cd387e79cff4e934ab8164f4f0bf4b 100644
Binary files a/sd_feed/newtype_v3/__pycache__/users.cpython-310.pyc and b/sd_feed/newtype_v3/__pycache__/users.cpython-310.pyc differ
diff --git a/sd_feed/newtype_v3/tabs/__pycache__/__init__.cpython-310.pyc b/sd_feed/newtype_v3/tabs/__pycache__/__init__.cpython-310.pyc
index 46db3330fe6464ef260274623fe4723a7b2f0d67..3fc2415bd8c512d1b9ae9f7ceffea367175fef71 100644
Binary files a/sd_feed/newtype_v3/tabs/__pycache__/__init__.cpython-310.pyc and b/sd_feed/newtype_v3/tabs/__pycache__/__init__.cpython-310.pyc differ
diff --git a/sd_feed/newtype_v3/tabs/__pycache__/feed.cpython-310.pyc b/sd_feed/newtype_v3/tabs/__pycache__/feed.cpython-310.pyc
index 565232b049427452450ae958bae584ede115ae07..e17e4c66eb793cf75d6cf474b9598501b7e5d83c 100644
Binary files a/sd_feed/newtype_v3/tabs/__pycache__/feed.cpython-310.pyc and b/sd_feed/newtype_v3/tabs/__pycache__/feed.cpython-310.pyc differ
diff --git a/sd_feed/newtype_v3/utils/__pycache__/__init__.cpython-310.pyc b/sd_feed/newtype_v3/utils/__pycache__/__init__.cpython-310.pyc
index 0dfc89609db0a4bd33c7046b16f6ba26c3a21f2e..d8b1558ff9f750d1a9f271ddefbe832b0a7cb321 100644
Binary files a/sd_feed/newtype_v3/utils/__pycache__/__init__.cpython-310.pyc and b/sd_feed/newtype_v3/utils/__pycache__/__init__.cpython-310.pyc differ
diff --git a/sd_feed/newtype_v3/utils/__pycache__/string_utils.cpython-310.pyc b/sd_feed/newtype_v3/utils/__pycache__/string_utils.cpython-310.pyc
index 2bc9367627bf51082f85470185ed69b242b9e1fb..afe19ad74b76fe36fbbfff53c8a246cd35c88a89 100644
Binary files a/sd_feed/newtype_v3/utils/__pycache__/string_utils.cpython-310.pyc and b/sd_feed/newtype_v3/utils/__pycache__/string_utils.cpython-310.pyc differ
diff --git a/sd_feed/scripts/__pycache__/main.cpython-310.pyc b/sd_feed/scripts/__pycache__/main.cpython-310.pyc
index 447d68b3953faee2f990b19aebfa02c6af901c53..577ce8ac5ed4ad68995582ca17d2817645299d6b 100644
Binary files a/sd_feed/scripts/__pycache__/main.cpython-310.pyc and b/sd_feed/scripts/__pycache__/main.cpython-310.pyc differ
diff --git a/stable-diffusion-webui-composable-lora/__pycache__/composable_lora.cpython-310.pyc b/stable-diffusion-webui-composable-lora/__pycache__/composable_lora.cpython-310.pyc
index 806609e2326c052a0a3e12fd45b9f1235ca528d6..794cdd8d51f3df353af4ed4fd7e3d78d536f2d4d 100644
Binary files a/stable-diffusion-webui-composable-lora/__pycache__/composable_lora.cpython-310.pyc and b/stable-diffusion-webui-composable-lora/__pycache__/composable_lora.cpython-310.pyc differ
diff --git a/stable-diffusion-webui-composable-lora/scripts/__pycache__/composable_lora_script.cpython-310.pyc b/stable-diffusion-webui-composable-lora/scripts/__pycache__/composable_lora_script.cpython-310.pyc
index c664309d7ffa4f5f0ed3521c860a895dee352fbb..849f44ddac837ef627026f63de982e0505039048 100644
Binary files a/stable-diffusion-webui-composable-lora/scripts/__pycache__/composable_lora_script.cpython-310.pyc and b/stable-diffusion-webui-composable-lora/scripts/__pycache__/composable_lora_script.cpython-310.pyc differ
diff --git a/stable-diffusion-webui-images-browser/scripts/__pycache__/image_browser.cpython-310.pyc b/stable-diffusion-webui-images-browser/scripts/__pycache__/image_browser.cpython-310.pyc
index 85377e5457bc069369faa58120a2ff01df58ab61..981061538fc6f5729e6a93806def7c56d5d78041 100644
Binary files a/stable-diffusion-webui-images-browser/scripts/__pycache__/image_browser.cpython-310.pyc and b/stable-diffusion-webui-images-browser/scripts/__pycache__/image_browser.cpython-310.pyc differ
diff --git a/stable-diffusion-webui-images-browser/scripts/wib/__pycache__/wib_db.cpython-310.pyc b/stable-diffusion-webui-images-browser/scripts/wib/__pycache__/wib_db.cpython-310.pyc
index 6951102f981d893523fba60c8a5ebe6fd6c3d035..5dc9f381511d518ce2f846912353f994e2a3e895 100644
Binary files a/stable-diffusion-webui-images-browser/scripts/wib/__pycache__/wib_db.cpython-310.pyc and b/stable-diffusion-webui-images-browser/scripts/wib/__pycache__/wib_db.cpython-310.pyc differ
diff --git a/ultimate-upscale-for-automatic1111/scripts/__pycache__/ultimate-upscale.cpython-310.pyc b/ultimate-upscale-for-automatic1111/scripts/__pycache__/ultimate-upscale.cpython-310.pyc
index 034e238c89901db69d1a7e25da061c67dc7ae660..63b6439bbfb96218b734701bfa1d929fc2e49165 100644
Binary files a/ultimate-upscale-for-automatic1111/scripts/__pycache__/ultimate-upscale.cpython-310.pyc and b/ultimate-upscale-for-automatic1111/scripts/__pycache__/ultimate-upscale.cpython-310.pyc differ