| import numpy as np |
| from tqdm import trange |
| from PIL import Image, ImageEnhance |
|
|
| import modules.scripts as scripts |
| import gradio as gr |
|
|
| from modules import processing, shared, sd_samplers, images |
| from modules.processing import Processed |
| from modules.sd_samplers import samplers |
| from modules.shared import opts, cmd_opts, state |
| from copy import deepcopy |
| from math import sin, pi |
|
|
| class Script(scripts.Script): |
| def title(self): |
| return "Advanced loopback blend" |
|
|
| def show(self, is_img2img): |
| return is_img2img |
|
|
| def ui(self, is_img2img): |
| loops = gr.Number(minimum=1, step=1, label='Loops', value=4) |
| use_first_image_colors = gr.Checkbox(label='Use first image colors (custom color correction) ', value=False) |
| denoising_strength_change_factor = gr.Slider(minimum=0.9, maximum=1.1, step=0.01, label='Denoising strength change factor (overridden if proportional used)', value=1) |
| with gr.Row(): |
| zoom_level = gr.Slider(minimum=0, maximum=50, step=1, label='Zoom level ', value=0) |
| zoom_blend = gr.Checkbox(label='Blend 50/50 with original when zoomed. Doesn\'t work with sine variation.', value=False) |
| |
| |
| |
| with gr.Row(): |
| denoising_strength_first_image = gr.Number(minimum=0, step=1, label='Denoising strength start ', value=0) |
| denoising_strength_last_image = gr.Number(minimum=0, step=1, label='Denoising strength end ', value=4) |
| denoising_strength_min = gr.Slider(minimum=0.1, maximum=1, step=0.01, label='Denoising strength proportional change starting value ', value=0.1) |
| denoising_strength_max = gr.Slider(minimum=0.1, maximum=1, step=0.01, label='Denoising strength proportional change ending value (0.1 = disabled) ', value=0.1) |
| cfg_scale_min = gr.Slider(minimum=0.1, maximum=30, step=0.1, label='CFG scale proportional change starting value ', value=0.1) |
| cfg_scale_max = gr.Slider(minimum=0.1, maximum=30, step=0.1, label='CFG scale proportional change ending value (0.1 = disabled) ', value=0.1) |
| saturation_per_image = gr.Slider(minimum=0.99, maximum=1.01, step=0.001, label='Saturation enhancement per image ', value=1) |
| with gr.Row(): |
| use_sine_variation_dns = gr.Checkbox(label='Use sine denoising strength variation (CFG will be scaled with it if the slider is > 0.1)', value=True) |
| phase_diff_denoising = gr.Slider(minimum=0, maximum=1, step=0.05, label='Phase difference', value=0) |
| amplify_sine_variation_denoise = gr.Slider(minimum=1, maximum=10, step=1, label='Denoising strength exponentiation ', value=1) |
| with gr.Row(): |
| use_sine_variation_zoom = gr.Checkbox(label='Use sine zoom variation', value=False) |
| phase_diff_zoom = gr.Slider(minimum=0, maximum=1, step=0.05, label='Phase difference', value=0) |
| amplify_sine_variation_zoom = gr.Slider(minimum=1, maximum=10, step=1, label='Zoom exponentiation ', value=1) |
| with gr.Row(): |
| use_multi_prompts = gr.Checkbox(label='Use multiple prompts', value=False) |
| same_seed_per_prompt = gr.Checkbox(label='Same seed per prompt', value=False) |
| same_seed_always = gr.Checkbox(label='Same seed for everything', value=False) |
| same_init_image = gr.Checkbox(label='Original init image for everything', value=False) |
| multi_prompts = gr.Textbox(label="Multiple prompts : 1 line positive, 1 line negative, leave a blank line for no negative", lines=2, max_lines=2000) |
| return [ |
| loops, |
| denoising_strength_change_factor, |
| zoom_level, |
| zoom_blend, |
| |
| |
| |
| denoising_strength_first_image, |
| denoising_strength_last_image, |
| denoising_strength_min, |
| denoising_strength_max, |
| cfg_scale_min, |
| cfg_scale_max, |
| saturation_per_image, |
| use_first_image_colors, |
| use_sine_variation_dns, |
| use_sine_variation_zoom, |
| phase_diff_zoom, |
| use_multi_prompts, |
| multi_prompts, |
| amplify_sine_variation_zoom, |
| same_seed_per_prompt, |
| phase_diff_denoising, |
| amplify_sine_variation_denoise, |
| same_seed_always, |
| same_init_image |
| ] |
|
|
| def zoom_into(self, img, zoom): |
| w, h = img.size |
| img = img.crop((zoom,zoom,w-zoom,h-zoom)) |
| return img.resize((w, h), Image.LANCZOS) |
|
|
| def run(self, p, |
| loops, |
| denoising_strength_change_factor, |
| zoom_level, |
| zoom_blend, |
| |
| |
| |
| denoising_strength_first_image, |
| denoising_strength_last_image, |
| denoising_strength_min, |
| denoising_strength_max, |
| cfg_scale_min, |
| cfg_scale_max, |
| saturation_per_image, |
| use_first_image_colors, |
| use_sine_variation_dns, |
| use_sine_variation_zoom, |
| phase_diff_zoom, |
| use_multi_prompts, |
| multi_prompts, |
| amplify_sine_variation_zoom, |
| same_seed_per_prompt, |
| phase_diff_denoising, |
| amplify_sine_variation_denoise, |
| same_seed_always, |
| same_init_image |
| ): |
|
|
| ppos = [] |
| pneg = [] |
| if use_multi_prompts : |
| prompts_list = multi_prompts.splitlines() |
| oddeven = lambda x: 1 if x%2==0 else 0 |
| for x in range(len(prompts_list)) : |
| if oddeven(x): |
| ppos.append(prompts_list[x]) |
| else: |
| pneg.append(prompts_list[x]) |
| if len(pneg) < len(ppos) : |
| pneg.append("") |
|
|
| def remap_range(value, minIn, MaxIn, minOut, maxOut): |
| if value > MaxIn: value = MaxIn; |
| if value < minIn: value = minIn; |
| finalValue = ((value - minIn) / (MaxIn - minIn)) * (maxOut - minOut) + minOut; |
| return finalValue; |
|
|
| def get_sin_steps(i,amplify,phase_diff=0): |
| i -= denoising_strength_first_image |
| range = (denoising_strength_last_image - denoising_strength_first_image) |
| x = i % (range) |
| y = remap_range(x,0,range,0,1) |
| y = y ** amplify |
| z = sin((y+phase_diff/2)*pi) |
| return z |
|
|
| processing.fix_seed(p) |
| batch_count = p.n_iter |
| p.extra_generation_params = { |
| "Denoising strength change factor": denoising_strength_change_factor, |
| 'Denoising strength proportional change start image':denoising_strength_first_image, |
| 'Denoising strength proportional change end image':denoising_strength_last_image, |
| 'Denoising strength proportional change starting value':denoising_strength_min, |
| 'Denoising strength proportional change ending value':denoising_strength_max, |
| 'CFG min':cfg_scale_min, |
| 'CFG max':cfg_scale_max, |
| 'use first image colors': use_first_image_colors, |
| 'Saturation enhancement per image':saturation_per_image, |
| 'Zoom level':zoom_level, |
| } |
|
|
| p.batch_size = 1 |
| p.n_iter = 1 |
|
|
| output_images, info = None, None |
| initial_seed = None |
| initial_info = None |
|
|
| grids = [] |
| all_images = [] |
| state.job_count = loops * batch_count |
|
|
| original_image = p.init_images[0].copy() |
| original_image_for_zoom = p.init_images[0].copy() |
| if opts.img2img_color_correction: |
| p.color_corrections = [processing.setup_color_correction(p.init_images[0])] |
|
|
|
|
| for n in range(batch_count): |
| history = [] |
| multi_prompts_index = 0 |
| loops = round(loops) |
| for i in range(loops): |
| p.n_iter = 1 |
| p.batch_size = 1 |
| p.do_not_save_grid = True |
|
|
| if use_multi_prompts : |
| image_range = (denoising_strength_last_image - denoising_strength_first_image) |
| il = i % (image_range) |
| if i == 0: |
| p.prompt = ppos[multi_prompts_index] |
| p.negative_prompt = pneg[multi_prompts_index] |
| print("Prompt :",p.prompt) |
| print("Negative prompt :",p.negative_prompt) |
| if il == 0 and i > 0: |
| multi_prompts_index+=1 |
| try: |
| if same_seed_per_prompt: |
| if not same_seed_always: |
| p.subseed = p.subseed + 1 if p.subseed_strength > 0 else p.subseed |
| p.seed = p.seed + 1 if p.subseed_strength == 0 else p.seed |
| p.prompt = ppos[multi_prompts_index] |
| p.negative_prompt = pneg[multi_prompts_index] |
| except Exception as e: |
| multi_prompts_index = 0 |
| if same_seed_per_prompt: |
| if not same_seed_always: |
| p.subseed = p.subseed + 1 if p.subseed_strength > 0 else p.subseed |
| p.seed = p.seed + 1 if p.subseed_strength == 0 else p.seed |
| p.prompt = ppos[multi_prompts_index] |
| p.negative_prompt = pneg[multi_prompts_index] |
| |
| |
|
|
| if use_first_image_colors: |
| p.color_corrections = [processing.setup_color_correction(original_image)] |
|
|
| state.job = f"Iteration {i + 1}/{loops}, batch {n + 1}/{batch_count}" |
|
|
| if denoising_strength_max > 0.1 : |
| if use_sine_variation_dns : |
| ds = remap_range(get_sin_steps(i,amplify_sine_variation_denoise,phase_diff_denoising),0,1,denoising_strength_min,denoising_strength_max) |
| else: |
| ds = remap_range(i+1,denoising_strength_first_image,denoising_strength_last_image,denoising_strength_min,denoising_strength_max) |
| p.denoising_strength = round(ds,3) |
| print("Denoising strength : "+str(p.denoising_strength)) |
|
|
| if cfg_scale_max > 0.1 : |
| if use_sine_variation_dns : |
| cfgs = remap_range(get_sin_steps(i,amplify_sine_variation_denoise,phase_diff_denoising),0,1,cfg_scale_min,cfg_scale_max) |
| else: |
| cfgs = remap_range(i+1,denoising_strength_first_image,denoising_strength_last_image,cfg_scale_min,cfg_scale_max) |
| p.cfg_scale = round(cfgs,2) |
| print("CFG scale : "+str(p.cfg_scale)) |
|
|
| processed = processing.process_images(p) |
| if zoom_level > 0: |
| if use_sine_variation_zoom : |
| if loops >= denoising_strength_first_image : |
| z = remap_range(get_sin_steps(i,amplify_sine_variation_zoom,phase_diff_zoom),0,1,1,zoom_level) |
| processed.images[0] = self.zoom_into(processed.images[0], z) |
| print("Zoom level :",z) |
| else: |
| processed.images[0] = self.zoom_into(processed.images[0], zoom_level) |
| if zoom_blend: |
| |
| |
| original_image_zoomed = self.zoom_into(original_image_for_zoom.copy(), zoom_level*(i+1)) |
| processed.images[0] = Image.blend(original_image_zoomed.copy().convert('RGB').resize(processed.images[0].size, Image.LANCZOS), processed.images[0].copy().convert('RGB'), alpha=0.5) |
|
|
|
|
| if initial_seed is None: |
| initial_seed = processed.seed |
| initial_info = processed.info |
|
|
| if not same_init_image : |
| init_img = processed.images[0] |
| else: |
| init_img = original_image |
|
|
| if saturation_per_image != 1 : |
| init_img = ImageEnhance.Color(init_img).enhance(saturation_per_image) |
|
|
| p.init_images = [init_img] |
| if not same_seed_per_prompt: |
| if not same_seed_always: |
| p.subseed = p.subseed + 1 if p.subseed_strength > 0 else p.subseed |
| p.seed = p.seed + 1 if p.subseed_strength == 0 else p.seed |
| p.denoising_strength = min(max(p.denoising_strength * denoising_strength_change_factor, 0.1), 1) |
| history.append(processed.images[0]) |
| if state.interrupted: |
| break |
|
|
| grid = images.image_grid(history, rows=1) |
| if opts.grid_save: |
| images.save_image(grid, p.outpath_grids, "grid", initial_seed, p.prompt, opts.grid_format, info=info, short_filename=not opts.grid_extended_filename, grid=True, p=p) |
|
|
| grids.append(grid) |
| all_images += history |
|
|
| if opts.return_grid: |
| all_images = grids + all_images |
|
|
| processed = Processed(p, all_images, initial_seed, initial_info) |
|
|
| return processed |
|
|