diff --git a/cli/api-txt2img.py b/cli/api-txt2img.py index fe085e7f1..89d84be80 100755 --- a/cli/api-txt2img.py +++ b/cli/api-txt2img.py @@ -49,7 +49,7 @@ def generate(args): # pylint: disable=redefined-outer-name options['width'] = int(args.width) options['height'] = int(args.height) if args.faces: - options['restore_faces'] = args.faces + options['detailer'] = args.detailer options['denoising_strength'] = 0.5 options['hr_sampler_name'] = args.sampler data = post('/sdapi/v1/txt2img', options) @@ -75,7 +75,7 @@ if __name__ == "__main__": parser.add_argument('--height', required=False, default=512, help='image height') parser.add_argument('--steps', required=False, default=20, help='number of steps') parser.add_argument('--seed', required=False, default=-1, help='initial seed') - parser.add_argument('--faces', action='store_true', help='restore faces') + parser.add_argument('--detailer', action='store_true', help='run detailer') parser.add_argument('--sampler', required=False, default='Euler a', help='sampler name') parser.add_argument('--output', required=False, default=None, help='output image file') parser.add_argument('--model', required=False, help='model name') diff --git a/cli/create-previews.py b/cli/create-previews.py index 58c2136df..fd1d81a7f 100755 --- a/cli/create-previews.py +++ b/cli/create-previews.py @@ -46,7 +46,7 @@ options = Map({ }, # generate params 'generate': { - 'restore_faces': True, + 'detailer': True, 'prompt': '', 'negative_prompt': 'foggy, blurry, blurred, duplicate, ugly, mutilated, mutation, mutated, out of frame, bad anatomy, disfigured, deformed, censored, low res, low resolution, watermark, text, poorly drawn face, poorly drawn hands, signature', 'steps': 20, diff --git a/cli/generate.json b/cli/generate.json index 0bbcb1439..c379a6f64 100644 --- a/cli/generate.json +++ b/cli/generate.json @@ -8,7 +8,7 @@ }, "generate": { - "restore_faces": true, + "detailer": true, "prompt": "dynamic", "negative_prompt": "foggy, blurry, blurred, duplicate, ugly, mutilated, mutation, mutated, out of frame, bad anatomy, disfigured, deformed, censored, low res, watermark, text, poorly drawn face, signature", "steps": 30, diff --git a/cli/generate.py b/cli/generate.py index b8d5cac66..9b784373a 100755 --- a/cli/generate.py +++ b/cli/generate.py @@ -230,7 +230,7 @@ def args(): # parse cmd arguments parser.add_argument('--style', type = str, default = 'random', required = False, help = 'image style, used to guide dynamic prompt when prompt is not provided') parser.add_argument('--suffix', type = str, default = 'random', required = False, help = 'style suffix, used to guide dynamic prompt when prompt is not provided') parser.add_argument('--place', type = str, default = 'random', required = False, help = 'place locator, used to guide dynamic prompt when prompt is not provided') - parser.add_argument('--faces', default = False, action='store_true', help = 'restore faces during upscaling') + parser.add_argument('--detailer', default = False, action='store_true', help = 'run detailer') parser.add_argument('--steps', type = int, default = 0, required = False, help = 'number of steps') parser.add_argument('--batch', type = int, default = 0, required = False, help = 'batch size, limited by gpu vram') parser.add_argument('--n', type = int, default = 0, required = False, help = 'number of iterations') @@ -299,7 +299,7 @@ def args(): # parse cmd arguments _dynamic = prompt(params) sd.paths.root = params.path if params.path != '' else sd.paths.root - sd.generate.restore_faces = params.faces if params.faces is not None else sd.generate.restore_faces + sd.generate.detailer = params.detailer if params.detailer is not None else sd.generate.detailer sd.generate.seed = params.seed if params.seed > 0 else sd.generate.seed sd.generate.sampler_name = params.sampler if params.sampler != 'random' else sd.generate.sampler_name sd.generate.batch_size = params.batch if params.batch > 0 else sd.generate.batch_size @@ -309,7 +309,7 @@ def args(): # parse cmd arguments sd.generate.height = params.height if params.height > 0 else sd.generate.height sd.generate.steps = params.steps if params.steps > 0 else sd.generate.steps sd.upscale.upscaling_resize = params.upscale if params.upscale > 0 else sd.upscale.upscaling_resize - sd.upscale.codeformer_visibility = 1 if params.faces else sd.upscale.codeformer_visibility + sd.upscale.codeformer_visibility = 1 if params.detailer else sd.upscale.codeformer_visibility sd.options.sd_vae = params.vae if params.vae != '' else sd.options.sd_vae sd.options.sd_model_checkpoint = params.model if params.model != '' else sd.options.sd_model_checkpoint sd.upscale.upscaler_1 = 'SwinIR_4x' if params.upscale > 1 else sd.upscale.upscaler_1 diff --git a/extensions-builtin/sd-extension-system-info b/extensions-builtin/sd-extension-system-info index c88e83d40..5267e3264 160000 --- a/extensions-builtin/sd-extension-system-info +++ b/extensions-builtin/sd-extension-system-info @@ -1 +1 @@ -Subproject commit c88e83d403e1cae478df870fa2dd277d2028dc34 +Subproject commit 5267e326499cb996c8804a02e8844a2f6d77a0d4 diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js index a0424f266..b15615a2a 100644 --- a/javascript/contextMenus.js +++ b/javascript/contextMenus.js @@ -129,7 +129,7 @@ async function initContextMenu() { id = `#${tab}_reprocess`; appendContextMenuOption(id, 'Decode full quality', () => reprocessClick(`${tab}`, 'reprocess_decode'), true); appendContextMenuOption(id, 'Refine & HiRes pass', () => reprocessClick(`${tab}`, 'reprocess_refine'), true); - appendContextMenuOption(id, 'Face restore', () => reprocessClick(`${tab}`, 'reprocess_face'), true); + appendContextMenuOption(id, 'Detailer pass', () => reprocessClick(`${tab}`, 'reprocess_detail'), true); } addContextMenuEventListener(); } diff --git a/modules/api/api.py b/modules/api/api.py index 890a18733..4b7c750fd 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -69,7 +69,7 @@ class Api: self.add_api_route("/sdapi/v1/upscalers", endpoints.get_upscalers, methods=["GET"], response_model=List[models.ItemUpscaler]) self.add_api_route("/sdapi/v1/sd-models", endpoints.get_sd_models, methods=["GET"], response_model=List[models.ItemModel]) self.add_api_route("/sdapi/v1/hypernetworks", endpoints.get_hypernetworks, methods=["GET"], response_model=List[models.ItemHypernetwork]) - self.add_api_route("/sdapi/v1/face-restorers", endpoints.get_face_restorers, methods=["GET"], response_model=List[models.ItemFaceRestorer]) + self.add_api_route("/sdapi/v1/face-restorers", endpoints.get_detailers, methods=["GET"], response_model=List[models.ItemDetailer]) self.add_api_route("/sdapi/v1/prompt-styles", endpoints.get_prompt_styles, methods=["GET"], response_model=List[models.ItemStyle]) self.add_api_route("/sdapi/v1/embeddings", endpoints.get_embeddings, methods=["GET"], response_model=models.ResEmbeddings) self.add_api_route("/sdapi/v1/sd-vae", endpoints.get_sd_vaes, methods=["GET"], response_model=List[models.ItemVae]) diff --git a/modules/api/endpoints.py b/modules/api/endpoints.py index 63c5764c0..310abed1e 100644 --- a/modules/api/endpoints.py +++ b/modules/api/endpoints.py @@ -23,8 +23,8 @@ def get_sd_models(): def get_hypernetworks(): return [{"name": name, "path": shared.hypernetworks[name]} for name in shared.hypernetworks] -def get_face_restorers(): - return [{"name":x.name(), "cmd_dir": getattr(x, "cmd_dir", None)} for x in shared.face_restorers] +def get_detailers(): + return [{"name":x.name(), "cmd_dir": getattr(x, "cmd_dir", None)} for x in shared.detailers] def get_prompt_styles(): return [{ 'name': v.name, 'prompt': v.prompt, 'negative_prompt': v.negative_prompt, 'extra': v.extra, 'filename': v.filename, 'preview': v.preview} for v in shared.prompt_styles.styles.values()] diff --git a/modules/api/models.py b/modules/api/models.py index 3c5fd6146..6e658b484 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -110,7 +110,7 @@ class ItemHypernetwork(BaseModel): name: str = Field(title="Name") path: Optional[str] = Field(title="Path") -class ItemFaceRestorer(BaseModel): +class ItemDetailer(BaseModel): name: str = Field(title="Name") cmd_dir: Optional[str] = Field(title="Path") diff --git a/modules/api/process.py b/modules/api/process.py index 6dd5e701e..505ba1374 100644 --- a/modules/api/process.py +++ b/modules/api/process.py @@ -107,7 +107,7 @@ class APIProcess(): return ResMask(mask=image) def post_face(self, req: ReqFace): - from scripts.face_details import yolo # pylint: disable=no-name-in-module + from scripts.detailer import yolo # pylint: disable=no-name-in-module image = decode_base64_to_image(req.image) shared.state.begin('API-FACE', api=True) images = [] diff --git a/modules/control/run.py b/modules/control/run.py index 4f8b48cd2..01779119e 100644 --- a/modules/control/run.py +++ b/modules/control/run.py @@ -60,7 +60,7 @@ def control_run(state: str = '', steps: int = 20, sampler_index: int = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, cfg_scale: float = 6.0, clip_skip: float = 1.0, image_cfg_scale: float = 6.0, diffusers_guidance_rescale: float = 0.7, pag_scale: float = 0.0, pag_adaptive: float = 0.5, cfg_end: float = 1.0, - full_quality: bool = True, restore_faces: bool = False, tiling: bool = False, hidiffusion: bool = False, + full_quality: bool = True, detailer: bool = False, tiling: bool = False, hidiffusion: bool = False, hdr_mode: int = 0, hdr_brightness: float = 0, hdr_color: float = 0, hdr_sharpen: float = 0, hdr_clamp: bool = False, hdr_boundary: float = 4.0, hdr_threshold: float = 0.95, hdr_maximize: bool = False, hdr_max_center: float = 0.6, hdr_max_boundry: float = 1.0, hdr_color_picker: str = None, hdr_tint_ratio: float = 0, resize_mode_before: int = 0, resize_name_before: str = 'None', resize_context_before: str = 'None', width_before: int = 512, height_before: int = 512, scale_by_before: float = 1.0, selected_scale_tab_before: int = 0, @@ -129,7 +129,7 @@ def control_run(state: str = '', pag_scale = pag_scale, pag_adaptive = pag_adaptive, full_quality = full_quality, - restore_faces = restore_faces, + detailer = detailer, tiling = tiling, hidiffusion = hidiffusion, # resize diff --git a/modules/detailer.py b/modules/detailer.py new file mode 100644 index 000000000..86eae2230 --- /dev/null +++ b/modules/detailer.py @@ -0,0 +1,17 @@ +from modules import shared + + +class Detailer: + def name(self): + return "None" + + def restore(self, np_image): + return np_image + + +def detail(np_image, p=None): + detailers = [x for x in shared.detailers if x.name() == shared.opts.detailer_model or shared.opts.detailer_model is None] + if len(detailers) == 0: + return np_image + detailer = detailers[0] + return detailer.restore(np_image, p) diff --git a/modules/face/__init__.py b/modules/face/__init__.py index d5d51e647..aae3cdaa2 100644 --- a/modules/face/__init__.py +++ b/modules/face/__init__.py @@ -134,7 +134,7 @@ class Script(scripts.Script): from modules.face.insightface import get_app app=get_app('buffalo_l') from modules.face.faceswap import face_swap - if shared.opts.save_images_before_face_restoration and not p.do_not_save_samples: + if shared.opts.save_images_before_detailer and not p.do_not_save_samples: for i, image in enumerate(processed.images): info = processing.create_infotext(p, index=i) images.save_image(image, path=p.outpath_samples, seed=p.all_seeds[i], prompt=p.all_prompts[i], info=info, p=p, suffix="-before-faceswap") diff --git a/modules/face_restoration.py b/modules/face_restoration.py deleted file mode 100644 index d17191fdf..000000000 --- a/modules/face_restoration.py +++ /dev/null @@ -1,17 +0,0 @@ -from modules import shared - - -class FaceRestoration: - def name(self): - return "None" - - def restore(self, np_image): - return np_image - - -def restore_faces(np_image, p=None): - face_restorers = [x for x in shared.face_restorers if x.name() == shared.opts.face_restoration_model or shared.opts.face_restoration_model is None] - if len(face_restorers) == 0: - return np_image - face_restorer = face_restorers[0] - return face_restorer.restore(np_image, p) diff --git a/modules/img2img.py b/modules/img2img.py index 6e2986608..2417c01b3 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -120,7 +120,7 @@ def img2img(id_task: str, state: str, mode: int, sampler_index, mask_blur, mask_alpha, inpainting_fill, - full_quality, restore_faces, tiling, hidiffusion, + full_quality, detailer, tiling, hidiffusion, n_iter, batch_size, cfg_scale, image_cfg_scale, diffusers_guidance_rescale, @@ -144,7 +144,7 @@ def img2img(id_task: str, state: str, mode: int, shared.log.warning('Model not loaded') return [], '', '', 'Error: model not loaded' - debug(f'img2img: id_task={id_task}|mode={mode}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|init_img={init_img}|sketch={sketch}|init_img_with_mask={init_img_with_mask}|inpaint_color_sketch={inpaint_color_sketch}|inpaint_color_sketch_orig={inpaint_color_sketch_orig}|init_img_inpaint={init_img_inpaint}|init_mask_inpaint={init_mask_inpaint}|steps={steps}|sampler_index={sampler_index}||mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|full_quality={full_quality}|restore_faces={restore_faces}|tiling={tiling}|hidiffusion={hidiffusion}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|image_cfg_scale={image_cfg_scale}|clip_skip={clip_skip}|denoising_strength={denoising_strength}|seed={seed}|subseed{subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}|selected_scale_tab={selected_scale_tab}|height={height}|width={width}|scale_by={scale_by}|resize_mode={resize_mode}|resize_name={resize_name}|resize_context={resize_context}|inpaint_full_res={inpaint_full_res}|inpaint_full_res_padding={inpaint_full_res_padding}|inpainting_mask_invert={inpainting_mask_invert}|img2img_batch_files={img2img_batch_files}|img2img_batch_input_dir={img2img_batch_input_dir}|img2img_batch_output_dir={img2img_batch_output_dir}|img2img_batch_inpaint_mask_dir={img2img_batch_inpaint_mask_dir}|override_settings_texts={override_settings_texts}') + debug(f'img2img: id_task={id_task}|mode={mode}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|init_img={init_img}|sketch={sketch}|init_img_with_mask={init_img_with_mask}|inpaint_color_sketch={inpaint_color_sketch}|inpaint_color_sketch_orig={inpaint_color_sketch_orig}|init_img_inpaint={init_img_inpaint}|init_mask_inpaint={init_mask_inpaint}|steps={steps}|sampler_index={sampler_index}||mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|full_quality={full_quality}|detailer={detailer}|tiling={tiling}|hidiffusion={hidiffusion}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|image_cfg_scale={image_cfg_scale}|clip_skip={clip_skip}|denoising_strength={denoising_strength}|seed={seed}|subseed{subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}|selected_scale_tab={selected_scale_tab}|height={height}|width={width}|scale_by={scale_by}|resize_mode={resize_mode}|resize_name={resize_name}|resize_context={resize_context}|inpaint_full_res={inpaint_full_res}|inpaint_full_res_padding={inpaint_full_res_padding}|inpainting_mask_invert={inpainting_mask_invert}|img2img_batch_files={img2img_batch_files}|img2img_batch_input_dir={img2img_batch_input_dir}|img2img_batch_output_dir={img2img_batch_output_dir}|img2img_batch_inpaint_mask_dir={img2img_batch_inpaint_mask_dir}|override_settings_texts={override_settings_texts}') if mode == 5: if img2img_batch_files is None or len(img2img_batch_files) == 0: @@ -225,7 +225,7 @@ def img2img(id_task: str, state: str, mode: int, width=width, height=height, full_quality=full_quality, - restore_faces=restore_faces, + detailer=detailer, tiling=tiling, hidiffusion=hidiffusion, init_images=[image], diff --git a/modules/ipadapter.py b/modules/ipadapter.py index de8522195..a92a30459 100644 --- a/modules/ipadapter.py +++ b/modules/ipadapter.py @@ -83,7 +83,7 @@ def crop_images(images, crops): try: for i in range(len(images)): if crops[i]: - from scripts.face_details import yolo # pylint: disable=no-name-in-module + from scripts.detailer import yolo # pylint: disable=no-name-in-module yolo.load() cropped = [] for image in images[i]: diff --git a/modules/paths.py b/modules/paths.py index 52bec2d0f..6f864da7f 100644 --- a/modules/paths.py +++ b/modules/paths.py @@ -123,6 +123,7 @@ def create_paths(opts): create_path(fix_path('outdir_save')) create_path(fix_path('outdir_video')) create_path(fix_path('styles_dir')) + create_path(fix_path('yolo_dir')) create_path(fix_path('wildcards_dir')) diff --git a/modules/postprocess/codeformer_model.py b/modules/postprocess/codeformer_model.py index e661335f9..4493ab8a3 100644 --- a/modules/postprocess/codeformer_model.py +++ b/modules/postprocess/codeformer_model.py @@ -1,7 +1,7 @@ import os import cv2 import torch -import modules.face_restoration +import modules.detailer from modules import shared, devices, modelloader, errors from modules.paths import models_path @@ -27,7 +27,7 @@ def setup_model(dirname): return try: - class FaceRestorerCodeFormer(modules.face_restoration.FaceRestoration): + class FaceRestorerCodeFormer(modules.detailer.Detailer): def name(self): return "CodeFormer" @@ -38,7 +38,7 @@ def setup_model(dirname): def create_models(self): from modules.postprocess.codeformer_arch import CodeFormer - from facelib.utils.face_restoration_helper import FaceRestoreHelper + from facelib.utils.detailer_helper import FaceRestoreHelper from facelib.detection.retinaface import retinaface if self.net is not None and self.face_helper is not None: self.net.to(devices.device) @@ -100,7 +100,7 @@ def setup_model(dirname): if original_resolution != restored_img.shape[0:2]: restored_img = cv2.resize(restored_img, (0, 0), fx=original_resolution[1]/restored_img.shape[1], fy=original_resolution[0]/restored_img.shape[0], interpolation=cv2.INTER_LINEAR) self.face_helper.clean_all() - if shared.opts.face_restoration_unload: + if shared.opts.detailer_unload: self.send_model_to(devices.cpu) return restored_img @@ -108,7 +108,7 @@ def setup_model(dirname): have_codeformer = True global codeformer # pylint: disable=global-statement codeformer = FaceRestorerCodeFormer(dirname) - shared.face_restorers.append(codeformer) + shared.detailers.append(codeformer) except Exception as e: errors.display(e, 'codeformer') diff --git a/modules/postprocess/gfpgan_model.py b/modules/postprocess/gfpgan_model.py index f17c91b2e..03274b7f4 100644 --- a/modules/postprocess/gfpgan_model.py +++ b/modules/postprocess/gfpgan_model.py @@ -56,7 +56,7 @@ def gfpgan_fix_faces(np_image): model.face_helper.clean_all() - if shared.opts.face_restoration_unload: + if shared.opts.detailer_unload: send_model_to(model, devices.cpu) return np_image @@ -76,7 +76,7 @@ def setup_model(dirname): install('gfpgan', quiet=True) import gfpgan import facexlib - import modules.face_restoration + import modules.detailer global user_path # pylint: disable=global-statement global have_gfpgan # pylint: disable=global-statement @@ -101,13 +101,13 @@ def setup_model(dirname): have_gfpgan = True gfpgan_constructor = gfpgan.GFPGANer - class FaceRestorerGFPGAN(modules.face_restoration.FaceRestoration): + class FaceRestorerGFPGAN(modules.detailer.Detailer): def name(self): return "GFPGAN" def restore(self, np_image, p=None): # pylint: disable=unused-argument return gfpgan_fix_faces(np_image) - shared.face_restorers.append(FaceRestorerGFPGAN()) + shared.detailers.append(FaceRestorerGFPGAN()) except Exception as e: errors.log.error(f'GFPGan failed to initialize: {e}') diff --git a/modules/processing.py b/modules/processing.py index c26668763..e0b89ef47 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -4,7 +4,7 @@ import time from contextlib import nullcontext import numpy as np from PIL import Image, ImageOps -from modules import shared, devices, errors, images, scripts, memstats, lowvram, script_callbacks, extra_networks, face_restoration, sd_hijack_freeu, sd_models, sd_vae, processing_helpers, timer +from modules import shared, devices, errors, images, scripts, memstats, lowvram, script_callbacks, extra_networks, detailer, sd_hijack_freeu, sd_models, sd_vae, processing_helpers, timer from modules.sd_hijack_hypertile import context_hypertile_vae, context_hypertile_unet from modules.processing_class import StableDiffusionProcessing, StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, StableDiffusionProcessingControl # pylint: disable=unused-import from modules.processing_info import create_infotext @@ -50,8 +50,8 @@ class Processed: self.image_cfg_scale = p.image_cfg_scale or 0 self.steps = p.steps or 0 self.batch_size = max(1, p.batch_size) - self.restore_faces = p.restore_faces or False - self.face_restoration_model = shared.opts.face_restoration_model if p.restore_faces else None + self.detailer = p.detailer or False + self.detailer_model = shared.opts.detailer_model if p.detailer else None self.sd_model_hash = getattr(shared.sd_model, 'sd_model_hash', '') if model_data.sd_model is not None else '' self.seed_resize_from_w = p.seed_resize_from_w self.seed_resize_from_h = p.seed_resize_from_h @@ -96,8 +96,8 @@ class Processed: "cfg_scale": self.cfg_scale, "steps": self.steps, "batch_size": self.batch_size, - "restore_faces": self.restore_faces, - "face_restoration_model": self.face_restoration_model, + "detailer": self.detailer, + "detailer_model": self.detailer_model, "sd_model_hash": self.sd_model_hash, "seed_resize_from_w": self.seed_resize_from_w, "seed_resize_from_h": self.seed_resize_from_h, @@ -359,11 +359,11 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: else: sample = validate_sample(sample) image = Image.fromarray(sample) - if p.restore_faces: - if not p.do_not_save_samples and shared.opts.save_images_before_face_restoration: + if p.detailer: + if not p.do_not_save_samples and shared.opts.save_images_before_detailer: images.save_image(Image.fromarray(sample), path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix="-before-face-restore") p.ops.append('face') - sample = face_restoration.restore_faces(sample, p) + sample = detailer.detail(sample, p) if sample is not None: image = Image.fromarray(sample) if p.scripts is not None and isinstance(p.scripts, scripts.ScriptRunner): @@ -439,8 +439,8 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: p.image_mask = ImageOps.invert(p.image_mask) output_images.append(p.image_mask) elif getattr(p, 'image_mask', None) is not None and isinstance(p.image_mask, Image.Image): - if getattr(p, 'mask_for_facehires', None) is not None: - output_images.append(p.mask_for_facehires) + if getattr(p, 'mask_for_detailer', None) is not None: + output_images.append(p.mask_for_detailer) else: output_images.append(p.image_mask) diff --git a/modules/processing_class.py b/modules/processing_class.py index dcf003f11..3eb35aa31 100644 --- a/modules/processing_class.py +++ b/modules/processing_class.py @@ -20,7 +20,7 @@ class StableDiffusionProcessing: """ The first set of paramaters: sd_models -> do_not_reload_embeddings represent the minimum required to create a StableDiffusionProcessing """ - def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt: str = "", styles: List[str] = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, seed_enable_extras: bool = True, sampler_name: str = None, hr_sampler_name: str = None, batch_size: int = 1, n_iter: int = 1, steps: int = 50, cfg_scale: float = 7.0, image_cfg_scale: float = None, clip_skip: int = 1, width: int = 512, height: int = 512, full_quality: bool = True, restore_faces: bool = False, tiling: bool = False, hidiffusion: bool = False, do_not_save_samples: bool = False, do_not_save_grid: bool = False, extra_generation_params: Dict[Any, Any] = None, overlay_images: Any = None, negative_prompt: str = None, eta: float = None, do_not_reload_embeddings: bool = False, denoising_strength: float = 0, diffusers_guidance_rescale: float = 0.7, pag_scale: float = 0.0, pag_adaptive: float = 0.5, cfg_end: float = 1, resize_mode: int = 0, resize_name: str = 'None', resize_context: str = 'None', scale_by: float = 0, selected_scale_tab: int = 0, hdr_mode: int = 0, hdr_brightness: float = 0, hdr_color: float = 0, hdr_sharpen: float = 0, hdr_clamp: bool = False, hdr_boundary: float = 4.0, hdr_threshold: float = 0.95, hdr_maximize: bool = False, hdr_max_center: float = 0.6, hdr_max_boundry: float = 1.0, hdr_color_picker: str = None, hdr_tint_ratio: float = 0, override_settings: Dict[str, Any] = None, override_settings_restore_afterwards: bool = True, sampler_index: int = None, script_args: list = None): # pylint: disable=unused-argument + def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt: str = "", styles: List[str] = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, seed_enable_extras: bool = True, sampler_name: str = None, hr_sampler_name: str = None, batch_size: int = 1, n_iter: int = 1, steps: int = 50, cfg_scale: float = 7.0, image_cfg_scale: float = None, clip_skip: int = 1, width: int = 512, height: int = 512, full_quality: bool = True, detailer: bool = False, tiling: bool = False, hidiffusion: bool = False, do_not_save_samples: bool = False, do_not_save_grid: bool = False, extra_generation_params: Dict[Any, Any] = None, overlay_images: Any = None, negative_prompt: str = None, eta: float = None, do_not_reload_embeddings: bool = False, denoising_strength: float = 0, diffusers_guidance_rescale: float = 0.7, pag_scale: float = 0.0, pag_adaptive: float = 0.5, cfg_end: float = 1, resize_mode: int = 0, resize_name: str = 'None', resize_context: str = 'None', scale_by: float = 0, selected_scale_tab: int = 0, hdr_mode: int = 0, hdr_brightness: float = 0, hdr_color: float = 0, hdr_sharpen: float = 0, hdr_clamp: bool = False, hdr_boundary: float = 4.0, hdr_threshold: float = 0.95, hdr_maximize: bool = False, hdr_max_center: float = 0.6, hdr_max_boundry: float = 1.0, hdr_color_picker: str = None, hdr_tint_ratio: float = 0, override_settings: Dict[str, Any] = None, override_settings_restore_afterwards: bool = True, sampler_index: int = None, script_args: list = None): # pylint: disable=unused-argument self.state: str = '' self.skip = [] self.outpath_samples: str = outpath_samples @@ -50,7 +50,7 @@ class StableDiffusionProcessing: self.width: int = width self.height: int = height self.full_quality: bool = full_quality - self.restore_faces: bool = restore_faces + self.detailer: bool = detailer self.tiling: bool = tiling self.hidiffusion: bool = hidiffusion self.do_not_save_samples: bool = do_not_save_samples diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 22293fb02..c06c3d3de 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -17,7 +17,7 @@ orig_pipeline = shared.sd_model def restore_state(p: processing.StableDiffusionProcessing): - if p.state in ['reprocess_refine', 'reprocess_face']: + if p.state in ['reprocess_refine', 'reprocess_detail']: # validate if last_p is None: shared.log.warning(f'Restore state: op={p.state} last state missing') @@ -43,9 +43,9 @@ def restore_state(p: processing.StableDiffusionProcessing): p.hr_scale, p.hr_upscaler, p.hr_resize_mode, p.hr_resize_context, p.hr_resize_x, p.hr_resize_y, p.hr_upscale_to_x, p.hr_upscale_to_y = hr_scale, hr_upscaler, hr_resize_mode, hr_resize_context, hr_resize_x, hr_resize_y, hr_upscale_to_x, hr_upscale_to_y p.height, p.width, p.scale_by, p.resize_mode, p.resize_name, p.resize_context = height, width, scale_by, resize_mode, resize_name, resize_context p.init_images = None - if state == 'reprocess_face': + if state == 'reprocess_detail': p.skip = ['encode', 'base', 'hires'] - p.restore_faces = True + p.detailer = True shared.log.info(f'Restore state: op={p.state} skip={p.skip}') return p diff --git a/modules/processing_info.py b/modules/processing_info.py index ad0a455fa..b0f4f20d8 100644 --- a/modules/processing_info.py +++ b/modules/processing_info.py @@ -124,7 +124,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No args['Size scale mask'] = p.scale_by_mask args['Size name mask'] = p.resize_name_mask if 'face' in p.ops: - args["Face restoration"] = shared.opts.face_restoration_model + args["Face restoration"] = shared.opts.detailer_model if 'color' in p.ops: args["Color correction"] = True # embeddings diff --git a/modules/processing_original.py b/modules/processing_original.py index bd6a8b466..852eb9a37 100644 --- a/modules/processing_original.py +++ b/modules/processing_original.py @@ -90,11 +90,11 @@ def sample_txt2img(p: processing.StableDiffusionProcessingTxt2Img, conditioning, for i, x_sample in enumerate(decoded_samples): x_sample = validate_sample(x_sample) image = Image.fromarray(x_sample) - bak_extra_generation_params, bak_restore_faces = p.extra_generation_params, p.restore_faces + bak_extra_generation_params, bak_detailer = p.extra_generation_params, p.detailer p.extra_generation_params = {} - p.restore_faces = False + p.detailer = False info = processing.create_infotext(p, p.all_prompts, p.all_seeds, p.all_subseeds, [], iteration=p.iteration, position_in_batch=i) - p.extra_generation_params, p.restore_faces = bak_extra_generation_params, bak_restore_faces + p.extra_generation_params, p.detailer = bak_extra_generation_params, bak_detailer images.save_image(image, p.outpath_samples, "", seeds[i], prompts[i], shared.opts.samples_format, info=info, suffix="-before-hires") if latent_scale_mode is None or p.hr_force: # non-latent upscaling shared.state.job = 'Upscale' diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index cf72301e4..0ea6dbdee 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -54,7 +54,7 @@ def create_sampler(name, model): model.prior_pipe.scheduler = copy.deepcopy(model.default_scheduler) model.prior_pipe.scheduler.config.clip_sample = False config = {k: v for k, v in model.scheduler.config.items() if not k.startswith('_')} - shared.log.debug(f'Sampler default {type(model.scheduler).__name__}: {config}') + shared.log.debug(f'Sampler: sampler=default class={model.scheduler.__class__.__name__}: {config}') return model.scheduler config = find_sampler_config(name) if config is None or config.constructor is None: diff --git a/modules/shared.py b/modules/shared.py index abcfbdbab..aba93bbaf 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -43,7 +43,8 @@ locking_available = True clip_model = None interrogator = modules.interrogate.InterrogateModels(os.path.join("models", "interrogate")) sd_upscalers = [] -face_restorers = [] +detailers = [] +yolo = None tab_names = [] extra_networks = [] options_templates = {} @@ -592,6 +593,7 @@ options_templates.update(options_section(('system-paths', "System Paths"), { "embeddings_dir": OptionInfo(os.path.join(paths.models_path, 'embeddings'), "Folder with textual inversion embeddings", folder=True), "hypernetwork_dir": OptionInfo(os.path.join(paths.models_path, 'hypernetworks'), "Folder with Hypernetwork models", folder=True), "control_dir": OptionInfo(os.path.join(paths.models_path, 'control'), "Folder with Control models", folder=True), + "yolo_dir": OptionInfo(os.path.join(paths.models_path, 'yolo'), "Folder with Yolo models", folder=True), "codeformer_models_path": OptionInfo(os.path.join(paths.models_path, 'Codeformer'), "Folder with codeformer models", folder=True), "gfpgan_models_path": OptionInfo(os.path.join(paths.models_path, 'GFPGAN'), "Folder with GFPGAN models", folder=True), "esrgan_models_path": OptionInfo(os.path.join(paths.models_path, 'ESRGAN'), "Folder with ESRGAN models", folder=True), @@ -644,7 +646,7 @@ options_templates.update(options_section(('saving-images', "Image Options"), { "save_init_img": OptionInfo(False, "Save init images"), "save_images_before_highres_fix": OptionInfo(False, "Save image before hires"), "save_images_before_refiner": OptionInfo(False, "Save image before refiner"), - "save_images_before_face_restoration": OptionInfo(False, "Save image before face restoration"), + "save_images_before_detailer": OptionInfo(False, "Save image before detailer"), "save_images_before_color_correction": OptionInfo(False, "Save image before color correction"), "save_mask": OptionInfo(False, "Save inpainting mask"), "save_mask_composite": OptionInfo(False, "Save inpainting masked composite"), @@ -782,18 +784,19 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), { "img2img_extra_noise": OptionInfo(0.0, "Extra noise multiplier for img2img", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), "CLIP_stop_at_last_layers": OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 8, "step": 1, "visible": False}), - "postprocessing_sep_face_restoration": OptionInfo("