diff --git a/CHANGELOG.md b/CHANGELOG.md index fc0fa78bb..8910cf871 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,9 @@ - allow passing **processing args** directly: params are set directly on main processing object and can be known or new params example: `steps=10, steps=20; test=unknown` + - enable working with different resolutions + now you can adjust width/height in the grid just as any other param + - renamed options to include section name and adjusted cost of each option - **interrogate** - add additional blip models: *blip-base, blip-large, blip-t5-xl, blip-t5-xxl, opt-2.7b, opt-6.7b* - change default params for better memory utilization diff --git a/modules/images.py b/modules/images.py index e00dbceda..3baa2c8fa 100644 --- a/modules/images.py +++ b/modules/images.py @@ -12,7 +12,7 @@ import piexif import piexif.helper from PIL import Image, PngImagePlugin, ExifTags from modules import sd_samplers, shared, script_callbacks, errors, paths -from modules.images_grid import image_grid, split_grid, combine_grid, check_grid_size, get_font, draw_grid_annotations, draw_prompt_matrix # pylint: disable=unused-import +from modules.images_grid import image_grid, split_grid, combine_grid, check_grid_size, get_font, draw_grid_annotations, draw_prompt_matrix, GridAnnotation # pylint: disable=unused-import from modules.images_resize import resize_image # pylint: disable=unused-import from modules.images_namegen import FilenameGenerator diff --git a/modules/images_grid.py b/modules/images_grid.py index d3a6c79d1..c50d81612 100644 --- a/modules/images_grid.py +++ b/modules/images_grid.py @@ -5,6 +5,9 @@ from PIL import Image, ImageFont, ImageDraw from modules import shared, script_callbacks +Grid = namedtuple("Grid", ["tiles", "tile_w", "tile_h", "image_w", "image_h", "overlap"]) + + def check_grid_size(imgs): mp = 0 for img in imgs: @@ -34,16 +37,13 @@ def image_grid(imgs, batch_size=1, rows=None): imgs = [i for i in imgs if i is not None] if imgs is not None else [] if len(imgs) == 0: return None - w, h = imgs[0].size + w, h = max(i.width for i in imgs), max(i.height for i in imgs) grid = Image.new('RGB', size=(params.cols * w, params.rows * h), color=shared.opts.grid_background) for i, img in enumerate(params.imgs): grid.paste(img, box=(i % params.cols * w, i // params.cols * h)) return grid -Grid = namedtuple("Grid", ["tiles", "tile_w", "tile_h", "image_w", "image_h", "overlap"]) - - def split_grid(image, tile_w=512, tile_h=512, overlap=64): w = image.width h = image.height @@ -136,10 +136,10 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0, tit font = get_font(fontsize) color_inactive = (127, 127, 127) pad_left = 0 if sum([sum([len(line.text) for line in lines]) for lines in ver_texts]) == 0 else width * 3 // 4 - cols = im.width // width - rows = im.height // height - assert cols == len(hor_texts), f'bad number of horizontal texts: {len(hor_texts)}; must be {cols}' - assert rows == len(ver_texts), f'bad number of vertical texts: {len(ver_texts)}; must be {rows}' + cols = len(hor_texts) + rows = len(ver_texts) + # assert cols == len(hor_texts), f'bad number of horizontal texts: {len(hor_texts)}; must be {cols}' + # assert rows == len(hor_texts), f'bad number of vertical texts: {len(ver_texts)}; must be {rows}' calc_img = Image.new("RGB", (1, 1), shared.opts.grid_background) calc_d = ImageDraw.Draw(calc_img) title_texts = [title] if title else [[GridAnnotation()]] diff --git a/scripts/xyz_grid_classes.py b/scripts/xyz_grid_classes.py index d52a1da01..af79f58a5 100644 --- a/scripts/xyz_grid_classes.py +++ b/scripts/xyz_grid_classes.py @@ -80,27 +80,30 @@ class SharedSettingsStackHelper(object): axis_options = [ AxisOption("Nothing", str, do_nothing, fmt=format_nothing), - AxisOption("Prompt S/R", str, apply_prompt, fmt=format_value), - AxisOption("Model", str, apply_checkpoint, fmt=format_value, cost=1.0, choices=lambda: sorted(sd_models.checkpoints_list)), - AxisOption("UNET", str, apply_unet, cost=0.9, choices=lambda: ['None'] + list(sd_unet.unet_dict)), - AxisOption("VAE", str, apply_vae, cost=0.7, choices=lambda: ['None'] + list(sd_vae.vae_dict)), - AxisOption("LoRA", str, apply_lora, cost=0.5, choices=list_lora), - AxisOption("LoRA strength", float, apply_setting('extra_networks_default_multiplier')), - AxisOption("Text encoder", str, apply_te, cost=0.7, choices=shared_items.sd_te_items), - AxisOption("Styles", str, apply_styles, choices=lambda: [s.name for s in shared.prompt_styles.styles.values()]), - AxisOption("Seed", int, apply_field("seed")), - AxisOption("Steps", int, apply_field("steps")), - AxisOption("CFG scale", float, apply_field("cfg_scale")), - AxisOption("Guidance end", float, apply_field("cfg_end")), - AxisOption("Variation seed", int, apply_field("subseed")), - AxisOption("Variation strength", float, apply_field("subseed_strength")), - AxisOption("Clip skip", float, apply_clip_skip), - AxisOption("Denoising strength", float, apply_field("denoising_strength")), - AxisOption("Prompt order", str_permutations, apply_order, fmt=format_value_join_list), - AxisOption("Model dictionary", str, apply_dict, fmt=format_value, cost=1.0, choices=lambda: ['None'] + list(sd_models.checkpoints_list)), - AxisOption("Model args", str, apply_task_args), - AxisOption("Processing args", str, apply_processing), - AxisOptionImg2Img("Image mask weight", float, apply_field("inpainting_mask_weight")), + AxisOption("[Model] Model", str, apply_checkpoint, cost=1.0, fmt=format_value, choices=lambda: sorted(sd_models.checkpoints_list)), + AxisOption("[Model] UNET", str, apply_unet, cost=0.8, choices=lambda: ['None'] + list(sd_unet.unet_dict)), + AxisOption("[Model] VAE", str, apply_vae, cost=0.6, choices=lambda: ['None'] + list(sd_vae.vae_dict)), + AxisOption("[Model] Refiner", str, apply_refiner, cost=0.8, fmt=format_value, choices=lambda: ['None'] + sorted(sd_models.checkpoints_list)), + AxisOption("[Model] Text encoder", str, apply_te, cost=0.7, choices=shared_items.sd_te_items), + AxisOption("[Model] Dictionary", str, apply_dict, fmt=format_value, cost=0.9, choices=lambda: ['None'] + list(sd_models.checkpoints_list)), + AxisOption("[Prompt] Search & replace", str, apply_prompt, fmt=format_value), + AxisOption("[Prompt] Prompt order", str_permutations, apply_order, fmt=format_value_join_list), + AxisOption("[Network] LoRA", str, apply_lora, cost=0.5, choices=list_lora), + AxisOption("[Network] LoRA strength", float, apply_setting('extra_networks_default_multiplier')), + AxisOption("[Network] Styles", str, apply_styles, choices=lambda: [s.name for s in shared.prompt_styles.styles.values()]), + AxisOption("[Param] Width", int, apply_field("width")), + AxisOption("[Param] Height", int, apply_field("height")), + AxisOption("[Param] Seed", int, apply_field("seed")), + AxisOption("[Param] Steps", int, apply_field("steps")), + AxisOption("[Param] CFG scale", float, apply_field("cfg_scale")), + AxisOption("[Param] Guidance end", float, apply_field("cfg_end")), + AxisOption("[Param] Variation seed", int, apply_field("subseed")), + AxisOption("[Param] Variation strength", float, apply_field("subseed_strength")), + AxisOption("[Param] Clip skip", float, apply_clip_skip), + AxisOption("[Param] Denoising strength", float, apply_field("denoising_strength")), + AxisOptionImg2Img("[Param] Mask weight", float, apply_field("inpainting_mask_weight")), + AxisOption("[Process] Model args", str, apply_task_args), + AxisOption("[Process] Processing args", str, apply_processing), AxisOptionTxt2Img("[Sampler] Name", str, apply_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]), AxisOptionImg2Img("[Sampler] Name", str, apply_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers_for_img2img]), AxisOption("[Sampler] Timestep spacing", str, apply_setting("schedulers_timestep_spacing"), choices=lambda: ['default', 'linspace', 'leading', 'trailing']), @@ -113,16 +116,15 @@ axis_options = [ AxisOption("[Sampler] Shift", float, apply_setting("schedulers_shift")), AxisOption("[Sampler] ETA", float, apply_setting("scheduler_eta")), AxisOption("[Sampler] Solver order", int, apply_setting("schedulers_solver_order")), - AxisOption("[Second pass] Upscaler", str, apply_field("hr_upscaler"), choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]), - AxisOption("[Second pass] Sampler", str, apply_hr_sampler_name, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]), - AxisOption("[Second pass] Denoising strength", float, apply_field("denoising_strength")), - AxisOption("[Second pass] Hires steps", int, apply_field("hr_second_pass_steps")), - AxisOption("[Second pass] CFG scale", float, apply_field("image_cfg_scale")), - AxisOption("[Second pass] Guidance rescale", float, apply_field("diffusers_guidance_rescale")), - AxisOption("[Refiner] Model", str, apply_refiner, fmt=format_value, cost=1.0, choices=lambda: ['None'] + sorted(sd_models.checkpoints_list)), - 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("[Refine] Upscaler", str, apply_field("hr_upscaler"), cost=0.3, choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]), + AxisOption("[Refine] Sampler", str, apply_hr_sampler_name, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]), + AxisOption("[Refine] Denoising strength", float, apply_field("denoising_strength")), + AxisOption("[Refine] Hires steps", int, apply_field("hr_second_pass_steps")), + AxisOption("[Refine] CFG scale", float, apply_field("image_cfg_scale")), + AxisOption("[Refine] Guidance rescale", float, apply_field("diffusers_guidance_rescale")), + AxisOption("[Refine] Refiner start", float, apply_field("refiner_start")), + AxisOption("[Refine] Refiner steps", float, apply_field("refiner_steps")), + AxisOption("[Postprocess] Upscaler", str, apply_upscaler, cost=0.4, 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")), diff --git a/scripts/xyz_grid_draw.py b/scripts/xyz_grid_draw.py index be4862e3d..1c6c4fb8e 100644 --- a/scripts/xyz_grid_draw.py +++ b/scripts/xyz_grid_draw.py @@ -85,21 +85,24 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend for i in range(z_count): start_index = (i * len(xs) * len(ys)) + i end_index = start_index + len(xs) * len(ys) + w, h = max(i.width for i in processed_result.images[start_index:end_index]), max(i.height for i in processed_result.images[start_index:end_index]) + print('HERE', w, h, z_count) if (not no_grid or include_sub_grids) and images.check_grid_size(processed_result.images[start_index:end_index]): grid = images.image_grid(processed_result.images[start_index:end_index], rows=len(ys)) if draw_legend: - grid = images.draw_grid_annotations(grid, processed_result.images[start_index].size[0], processed_result.images[start_index].size[1], hor_texts, ver_texts, margin_size, title=title_texts[i]) + grid = images.draw_grid_annotations(grid, w, h, hor_texts, ver_texts, margin_size, title=title_texts[i]) processed_result.images.insert(i, grid) processed_result.all_prompts.insert(i, processed_result.all_prompts[start_index]) processed_result.all_seeds.insert(i, processed_result.all_seeds[start_index]) processed_result.infotexts.insert(i, processed_result.infotexts[start_index]) - sub_grid_size = processed_result.images[0].size + """ if not no_grid and images.check_grid_size(processed_result.images[:z_count]): z_grid = images.image_grid(processed_result.images[:z_count], rows=1) if draw_legend: - z_grid = images.draw_grid_annotations(z_grid, sub_grid_size[0], sub_grid_size[1], [[images.GridAnnotation()] for _ in z_labels], [[images.GridAnnotation()]]) + z_grid = images.draw_grid_annotations(z_grid, w, h, [[images.GridAnnotation()] for _ in z_labels], [[images.GridAnnotation()]]) processed_result.images.insert(0, z_grid) - #processed_result.all_prompts.insert(0, processed_result.all_prompts[0]) - #processed_result.all_seeds.insert(0, processed_result.all_seeds[0]) - processed_result.infotexts.insert(0, processed_result.infotexts[0]) + processed_result.all_prompts.insert(0, processed_result.all_prompts[0]) + processed_result.all_seeds.insert(0, processed_result.all_seeds[0]) + processed_result.infotexts.insert(0, processed_result.infotexts[0]) + """ return processed_result