diff --git a/CHANGELOG.md b/CHANGELOG.md index 133aee806..04a4b62ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Change Log for SD.Next -## Update for 2024-09-06 +## Update for 2024-09-07 -### Highlights for 2024-09-06 +### Highlights for 2024-09-07 Major refactor of [FLUX.1](https://blackforestlabs.ai/announcing-black-forest-labs/) support: - Full **ControlNet** support, better **LoRA** support, full **prompt attention** support, @@ -11,13 +11,18 @@ Major refactor of [FLUX.1](https://blackforestlabs.ai/announcing-black-forest-la - Since both *Optimum-Quanto* and *BitsAndBytes* libraries are limited in their platform support matrix, try enabling **NNCF** for quantization/compression on-the-fly! -And few video related goodies: +Few image related goodies... +- **Context-aware** image resize that allows for img2img or inpaint even at massively different aspect ratios! +- Auto **HDR** image create for SD and SDXL with both 16ch true-HDR and 8-ch HDR-effect images ;) + +And few video related goodies... - [CogVideoX](https://huggingface.co/THUDM/CogVideoX-5b) 2b and 5b variants with support for *text-to-video* and *video-to-video*! - **AnimateDiff** prompt travel and long context windows! create video which travels between different prompts and at long video lengths! -Oh, as a sidenote, and also new auto **HDR** image create for SD and SDXL ;) + +Oh, as a sidenote, and also new Plus tons of minor items and fixes - see [changelog](https://github.com/vladmandic/automatic/blob/master/CHANGELOG.md) for details! ### Details for 2024-09-05 @@ -50,7 +55,7 @@ Plus tons of minor items and fixes - see [changelog](https://github.com/vladmand this brings supported quants to: *nf4/fp8/fp4/qint8/qint4* - vae support *fp16* - **lora** support additional training tools -- **face-hires** support +- **face-hires** support - support **fuse-qkv** projections can speed up generate enable via *settings -> compute -> fused projections* @@ -73,6 +78,10 @@ Plus tons of minor items and fixes - see [changelog](https://github.com/vladmand - support for **LCM** model - support for **free-noise** rolling context window allow for creation of much longer videos, automatically enabled if frames > 16 +- **Context-aware** image resize, thanks @AI-Casanova! + based on [seam-carving](https://github.com/li-plus/seam-carving) + allows for img2img or inpaint even at massively different aspect ratios! + simply select as resize method when using img2img or control tabs - **HDR** high-dynamic-range image create for SD and SDXL create hdr images from in multiple exposures by latent-space modifications during generation use via *scripts -> hdr* diff --git a/cli/image-grid.py b/cli/image-grid.py index 8a48aecd9..f6f8ed755 100755 --- a/cli/image-grid.py +++ b/cli/image-grid.py @@ -52,7 +52,8 @@ def grid(images, labels = None, width = 0, height = 0, border = 0, square = Fals h = round(height / rows) size = tuple(size) image = Image.new('RGB', size = size, color = 'black') # pylint: disable=redefined-outer-name - font = ImageFont.truetype('DejaVuSansMono', round(w / 40)) + font_size = round(w / 40) if params.font == 0 else params.font + font = ImageFont.truetype('DejaVuSansMono', font_size) for i, img in enumerate(images): # pylint: disable=redefined-outer-name x = (i % cols * w) + (i % cols * border) y = (i // cols * h) + (i // cols * border) @@ -76,6 +77,7 @@ if __name__ == '__main__': parser.add_argument("--width", type = int, default = 0, required = False, help = "fixed grid width") parser.add_argument("--height", type = int, default = 0, required = False, help = "fixed grid height") parser.add_argument("--border", type = int, default = 0, required = False, help = "image border") + parser.add_argument("--font", type = int, default = 0, required = False, help = "font text size") parser.add_argument('--nolabels', default = False, action='store_true', help = "do not print image labels") parser.add_argument('--debug', default = False, action='store_true', help = "print extra debug information") parser.add_argument('output', type = str) diff --git a/modules/control/run.py b/modules/control/run.py index 64a54d5d4..03e4bb0ae 100644 --- a/modules/control/run.py +++ b/modules/control/run.py @@ -62,9 +62,9 @@ def control_run(units: List[unit.Unit] = [], inputs: List[Image.Image] = [], ini full_quality: bool = True, restore_faces: 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', width_before: int = 512, height_before: int = 512, scale_by_before: float = 1.0, selected_scale_tab_before: int = 0, - resize_mode_after: int = 0, resize_name_after: str = 'None', width_after: int = 0, height_after: int = 0, scale_by_after: float = 1.0, selected_scale_tab_after: int = 0, - resize_mode_mask: int = 0, resize_name_mask: str = 'None', width_mask: int = 0, height_mask: int = 0, scale_by_mask: float = 1.0, selected_scale_tab_mask: int = 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, + resize_mode_after: int = 0, resize_name_after: str = 'None', resize_context_after: str = 'None', width_after: int = 0, height_after: int = 0, scale_by_after: float = 1.0, selected_scale_tab_after: int = 0, + resize_mode_mask: int = 0, resize_name_mask: str = 'None', resize_context_mask: str = 'None', width_mask: int = 0, height_mask: int = 0, scale_by_mask: float = 1.0, selected_scale_tab_mask: int = 0, denoising_strength: float = 0, batch_count: int = 1, batch_size: int = 1, enable_hr: bool = False, hr_sampler_index: int = None, hr_denoising_strength: float = 0.3, hr_upscaler: str = None, hr_force: bool = False, hr_second_pass_steps: int = 20, hr_scale: float = 1.0, hr_resize_x: int = 0, hr_resize_y: int = 0, refiner_steps: int = 5, refiner_start: float = 0.0, refiner_prompt: str = '', refiner_negative: str = '', @@ -456,8 +456,8 @@ def control_run(units: List[unit.Unit] = [], inputs: List[Image.Image] = [], ini width_before, height_before = int(input_image.width * scale_by_before), int(input_image.height * scale_by_before) if input_image is not None: p.extra_generation_params["Control resize"] = f'{resize_name_before}' - debug(f'Control resize: op=before image={input_image} width={width_before} height={height_before} mode={resize_mode_before} name={resize_name_before}') - input_image = images.resize_image(resize_mode_before, input_image, width_before, height_before, resize_name_before) + debug(f'Control resize: op=before image={input_image} width={width_before} height={height_before} mode={resize_mode_before} name={resize_name_before} context="{resize_context_before}"') + input_image = images.resize_image(resize_mode_before, input_image, width_before, height_before, resize_name_before, context=resize_context_before) if input_image is not None and init_image is not None and init_image.size != input_image.size: debug(f'Control resize init: image={init_image} target={input_image}') init_image = images.resize_image(resize_mode=1, im=init_image, width=input_image.width, height=input_image.height) @@ -618,7 +618,7 @@ def control_run(units: List[unit.Unit] = [], inputs: List[Image.Image] = [], ini if selected_scale_tab_mask == 1: width_mask, height_mask = int(input_image.width * scale_by_mask), int(input_image.height * scale_by_mask) p.width, p.height = width_mask, height_mask - debug(f'Control resize: op=mask image={mask} width={width_mask} height={height_mask} mode={resize_mode_mask} name={resize_name_mask}') + debug(f'Control resize: op=mask image={mask} width={width_mask} height={height_mask} mode={resize_mode_mask} name={resize_name_mask} context="{resize_context_mask}"') # pipeline output = None @@ -667,8 +667,8 @@ def control_run(units: List[unit.Unit] = [], inputs: List[Image.Image] = [], ini width_after = int(output_image.width * scale_by_after) height_after = int(output_image.height * scale_by_after) if resize_mode_after != 0 and resize_name_after != 'None' and not is_grid: - debug(f'Control resize: op=after image={output_image} width={width_after} height={height_after} mode={resize_mode_after} name={resize_name_after}') - output_image = images.resize_image(resize_mode_after, output_image, width_after, height_after, resize_name_after) + debug(f'Control resize: op=after image={output_image} width={width_after} height={height_after} mode={resize_mode_after} name={resize_name_after} context="{resize_context_after}"') + output_image = images.resize_image(resize_mode_after, output_image, width_after, height_after, resize_name_after, context=resize_context_after) output_images.append(output_image) if shared.opts.include_mask and not script_run: diff --git a/modules/images.py b/modules/images.py index 8dc32d2be..7c27ca4a4 100644 --- a/modules/images.py +++ b/modules/images.py @@ -5,13 +5,13 @@ import sys import math import json import uuid +import time import queue import string import random import hashlib import datetime import threading -import seam_carving from pathlib import Path from collections import namedtuple import numpy as np @@ -215,7 +215,7 @@ def draw_prompt_matrix(im, width, height, all_prompts, margin=0): return draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin) -def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type='image'): +def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type='image', context=None): upscaler_name = upscaler_name or shared.opts.upscaler_for_img2img def latent(im, w, h, upscaler): @@ -287,6 +287,37 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type res.paste(im, box=((width - im.width)//2, (height - im.height)//2)) return res + def context_aware(im, width, height, context): + import seam_carving # https://github.com/li-plus/seam-carving + if 'forward' in context: + energy_mode = "forward" + elif 'backward' in context: + energy_mode = "backward" + else: + return im + if 'Add' in context: + src_ratio = min(width / im.width, height / im.height) + src_w = int(im.width * src_ratio) + src_h = int(im.height * src_ratio) + src_image = resize(im, src_w, src_h) + elif 'Remove' in context: + ratio = width / height + src_ratio = im.width / im.height + src_w = width if ratio > src_ratio else im.width * height // im.height + src_h = height if ratio <= src_ratio else im.height * width // im.width + src_image = resize(im, src_w, src_h) + else: + return im + res = Image.fromarray(seam_carving.resize( + src_image, # source image (rgb or gray) + size=(width, height), # target size + energy_mode=energy_mode, # choose from {backward, forward} + order="width-first", # choose from {width-first, height-first} + keep_mask=None, # object mask to protect from removal + )) + return res + + t0 = time.time() if resize_mode is None: resize_mode = 0 if resize_mode == 0 or (im.width == width and im.height == height): # none @@ -301,33 +332,13 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type from modules import masking res = fill(im, color=0) res, _mask = masking.outpaint(res) - elif resize_mode == 5: # seam-add - ratio = min(width / im.width, height / im.height) - im = resize(im, int(im.width * ratio), int(im.height * ratio)) - res = Image.fromarray(seam_carving.resize( - im, # source image (rgb or gray) - size=(width, height), # target size - energy_mode="backward", # choose from {backward, forward} - order="width-first", # choose from {width-first, height-first} - keep_mask=None, # object mask to protect from removal - )) - elif resize_mode == 6: # seam-delete - ratio = width / height - src_ratio = im.width / im.height - src_w = width if ratio > src_ratio else im.width * height // im.height - src_h = height if ratio <= src_ratio else im.height * width // im.width - resized = resize(im, src_w, src_h) - res = Image.fromarray(seam_carving.resize( - resized, # source image (rgb or gray) - size=(width, height), # target size - energy_mode="backward", # choose from {backward, forward} - order="width-first", # choose from {width-first, height-first} - keep_mask=None, # object mask to protect from removal - )) + elif resize_mode == 5: # context-aware + res = context_aware(im, width, height, context) else: res = im.copy() shared.log.error(f'Invalid resize mode: {resize_mode}') - shared.log.debug(f'Image resize: input={im} width={width} height={height} mode={shared.resize_modes[resize_mode]} upscaler="{upscaler_name}" type={output_type} fn={sys._getframe(1).f_code.co_name}') # pylint: disable=protected-access + t1 = time.time() + shared.log.debug(f'Image resize: input={im} width={width} height={height} mode="{shared.resize_modes[resize_mode]}" upscaler="{upscaler_name}" context="{context}" type={output_type} time={t1-t0:.2f} fn={sys._getframe(1).f_code.co_name}') # pylint: disable=protected-access return np.array(res) if output_type == 'np' else res diff --git a/modules/img2img.py b/modules/img2img.py index e576f1058..e2ec2837e 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -133,7 +133,7 @@ def img2img(id_task: str, mode: int, selected_scale_tab, height, width, scale_by, - resize_mode, resize_name, + resize_mode, resize_name, resize_context, inpaint_full_res, inpaint_full_res_padding, inpainting_mask_invert, img2img_batch_files, img2img_batch_input_dir, img2img_batch_output_dir, img2img_batch_inpaint_mask_dir, hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundry, hdr_color_picker, hdr_tint_ratio, @@ -144,7 +144,7 @@ def img2img(id_task: 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}|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}|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}') if mode == 5: if img2img_batch_files is None or len(img2img_batch_files) == 0: @@ -234,6 +234,7 @@ def img2img(id_task: str, mode: int, inpainting_fill=inpainting_fill, resize_mode=resize_mode, resize_name=resize_name, + resize_context=resize_context, denoising_strength=denoising_strength, image_cfg_scale=image_cfg_scale, diffusers_guidance_rescale=diffusers_guidance_rescale, diff --git a/modules/processing_class.py b/modules/processing_class.py index 5b052e354..31f6fde40 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', 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, 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 self.outpath_samples: str = outpath_samples self.outpath_grids: str = outpath_grids self.prompt: str = prompt @@ -95,6 +95,7 @@ class StableDiffusionProcessing: self.ops = [] self.resize_mode: int = resize_mode self.resize_name: str = resize_name + self.resize_context: str = resize_context self.ddim_discretize = shared.opts.ddim_discretize self.s_min_uncond = shared.opts.s_min_uncond self.s_churn = shared.opts.s_churn @@ -269,11 +270,12 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): - def __init__(self, init_images: list = None, resize_mode: int = 0, resize_name: str = 'None', denoising_strength: float = 0.3, image_cfg_scale: float = None, mask: Any = None, mask_blur: int = 4, inpainting_fill: int = 0, inpaint_full_res: bool = False, inpaint_full_res_padding: int = 0, inpainting_mask_invert: int = 0, initial_noise_multiplier: float = None, scale_by: float = 1, refiner_steps: int = 5, refiner_start: float = 0, refiner_prompt: str = '', refiner_negative: str = '', **kwargs): + def __init__(self, init_images: list = None, resize_mode: int = 0, resize_name: str = 'None', resize_context: str = 'None', denoising_strength: float = 0.3, image_cfg_scale: float = None, mask: Any = None, mask_blur: int = 4, inpainting_fill: int = 0, inpaint_full_res: bool = False, inpaint_full_res_padding: int = 0, inpainting_mask_invert: int = 0, initial_noise_multiplier: float = None, scale_by: float = 1, refiner_steps: int = 5, refiner_start: float = 0, refiner_prompt: str = '', refiner_negative: str = '', **kwargs): super().__init__(**kwargs) self.init_images = init_images self.resize_mode: int = resize_mode self.resize_name: str = resize_name + self.resize_context: str = resize_context self.denoising_strength: float = denoising_strength self.hr_denoising_strength: float = denoising_strength self.image_cfg_scale: float = image_cfg_scale @@ -386,7 +388,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): if self.width is None or self.height is None: self.width, self.height = image.width, image.height if crop_region is None and self.resize_mode > 0: - image = images.resize_image(self.resize_mode, image, self.width, self.height, self.resize_name) + image = images.resize_image(self.resize_mode, image, self.width, self.height, upscaler_name=self.resize_name, context=self.resize_context) self.width = image.width self.height = image.height if self.image_mask is not None and shared.opts.mask_apply_overlay: diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 583c93ea1..db9e3425c 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -171,6 +171,10 @@ def process_diffusers(p: processing.StableDiffusionProcessing): p.hr_force = True # hires + p.denoising_strength = getattr(p, 'hr_denoising_strength', p.denoising_strength) + if p.hr_force and p.denoising_strength == 0: + shared.log.warning('HiRes skip: denoising=0') + p.hr_force = False if p.hr_force: shared.state.job_count = 2 * p.n_iter shared.sd_model = sd_models.set_diffuser_pipe(shared.sd_model, sd_models.DiffusersTaskType.IMAGE_2_IMAGE) diff --git a/modules/shared.py b/modules/shared.py index dc96d8f83..4ab82569c 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -76,7 +76,7 @@ restricted_opts = { "outdir_save", "outdir_init_images" } -resize_modes = ["None", "Fixed", "Crop", "Fill", "Outpaint", "Seam-Carving Add", "Seam-Carving Subtract"] +resize_modes = ["None", "Fixed", "Crop", "Fill", "Outpaint", "Context aware"] compatibility_opts = ['clip_skip', 'uni_pc_lower_order_final', 'uni_pc_order'] console = Console(log_time=True, log_time_format='%H:%M:%S-%f') dir_timestamps = {} diff --git a/modules/ui_control.py b/modules/ui_control.py index b2cf157a7..cfe1f59ca 100644 --- a/modules/ui_control.py +++ b/modules/ui_control.py @@ -97,11 +97,11 @@ def create_ui(_blocks: gr.Blocks=None): with gr.Accordion(open=False, label="Size", elem_id="control_size", elem_classes=["small-accordion"]): with gr.Tabs(): with gr.Tab('Before'): - resize_mode_before, resize_name_before, width_before, height_before, scale_by_before, selected_scale_tab_before = ui_sections.create_resize_inputs('control_before', [], accordion=False, latent=True) + resize_mode_before, resize_name_before, resize_context_before, width_before, height_before, scale_by_before, selected_scale_tab_before = ui_sections.create_resize_inputs('control_before', [], accordion=False, latent=True) with gr.Tab('After'): - resize_mode_after, resize_name_after, width_after, height_after, scale_by_after, selected_scale_tab_after = ui_sections.create_resize_inputs('control_after', [], accordion=False, latent=False) + resize_mode_after, resize_name_after, resize_context_after, width_after, height_after, scale_by_after, selected_scale_tab_after = ui_sections.create_resize_inputs('control_after', [], accordion=False, latent=False) with gr.Tab('Mask'): - resize_mode_mask, resize_name_mask, width_mask, height_mask, scale_by_mask, selected_scale_tab_mask = ui_sections.create_resize_inputs('control_mask', [], accordion=False, latent=False) + resize_mode_mask, resize_name_mask, resize_context_mask, width_mask, height_mask, scale_by_mask, selected_scale_tab_mask = ui_sections.create_resize_inputs('control_mask', [], accordion=False, latent=False) with gr.Accordion(open=False, label="Sampler", elem_id="control_sampler", elem_classes=["small-accordion"]): steps, sampler_index = ui_sections.create_sampler_and_steps_selection(None, "control") @@ -504,9 +504,9 @@ def create_ui(_blocks: gr.Blocks=None): seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, cfg_scale, clip_skip, image_cfg_scale, diffusers_guidance_rescale, pag_scale, pag_adaptive, cfg_end, full_quality, restore_faces, tiling, hidiffusion, hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundry, hdr_color_picker, hdr_tint_ratio, - resize_mode_before, resize_name_before, width_before, height_before, scale_by_before, selected_scale_tab_before, - resize_mode_after, resize_name_after, width_after, height_after, scale_by_after, selected_scale_tab_after, - resize_mode_mask, resize_name_mask, width_mask, height_mask, scale_by_mask, selected_scale_tab_mask, + resize_mode_before, resize_name_before, resize_context_before, width_before, height_before, scale_by_before, selected_scale_tab_before, + resize_mode_after, resize_name_after, resize_context_after, width_after, height_after, scale_by_after, selected_scale_tab_after, + resize_mode_mask, resize_name_mask, resize_context_mask, width_mask, height_mask, scale_by_mask, selected_scale_tab_mask, denoising_strength, batch_count, batch_size, enable_hr, hr_sampler_index, hr_denoising_strength, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative, diff --git a/modules/ui_img2img.py b/modules/ui_img2img.py index 058b4ba6c..e0a6a65ca 100644 --- a/modules/ui_img2img.py +++ b/modules/ui_img2img.py @@ -119,7 +119,7 @@ def create_ui(): with gr.Accordion(open=False, label="Sampler", elem_classes=["small-accordion"], elem_id="img2img_sampler_group"): steps, sampler_index = ui_sections.create_sampler_and_steps_selection(None, "img2img") ui_sections.create_sampler_options('img2img') - resize_mode, resize_name, width, height, scale_by, selected_scale_tab = ui_sections.create_resize_inputs('img2img', [init_img, sketch], latent=True) + resize_mode, resize_name, resize_context, width, height, scale_by, selected_scale_tab = ui_sections.create_resize_inputs('img2img', [init_img, sketch], latent=True) batch_count, batch_size = ui_sections.create_batch_inputs('img2img', accordion=True) seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = ui_sections.create_seed_inputs('img2img') @@ -187,7 +187,7 @@ def create_ui(): selected_scale_tab, height, width, scale_by, - resize_mode, resize_name, + resize_mode, resize_name, resize_context, inpaint_full_res, inpaint_full_res_padding, inpainting_mask_invert, img2img_batch_files, img2img_batch_input_dir, img2img_batch_output_dir, img2img_batch_inpaint_mask_dir, hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundry, hdr_color_picker, hdr_tint_ratio, diff --git a/modules/ui_sections.py b/modules/ui_sections.py index 4e8e9648e..f3fe6c137 100644 --- a/modules/ui_sections.py +++ b/modules/ui_sections.py @@ -308,9 +308,17 @@ def create_resize_inputs(tab, images, accordion=True, latent=False): with gr.Accordion(open=False, label="Resize", elem_classes=["small-accordion"], elem_id=f"{tab}_resize_group") if accordion else gr.Group(): with gr.Row(): resize_mode = gr.Dropdown(label="Mode", elem_id=f"{tab}_resize_mode", choices=shared.resize_modes, type="index", value='Fixed') - resize_name = gr.Dropdown(label="Method", elem_id=f"{tab}_resize_name", choices=([] if not latent else list(shared.latent_upscale_modes)) + [x.name for x in shared.sd_upscalers], value=shared.latent_upscale_default_mode) + resize_name = gr.Dropdown(label="Method", elem_id=f"{tab}_resize_name", choices=([] if not latent else list(shared.latent_upscale_modes)) + [x.name for x in shared.sd_upscalers], value=shared.latent_upscale_default_mode, visible=True) + resize_context_choices = ["Add with forward", "Remove with forward", "Add with backward", "Remove with backward"] + resize_context = gr.Dropdown(label="Context", elem_id=f"{tab}_resize_context", choices=resize_context_choices, value=resize_context_choices[0], visible=False) ui_common.create_refresh_button(resize_name, modelloader.load_upscalers, lambda: {"choices": modelloader.load_upscalers()}, 'refresh_upscalers') + def resize_mode_change(mode): + if mode is None or mode == 0: + return gr.update(visible=False), gr.update(visible=False) + return gr.update(visible=(mode != 5)), gr.update(visible=(mode == 5)) + resize_mode.change(fn=resize_mode_change, inputs=[resize_mode], outputs=[resize_name, resize_context]) + with gr.Row(visible=True) as _resize_group: with gr.Column(elem_id=f"{tab}_column_size"): selected_scale_tab = gr.State(value=0) # pylint: disable=abstract-class-instantiated @@ -337,4 +345,4 @@ def create_resize_inputs(tab, images, accordion=True, latent=False): tab_scale_to.select(fn=lambda: 0, inputs=[], outputs=[selected_scale_tab]) tab_scale_by.select(fn=lambda: 1, inputs=[], outputs=[selected_scale_tab]) # resize_mode.change(fn=lambda x: gr.update(visible=x != 0), inputs=[resize_mode], outputs=[_resize_group]) - return resize_mode, resize_name, width, height, scale_by, selected_scale_tab + return resize_mode, resize_name, resize_context, width, height, scale_by, selected_scale_tab diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index 75b4760bb..fd92407ce 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -171,6 +171,10 @@ def apply_upscaler(p: processing.StableDiffusionProcessingTxt2Img, opt, x): p.hr_upscaler = opt +def apply_context(p: processing.StableDiffusionProcessingTxt2Img, opt, x): + p.resize_mode = 5 + p.resize_context = opt + def apply_face_restore(p, opt, x): opt = opt.lower() if opt == 'codeformer': @@ -289,6 +293,7 @@ axis_options = [ AxisOption("[Refiner] Refiner start", float, apply_field("refiner_start")), AxisOption("[Refiner] Refiner steps", float, apply_field("refiner_steps")), AxisOption("[Postprocess] Upscaler", str, apply_upscaler, choices=lambda: [x.name for x in shared.sd_upscalers][1:]), + AxisOption("[Postprocess] Context", str, apply_context, choices=lambda: ["Add with forward", "Remove with forward", "Add with backward", "Remove with backward"]), AxisOption("[Postprocess] Face restore", str, apply_face_restore, fmt=format_value), AxisOption("[HDR] Mode", int, apply_field("hdr_mode")), AxisOption("[HDR] Brightness", float, apply_field("hdr_brightness")),