dikdimon's picture
Upload extensions using SD-Hub extension
c336648 verified
raw
history blame
No virus
13.3 kB
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 math import sin, pi
class Script(scripts.Script):
def title(self):
return "Advanced loopback"
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)
zoom_level = gr.Slider(minimum=1, maximum=1.1, step=0.001, label='Zoom level', value=1)
with gr.Row():
direction_x = gr.Slider(minimum=-0.1, maximum=0.1, step=0.01, label='Direction X', value=0)
direction_y = gr.Slider(minimum=-0.1, maximum=0.1, step=0.01, label='Direction Y', value=0)
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,
direction_x,
direction_y,
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, direction_x, direction_y):
neg = lambda x: 1 if x > 0 else -1
if abs(direction_x) > zoom-1 : direction_x = (zoom-1)*neg(direction_x)*0.999999999999999 #*0.999999999999999 to avoid a float rounding error that makes it higher than desired
if abs(direction_y) > zoom-1 : direction_y = (zoom-1)*neg(direction_y)*0.999999999999999
w, h = img.size
x = w/2+direction_x*w/4
y = h/2-direction_y*h/4
zoom2 = zoom * 2
img = img.crop((x - w / zoom2, y - h / zoom2,
x + w / zoom2, y + h / zoom2))
return img.resize((w, h), Image.LANCZOS)
def run(self, p,
loops,
denoising_strength_change_factor,
zoom_level,
direction_x,
direction_y,
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()
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]
# print("Prompt :",p.prompt)
# print("Negative prompt :",p.negative_prompt)
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 != 1:
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, direction_x, direction_y)
print("Zoom level :",z)
else:
processed.images[0] = self.zoom_into(processed.images[0], zoom_level, direction_x, direction_y)
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