stable-diffusion-webui/scripts/loopback.py
James Railton 33b8539147 Loopback Script Updates
- Improved user experience. You can now pick the denoising strength of the final loop and one of three curves. Previously you picked a multiplier such as 0.98 or 1.03 to define the change to the denoising strength for each loop. You had to do a ton of math in your head to visualize what was happening. The new UX makes it very easy to understand what's going on and tweak.
- For batch sizes over 1, intermediate images no longer returned. For a batch size of 1, intermediate images from each loop will continue to be returned. When more than 1 image is returned, a grid will also be generated. Previously for larger jobs, you'd get back a mess of many grids and potentially hundreds of images with no organization. To make large jobs usable, only final images are returned.
- Added support for skipping current image. Fixed interrupt to cleanly end and return images. Previously these would throw.
- Improved tooltip descriptions
- Fix some edge cases
2023-03-21 21:07:33 -04:00

140 lines
5.1 KiB
Python

import math
import gradio as gr
import modules.scripts as scripts
from modules import deepbooru, images, processing, shared
from modules.processing import Processed
from modules.shared import opts, state
class Script(scripts.Script):
def title(self):
return "Loopback"
def show(self, is_img2img):
return is_img2img
def ui(self, is_img2img):
loops = gr.Slider(minimum=1, maximum=32, step=1, label='Loops', value=4, elem_id=self.elem_id("loops"))
final_denoising_strength = gr.Slider(minimum=0, maximum=1, step=0.01, label='Final denoising strength', value=0.5, elem_id=self.elem_id("final_denoising_strength"))
denoising_curve = gr.Dropdown(label="Denoising strength curve", choices=["Aggressive", "Linear", "Lazy"], value="Linear")
append_interrogation = gr.Dropdown(label="Append interrogated prompt at each iteration", choices=["None", "CLIP", "DeepBooru"], value="None")
return [loops, final_denoising_strength, denoising_curve, append_interrogation]
def run(self, p, loops, final_denoising_strength, denoising_curve, append_interrogation):
processing.fix_seed(p)
batch_count = p.n_iter
p.extra_generation_params = {
"Final denoising strength": final_denoising_strength,
"Denoising curve": denoising_curve
}
p.batch_size = 1
p.n_iter = 1
info = None
initial_seed = None
initial_info = None
initial_denoising_strength = p.denoising_strength
grids = []
all_images = []
original_init_image = p.init_images
original_prompt = p.prompt
state.job_count = loops * batch_count
initial_color_corrections = [processing.setup_color_correction(p.init_images[0])]
def calculate_denoising_strength(loop):
strength = initial_denoising_strength
if loops == 1:
return strength
progress = loop / (loops - 1)
match denoising_curve:
case "Aggressive":
strength = math.sin((progress) * math.pi * 0.5)
case "Lazy":
strength = 1 - math.cos((progress) * math.pi * 0.5)
case _:
strength = progress
change = (final_denoising_strength - initial_denoising_strength) * strength
return initial_denoising_strength + change
history = []
for n in range(batch_count):
# Reset to original init image at the start of each batch
p.init_images = original_init_image
# Reset to original denoising strength
p.denoising_strength = initial_denoising_strength
last_image = None
for i in range(loops):
p.n_iter = 1
p.batch_size = 1
p.do_not_save_grid = True
if opts.img2img_color_correction:
p.color_corrections = initial_color_corrections
if append_interrogation != "None":
p.prompt = original_prompt + ", " if original_prompt != "" else ""
if append_interrogation == "CLIP":
p.prompt += shared.interrogator.interrogate(p.init_images[0])
elif append_interrogation == "DeepBooru":
p.prompt += deepbooru.model.tag(p.init_images[0])
state.job = f"Iteration {i + 1}/{loops}, batch {n + 1}/{batch_count}"
processed = processing.process_images(p)
# Generation cancelled.
if state.interrupted:
break
if initial_seed is None:
initial_seed = processed.seed
initial_info = processed.info
p.seed = processed.seed + 1
p.denoising_strength = calculate_denoising_strength(i + 1)
if state.skipped:
break
last_image = processed.images[0]
p.init_images = [last_image]
if batch_count == 1:
history.append(last_image)
all_images.append(last_image)
if batch_count > 1 and not state.skipped and not state.interrupted:
history.append(last_image)
all_images.append(last_image)
if state.interrupted:
break
if len(history) > 1:
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)
if opts.return_grid:
grids.append(grid)
all_images = grids + all_images
processed = Processed(p, all_images, initial_seed, initial_info)
return processed