add context-aware image resize

pull/3426/head
Vladimir Mandic 2024-09-07 11:58:58 -04:00
parent 7f347b0876
commit 605e5f67aa
12 changed files with 98 additions and 56 deletions

View File

@ -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*

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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,

View File

@ -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:

View File

@ -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)

View File

@ -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 = {}

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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")),