├── README.md └── scripts ├── advanced_loopback.py ├── advanced_loopback_blend.py └── quick_upscale.py /README.md: -------------------------------------------------------------------------------- 1 | # advanced-loopback-for-sd-webui 2 | 3 | This script is made to be used with the [AUTOMATIC1111 webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui). 4 | 5 | You can now set the CFG scale on scale with the denoising strength just by tweaking these sliders : 6 | ![image](https://user-images.githubusercontent.com/15731540/214673266-4c406822-44e8-480a-bfb8-03d528e174be.png) 7 | 8 | 9 | ## Installation 10 | 11 | Drop the script into your /scripts folder. 12 | 13 | Use the --allow-code argument. 14 | 15 | If you're using a Google Colab, you can add this in a code block before the one that starts the webui : 16 | 17 | !wget https://raw.githubusercontent.com/Extraltodeus/advanced-loopback-for-sd-webui/main/advanced_loopback.py -O /content/stable-diffusion-webui/scripts/advanced_loopback.py 18 | 19 | ## Features 20 | 21 | I will only describe the less obvious feats since you don't need to be explained what a zoom is :) 22 | 23 | The scripts UI looks like this and will show up in your img2img tab : 24 | 25 | ![image](https://user-images.githubusercontent.com/15731540/194636007-4dfaa7a1-b8d2-48a5-bd8d-b88b69fb8c90.png) 26 | 27 | - Use first image colors (custom color correction) 28 | 29 | This feature will use the colors from the init image instead of the last generated one (like the one already availaible does). This allows to avoid loosing colors when using the zoom feature. 30 | 31 | - Direction X/Y 32 | 33 | Will shift the cropped/zoomed next image up/down/left/right. The value is limited by the zoom level. 34 | 35 | - Denoising strength start/end 36 | 37 | ![image](https://user-images.githubusercontent.com/15731540/194637537-8b5dcb0e-f3c7-45bd-9c09-e60ffa0b76a8.png) 38 | 39 | This allows for a progressive parameter change (or sinusoidal, read below). Without the sine option enabled, it will simply put in proportion the starting value slider with the ending value. 40 | 41 | For example if you set it like this : 42 | 43 | ![image](https://user-images.githubusercontent.com/15731540/194638100-56389bf2-fd81-4721-801e-36df59414aba.png) 44 | 45 | The 5 first generated images will have a value of 0.2, then from 6 to 10 will ramp up from 0.2 to 0.6. 46 | 47 | This can be nice the have some visual rest in between the transitions while zooming. 48 | 49 | - Saturation enhancement per image 50 | 51 | Will increase/decrease slightly the saturation from one image to the next. 52 | 53 | If you are using the color correction, it will ony influence the contrasts. 54 | 55 | - Sine/exponentiation 56 | 57 | ![image](https://user-images.githubusercontent.com/15731540/194638484-351a6401-51b3-4c5d-a705-cb4372c08e5e.png) 58 | 59 | Allows a sinusoidal variation of these two parameters (the widest curve in the image below). 60 | 61 | Both of the options uses the start/end input boxes above. The maximum strength will be in between the minimum and maximum value and will then loop. 62 | 63 | The exponentiation sliders on the right kmakes the curves tighter, which will make the changes more sudden. 64 | 65 | ![expcurves](https://user-images.githubusercontent.com/15731540/194625416-ca0f3a3d-f0a3-4d00-9146-f30ac508a46b.png) 66 | 67 | The phase difference allows you to have the two variations not synchronised 68 | 69 | ![phase](https://user-images.githubusercontent.com/15731540/194625410-97754da7-4e61-49d9-9305-eeea1ec712cf.png) 70 | 71 | - prompt/seed options 72 | 73 | ![image](https://user-images.githubusercontent.com/15731540/194639114-86b477f3-8d94-4e7f-975a-828d93d2f738.png) 74 | 75 | The multiple prompts option will switch prompt after the "end" imagee has been reached (refering to the input box). 76 | 77 | So 0-10 will switch prompt every 10 images. 78 | 79 | The prompts have to be negative/positive, one per line. Just leave a blank line if you do not wish to use a negative prompt. 80 | 81 | ![image](https://user-images.githubusercontent.com/15731540/194639713-80063fd9-cb55-40a0-a588-28cd78ac164f.png) 82 | 83 | Note : "Same seed for everything" will accentuate the samplers noise. Euler A with the zoom will mostly create "warp drive" effects like in the example below. 84 | 85 | ## Example 86 | 87 | Unedited output with prompt switching/zoom/sine variations/same seed per prompt. 88 | 89 | "What you will see is 100% artificial" and birth to death related prompts. 90 | 91 | https://user-images.githubusercontent.com/15731540/194624678-544e52db-88d1-429e-b4f7-2a2a1e35cc60.mp4 92 | 93 | 94 | ### End note 95 | 96 | For now the script does not output a video immediatly. Just the images. I personnaly use ffmpeg to put it all together but you can go check on the [custom scripts page](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Custom-Scripts) as there is at least one that allows to do that with the webui (even though I haven't tested it). 97 | -------------------------------------------------------------------------------- /scripts/advanced_loopback.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from tqdm import trange 3 | from PIL import Image, ImageEnhance 4 | 5 | import modules.scripts as scripts 6 | import gradio as gr 7 | 8 | from modules import processing, shared, sd_samplers, images 9 | from modules.processing import Processed 10 | from modules.sd_samplers import samplers 11 | from modules.shared import opts, cmd_opts, state 12 | 13 | from math import sin, pi 14 | 15 | class Script(scripts.Script): 16 | def title(self): 17 | return "Advanced loopback" 18 | 19 | def show(self, is_img2img): 20 | return is_img2img 21 | 22 | def ui(self, is_img2img): 23 | loops = gr.Number(minimum=1, step=1, label='Loops', value=4) 24 | use_first_image_colors = gr.Checkbox(label='Use first image colors (custom color correction) ', value=False) 25 | 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) 26 | zoom_level = gr.Slider(minimum=1, maximum=1.1, step=0.001, label='Zoom level', value=1) 27 | with gr.Row(): 28 | direction_x = gr.Slider(minimum=-0.1, maximum=0.1, step=0.01, label='Direction X', value=0) 29 | direction_y = gr.Slider(minimum=-0.1, maximum=0.1, step=0.01, label='Direction Y', value=0) 30 | with gr.Row(): 31 | denoising_strength_first_image = gr.Number(minimum=0, step=1, label='Denoising strength start ', value=0) 32 | denoising_strength_last_image = gr.Number(minimum=0, step=1, label='Denoising strength end ', value=4) 33 | denoising_strength_min = gr.Slider(minimum=0.1, maximum=1, step=0.01, label='Denoising strength proportional change starting value ', value=0.1) 34 | 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) 35 | cfg_scale_min = gr.Slider(minimum=0.1, maximum=30, step=0.1, label='CFG scale proportional change starting value ', value=0.1) 36 | 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) 37 | saturation_per_image = gr.Slider(minimum=0.99, maximum=1.01, step=0.001, label='Saturation enhancement per image ', value=1) 38 | with gr.Row(): 39 | 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) 40 | phase_diff_denoising = gr.Slider(minimum=0, maximum=1, step=0.05, label='Phase difference', value=0) 41 | amplify_sine_variation_denoise = gr.Slider(minimum=1, maximum=10, step=1, label='Denoising strength exponentiation ', value=1) 42 | with gr.Row(): 43 | use_sine_variation_zoom = gr.Checkbox(label='Use sine zoom variation', value=False) 44 | phase_diff_zoom = gr.Slider(minimum=0, maximum=1, step=0.05, label='Phase difference', value=0) 45 | amplify_sine_variation_zoom = gr.Slider(minimum=1, maximum=10, step=1, label='Zoom exponentiation ', value=1) 46 | with gr.Row(): 47 | use_multi_prompts = gr.Checkbox(label='Use multiple prompts', value=False) 48 | same_seed_per_prompt = gr.Checkbox(label='Same seed per prompt', value=False) 49 | same_seed_always = gr.Checkbox(label='Same seed for everything', value=False) 50 | same_init_image = gr.Checkbox(label='Original init image for everything', value=False) 51 | 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) 52 | return [ 53 | loops, 54 | denoising_strength_change_factor, 55 | zoom_level, 56 | direction_x, 57 | direction_y, 58 | denoising_strength_first_image, 59 | denoising_strength_last_image, 60 | denoising_strength_min, 61 | denoising_strength_max, 62 | cfg_scale_min, 63 | cfg_scale_max, 64 | saturation_per_image, 65 | use_first_image_colors, 66 | use_sine_variation_dns, 67 | use_sine_variation_zoom, 68 | phase_diff_zoom, 69 | use_multi_prompts, 70 | multi_prompts, 71 | amplify_sine_variation_zoom, 72 | same_seed_per_prompt, 73 | phase_diff_denoising, 74 | amplify_sine_variation_denoise, 75 | same_seed_always, 76 | same_init_image 77 | ] 78 | 79 | def zoom_into(self, img, zoom, direction_x, direction_y): 80 | neg = lambda x: 1 if x > 0 else -1 81 | 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 82 | if abs(direction_y) > zoom-1 : direction_y = (zoom-1)*neg(direction_y)*0.999999999999999 83 | w, h = img.size 84 | x = w/2+direction_x*w/4 85 | y = h/2-direction_y*h/4 86 | zoom2 = zoom * 2 87 | img = img.crop((x - w / zoom2, y - h / zoom2, 88 | x + w / zoom2, y + h / zoom2)) 89 | return img.resize((w, h), Image.LANCZOS) 90 | 91 | def run(self, p, 92 | loops, 93 | denoising_strength_change_factor, 94 | zoom_level, 95 | direction_x, 96 | direction_y, 97 | denoising_strength_first_image, 98 | denoising_strength_last_image, 99 | denoising_strength_min, 100 | denoising_strength_max, 101 | cfg_scale_min, 102 | cfg_scale_max, 103 | saturation_per_image, 104 | use_first_image_colors, 105 | use_sine_variation_dns, 106 | use_sine_variation_zoom, 107 | phase_diff_zoom, 108 | use_multi_prompts, 109 | multi_prompts, 110 | amplify_sine_variation_zoom, 111 | same_seed_per_prompt, 112 | phase_diff_denoising, 113 | amplify_sine_variation_denoise, 114 | same_seed_always, 115 | same_init_image 116 | ): 117 | 118 | ppos = [] 119 | pneg = [] 120 | if use_multi_prompts : 121 | prompts_list = multi_prompts.splitlines() 122 | oddeven = lambda x: 1 if x%2==0 else 0 123 | for x in range(len(prompts_list)) : 124 | if oddeven(x): 125 | ppos.append(prompts_list[x]) 126 | else: 127 | pneg.append(prompts_list[x]) 128 | if len(pneg) < len(ppos) : 129 | pneg.append("") 130 | 131 | def remap_range(value, minIn, MaxIn, minOut, maxOut): 132 | if value > MaxIn: value = MaxIn; 133 | if value < minIn: value = minIn; 134 | finalValue = ((value - minIn) / (MaxIn - minIn)) * (maxOut - minOut) + minOut; 135 | return finalValue; 136 | 137 | def get_sin_steps(i,amplify,phase_diff=0): 138 | i -= denoising_strength_first_image 139 | range = (denoising_strength_last_image - denoising_strength_first_image) 140 | x = i % (range) 141 | y = remap_range(x,0,range,0,1) 142 | y = y ** amplify 143 | z = sin((y+phase_diff/2)*pi) 144 | return z 145 | 146 | processing.fix_seed(p) 147 | batch_count = p.n_iter 148 | p.extra_generation_params = { 149 | "Denoising strength change factor": denoising_strength_change_factor, 150 | 'Denoising strength proportional change start image':denoising_strength_first_image, 151 | 'Denoising strength proportional change end image':denoising_strength_last_image, 152 | 'Denoising strength proportional change starting value':denoising_strength_min, 153 | 'Denoising strength proportional change ending value':denoising_strength_max, 154 | 'CFG min':cfg_scale_min, 155 | 'CFG max':cfg_scale_max, 156 | 'use first image colors': use_first_image_colors, 157 | 'Saturation enhancement per image':saturation_per_image, 158 | 'Zoom level':zoom_level, 159 | } 160 | 161 | p.batch_size = 1 162 | p.n_iter = 1 163 | 164 | output_images, info = None, None 165 | initial_seed = None 166 | initial_info = None 167 | 168 | grids = [] 169 | all_images = [] 170 | state.job_count = loops * batch_count 171 | 172 | original_image = p.init_images[0].copy() 173 | if opts.img2img_color_correction: 174 | p.color_corrections = [processing.setup_color_correction(p.init_images[0])] 175 | 176 | 177 | for n in range(batch_count): 178 | history = [] 179 | multi_prompts_index = 0 180 | loops = round(loops) 181 | for i in range(loops): 182 | p.n_iter = 1 183 | p.batch_size = 1 184 | p.do_not_save_grid = True 185 | 186 | if use_multi_prompts : 187 | image_range = (denoising_strength_last_image - denoising_strength_first_image) 188 | il = i % (image_range) 189 | if i == 0: 190 | p.prompt = ppos[multi_prompts_index] 191 | p.negative_prompt = pneg[multi_prompts_index] 192 | print("Prompt :",p.prompt) 193 | print("Negative prompt :",p.negative_prompt) 194 | if il == 0 and i > 0: 195 | multi_prompts_index+=1 196 | try: 197 | if same_seed_per_prompt: 198 | if not same_seed_always: 199 | p.subseed = p.subseed + 1 if p.subseed_strength > 0 else p.subseed 200 | p.seed = p.seed + 1 if p.subseed_strength == 0 else p.seed 201 | p.prompt = ppos[multi_prompts_index] 202 | p.negative_prompt = pneg[multi_prompts_index] 203 | except Exception as e: 204 | multi_prompts_index = 0 205 | if same_seed_per_prompt: 206 | if not same_seed_always: 207 | p.subseed = p.subseed + 1 if p.subseed_strength > 0 else p.subseed 208 | p.seed = p.seed + 1 if p.subseed_strength == 0 else p.seed 209 | p.prompt = ppos[multi_prompts_index] 210 | p.negative_prompt = pneg[multi_prompts_index] 211 | # print("Prompt :",p.prompt) 212 | # print("Negative prompt :",p.negative_prompt) 213 | 214 | if use_first_image_colors: 215 | p.color_corrections = [processing.setup_color_correction(original_image)] 216 | 217 | state.job = f"Iteration {i + 1}/{loops}, batch {n + 1}/{batch_count}" 218 | 219 | if denoising_strength_max > 0.1 : 220 | if use_sine_variation_dns : 221 | ds = remap_range(get_sin_steps(i,amplify_sine_variation_denoise,phase_diff_denoising),0,1,denoising_strength_min,denoising_strength_max) 222 | else: 223 | ds = remap_range(i+1,denoising_strength_first_image,denoising_strength_last_image,denoising_strength_min,denoising_strength_max) 224 | p.denoising_strength = round(ds,3) 225 | print("Denoising strength : "+str(p.denoising_strength)) 226 | 227 | if cfg_scale_max > 0.1 : 228 | if use_sine_variation_dns : 229 | cfgs = remap_range(get_sin_steps(i,amplify_sine_variation_denoise,phase_diff_denoising),0,1,cfg_scale_min,cfg_scale_max) 230 | else: 231 | cfgs = remap_range(i+1,denoising_strength_first_image,denoising_strength_last_image,cfg_scale_min,cfg_scale_max) 232 | p.cfg_scale = round(cfgs,2) 233 | print("CFG scale : "+str(p.cfg_scale)) 234 | 235 | processed = processing.process_images(p) 236 | if zoom_level != 1: 237 | if use_sine_variation_zoom : 238 | if loops >= denoising_strength_first_image : 239 | z = remap_range(get_sin_steps(i,amplify_sine_variation_zoom,phase_diff_zoom),0,1,1,zoom_level) 240 | processed.images[0] = self.zoom_into(processed.images[0], z, direction_x, direction_y) 241 | print("Zoom level :",z) 242 | else: 243 | processed.images[0] = self.zoom_into(processed.images[0], zoom_level, direction_x, direction_y) 244 | 245 | if initial_seed is None: 246 | initial_seed = processed.seed 247 | initial_info = processed.info 248 | 249 | if not same_init_image : 250 | init_img = processed.images[0] 251 | else: 252 | init_img = original_image 253 | 254 | if saturation_per_image != 1 : 255 | init_img = ImageEnhance.Color(init_img).enhance(saturation_per_image) 256 | 257 | p.init_images = [init_img] 258 | if not same_seed_per_prompt: 259 | if not same_seed_always: 260 | p.subseed = p.subseed + 1 if p.subseed_strength > 0 else p.subseed 261 | p.seed = p.seed + 1 if p.subseed_strength == 0 else p.seed 262 | p.denoising_strength = min(max(p.denoising_strength * denoising_strength_change_factor, 0.1), 1) 263 | history.append(processed.images[0]) 264 | if state.interrupted: 265 | break 266 | 267 | grid = images.image_grid(history, rows=1) 268 | if opts.grid_save: 269 | 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) 270 | 271 | grids.append(grid) 272 | all_images += history 273 | 274 | if opts.return_grid: 275 | all_images = grids + all_images 276 | 277 | processed = Processed(p, all_images, initial_seed, initial_info) 278 | 279 | return processed 280 | -------------------------------------------------------------------------------- /scripts/advanced_loopback_blend.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from tqdm import trange 3 | from PIL import Image, ImageEnhance 4 | 5 | import modules.scripts as scripts 6 | import gradio as gr 7 | 8 | from modules import processing, shared, sd_samplers, images 9 | from modules.processing import Processed 10 | from modules.sd_samplers import samplers 11 | from modules.shared import opts, cmd_opts, state 12 | from copy import deepcopy 13 | from math import sin, pi 14 | 15 | class Script(scripts.Script): 16 | def title(self): 17 | return "Advanced loopback blend" 18 | 19 | def show(self, is_img2img): 20 | return is_img2img 21 | 22 | def ui(self, is_img2img): 23 | loops = gr.Number(minimum=1, step=1, label='Loops', value=4) 24 | use_first_image_colors = gr.Checkbox(label='Use first image colors (custom color correction) ', value=False) 25 | 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) 26 | with gr.Row(): 27 | zoom_level = gr.Slider(minimum=0, maximum=50, step=1, label='Zoom level ', value=0) 28 | zoom_blend = gr.Checkbox(label='Blend 50/50 with original when zoomed. Doesn\'t work with sine variation.', value=False) 29 | # zoom_refresh = gr.Slider(minimum=0, maximum=50, step=1, label='Refresh base image for blend every n iterations', value=0) 30 | # direction_x = gr.Slider(minimum=-0.1, maximum=0.1, step=0.01, label='Direction X', value=0) 31 | # direction_y = gr.Slider(minimum=-0.1, maximum=0.1, step=0.01, label='Direction Y', value=0) 32 | with gr.Row(): 33 | denoising_strength_first_image = gr.Number(minimum=0, step=1, label='Denoising strength start ', value=0) 34 | denoising_strength_last_image = gr.Number(minimum=0, step=1, label='Denoising strength end ', value=4) 35 | denoising_strength_min = gr.Slider(minimum=0.1, maximum=1, step=0.01, label='Denoising strength proportional change starting value ', value=0.1) 36 | 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) 37 | cfg_scale_min = gr.Slider(minimum=0.1, maximum=30, step=0.1, label='CFG scale proportional change starting value ', value=0.1) 38 | 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) 39 | saturation_per_image = gr.Slider(minimum=0.99, maximum=1.01, step=0.001, label='Saturation enhancement per image ', value=1) 40 | with gr.Row(): 41 | 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) 42 | phase_diff_denoising = gr.Slider(minimum=0, maximum=1, step=0.05, label='Phase difference', value=0) 43 | amplify_sine_variation_denoise = gr.Slider(minimum=1, maximum=10, step=1, label='Denoising strength exponentiation ', value=1) 44 | with gr.Row(): 45 | use_sine_variation_zoom = gr.Checkbox(label='Use sine zoom variation', value=False) 46 | phase_diff_zoom = gr.Slider(minimum=0, maximum=1, step=0.05, label='Phase difference', value=0) 47 | amplify_sine_variation_zoom = gr.Slider(minimum=1, maximum=10, step=1, label='Zoom exponentiation ', value=1) 48 | with gr.Row(): 49 | use_multi_prompts = gr.Checkbox(label='Use multiple prompts', value=False) 50 | same_seed_per_prompt = gr.Checkbox(label='Same seed per prompt', value=False) 51 | same_seed_always = gr.Checkbox(label='Same seed for everything', value=False) 52 | same_init_image = gr.Checkbox(label='Original init image for everything', value=False) 53 | 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) 54 | return [ 55 | loops, 56 | denoising_strength_change_factor, 57 | zoom_level, 58 | zoom_blend, 59 | # zoom_refresh, 60 | # direction_x, 61 | # direction_y, 62 | denoising_strength_first_image, 63 | denoising_strength_last_image, 64 | denoising_strength_min, 65 | denoising_strength_max, 66 | cfg_scale_min, 67 | cfg_scale_max, 68 | saturation_per_image, 69 | use_first_image_colors, 70 | use_sine_variation_dns, 71 | use_sine_variation_zoom, 72 | phase_diff_zoom, 73 | use_multi_prompts, 74 | multi_prompts, 75 | amplify_sine_variation_zoom, 76 | same_seed_per_prompt, 77 | phase_diff_denoising, 78 | amplify_sine_variation_denoise, 79 | same_seed_always, 80 | same_init_image 81 | ] 82 | 83 | def zoom_into(self, img, zoom): 84 | w, h = img.size 85 | img = img.crop((zoom,zoom,w-zoom,h-zoom)) 86 | return img.resize((w, h), Image.LANCZOS) 87 | 88 | def run(self, p, 89 | loops, 90 | denoising_strength_change_factor, 91 | zoom_level, 92 | zoom_blend, 93 | # zoom_refresh, 94 | # direction_x, 95 | # direction_y, 96 | denoising_strength_first_image, 97 | denoising_strength_last_image, 98 | denoising_strength_min, 99 | denoising_strength_max, 100 | cfg_scale_min, 101 | cfg_scale_max, 102 | saturation_per_image, 103 | use_first_image_colors, 104 | use_sine_variation_dns, 105 | use_sine_variation_zoom, 106 | phase_diff_zoom, 107 | use_multi_prompts, 108 | multi_prompts, 109 | amplify_sine_variation_zoom, 110 | same_seed_per_prompt, 111 | phase_diff_denoising, 112 | amplify_sine_variation_denoise, 113 | same_seed_always, 114 | same_init_image 115 | ): 116 | 117 | ppos = [] 118 | pneg = [] 119 | if use_multi_prompts : 120 | prompts_list = multi_prompts.splitlines() 121 | oddeven = lambda x: 1 if x%2==0 else 0 122 | for x in range(len(prompts_list)) : 123 | if oddeven(x): 124 | ppos.append(prompts_list[x]) 125 | else: 126 | pneg.append(prompts_list[x]) 127 | if len(pneg) < len(ppos) : 128 | pneg.append("") 129 | 130 | def remap_range(value, minIn, MaxIn, minOut, maxOut): 131 | if value > MaxIn: value = MaxIn; 132 | if value < minIn: value = minIn; 133 | finalValue = ((value - minIn) / (MaxIn - minIn)) * (maxOut - minOut) + minOut; 134 | return finalValue; 135 | 136 | def get_sin_steps(i,amplify,phase_diff=0): 137 | i -= denoising_strength_first_image 138 | range = (denoising_strength_last_image - denoising_strength_first_image) 139 | x = i % (range) 140 | y = remap_range(x,0,range,0,1) 141 | y = y ** amplify 142 | z = sin((y+phase_diff/2)*pi) 143 | return z 144 | 145 | processing.fix_seed(p) 146 | batch_count = p.n_iter 147 | p.extra_generation_params = { 148 | "Denoising strength change factor": denoising_strength_change_factor, 149 | 'Denoising strength proportional change start image':denoising_strength_first_image, 150 | 'Denoising strength proportional change end image':denoising_strength_last_image, 151 | 'Denoising strength proportional change starting value':denoising_strength_min, 152 | 'Denoising strength proportional change ending value':denoising_strength_max, 153 | 'CFG min':cfg_scale_min, 154 | 'CFG max':cfg_scale_max, 155 | 'use first image colors': use_first_image_colors, 156 | 'Saturation enhancement per image':saturation_per_image, 157 | 'Zoom level':zoom_level, 158 | } 159 | 160 | p.batch_size = 1 161 | p.n_iter = 1 162 | 163 | output_images, info = None, None 164 | initial_seed = None 165 | initial_info = None 166 | 167 | grids = [] 168 | all_images = [] 169 | state.job_count = loops * batch_count 170 | 171 | original_image = p.init_images[0].copy() 172 | original_image_for_zoom = p.init_images[0].copy() 173 | if opts.img2img_color_correction: 174 | p.color_corrections = [processing.setup_color_correction(p.init_images[0])] 175 | 176 | 177 | for n in range(batch_count): 178 | history = [] 179 | multi_prompts_index = 0 180 | loops = round(loops) 181 | for i in range(loops): 182 | p.n_iter = 1 183 | p.batch_size = 1 184 | p.do_not_save_grid = True 185 | 186 | if use_multi_prompts : 187 | image_range = (denoising_strength_last_image - denoising_strength_first_image) 188 | il = i % (image_range) 189 | if i == 0: 190 | p.prompt = ppos[multi_prompts_index] 191 | p.negative_prompt = pneg[multi_prompts_index] 192 | print("Prompt :",p.prompt) 193 | print("Negative prompt :",p.negative_prompt) 194 | if il == 0 and i > 0: 195 | multi_prompts_index+=1 196 | try: 197 | if same_seed_per_prompt: 198 | if not same_seed_always: 199 | p.subseed = p.subseed + 1 if p.subseed_strength > 0 else p.subseed 200 | p.seed = p.seed + 1 if p.subseed_strength == 0 else p.seed 201 | p.prompt = ppos[multi_prompts_index] 202 | p.negative_prompt = pneg[multi_prompts_index] 203 | except Exception as e: 204 | multi_prompts_index = 0 205 | if same_seed_per_prompt: 206 | if not same_seed_always: 207 | p.subseed = p.subseed + 1 if p.subseed_strength > 0 else p.subseed 208 | p.seed = p.seed + 1 if p.subseed_strength == 0 else p.seed 209 | p.prompt = ppos[multi_prompts_index] 210 | p.negative_prompt = pneg[multi_prompts_index] 211 | # print("Prompt :",p.prompt) 212 | # print("Negative prompt :",p.negative_prompt) 213 | 214 | if use_first_image_colors: 215 | p.color_corrections = [processing.setup_color_correction(original_image)] 216 | 217 | state.job = f"Iteration {i + 1}/{loops}, batch {n + 1}/{batch_count}" 218 | 219 | if denoising_strength_max > 0.1 : 220 | if use_sine_variation_dns : 221 | ds = remap_range(get_sin_steps(i,amplify_sine_variation_denoise,phase_diff_denoising),0,1,denoising_strength_min,denoising_strength_max) 222 | else: 223 | ds = remap_range(i+1,denoising_strength_first_image,denoising_strength_last_image,denoising_strength_min,denoising_strength_max) 224 | p.denoising_strength = round(ds,3) 225 | print("Denoising strength : "+str(p.denoising_strength)) 226 | 227 | if cfg_scale_max > 0.1 : 228 | if use_sine_variation_dns : 229 | cfgs = remap_range(get_sin_steps(i,amplify_sine_variation_denoise,phase_diff_denoising),0,1,cfg_scale_min,cfg_scale_max) 230 | else: 231 | cfgs = remap_range(i+1,denoising_strength_first_image,denoising_strength_last_image,cfg_scale_min,cfg_scale_max) 232 | p.cfg_scale = round(cfgs,2) 233 | print("CFG scale : "+str(p.cfg_scale)) 234 | 235 | processed = processing.process_images(p) 236 | if zoom_level > 0: 237 | if use_sine_variation_zoom : 238 | if loops >= denoising_strength_first_image : 239 | z = remap_range(get_sin_steps(i,amplify_sine_variation_zoom,phase_diff_zoom),0,1,1,zoom_level) 240 | processed.images[0] = self.zoom_into(processed.images[0], z) 241 | print("Zoom level :",z) 242 | else: 243 | processed.images[0] = self.zoom_into(processed.images[0], zoom_level) 244 | if zoom_blend: 245 | # if zoom_refresh > 0 and i%zoom_refresh == 0: 246 | # original_image_for_zoom = processed.images[0].copy() 247 | original_image_zoomed = self.zoom_into(original_image_for_zoom.copy(), zoom_level*(i+1)) 248 | 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) 249 | 250 | 251 | if initial_seed is None: 252 | initial_seed = processed.seed 253 | initial_info = processed.info 254 | 255 | if not same_init_image : 256 | init_img = processed.images[0] 257 | else: 258 | init_img = original_image 259 | 260 | if saturation_per_image != 1 : 261 | init_img = ImageEnhance.Color(init_img).enhance(saturation_per_image) 262 | 263 | p.init_images = [init_img] 264 | if not same_seed_per_prompt: 265 | if not same_seed_always: 266 | p.subseed = p.subseed + 1 if p.subseed_strength > 0 else p.subseed 267 | p.seed = p.seed + 1 if p.subseed_strength == 0 else p.seed 268 | p.denoising_strength = min(max(p.denoising_strength * denoising_strength_change_factor, 0.1), 1) 269 | history.append(processed.images[0]) 270 | if state.interrupted: 271 | break 272 | 273 | grid = images.image_grid(history, rows=1) 274 | if opts.grid_save: 275 | 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) 276 | 277 | grids.append(grid) 278 | all_images += history 279 | 280 | if opts.return_grid: 281 | all_images = grids + all_images 282 | 283 | processed = Processed(p, all_images, initial_seed, initial_info) 284 | 285 | return processed 286 | -------------------------------------------------------------------------------- /scripts/quick_upscale.py: -------------------------------------------------------------------------------- 1 | 2 | import math 3 | import os 4 | import sys 5 | import traceback 6 | import random 7 | 8 | import modules.scripts as scripts 9 | import modules.images as images 10 | import gradio as gr 11 | 12 | from modules.processing import Processed, process_images 13 | from PIL import Image 14 | from modules.shared import opts, cmd_opts, state 15 | 16 | class Script(scripts.Script): 17 | def title(self): 18 | return "Lanczos quick upscale" 19 | 20 | def ui(self, is_img2img): 21 | upscale_factor = gr.Slider(minimum=1, maximum=4, step=0.1, label='Upscale factor', value=2) 22 | return [upscale_factor] 23 | 24 | def run(self, p, upscale_factor): 25 | infotexts = [] 26 | def simple_upscale(img, upscale_factor): 27 | w, h = img.size 28 | w = int(w * upscale_factor) 29 | h = int(h * upscale_factor) 30 | return img.resize((w, h), Image.Resampling.LANCZOS) 31 | 32 | state.job_count = p.n_iter 33 | p.n_iter = 1 34 | p.do_not_save_samples = True 35 | output_images = [] 36 | for batch_no in range(state.job_count): 37 | # print(f"\nJob : {batch_no}/{state.job_count}\nSeed : {p.seed}\nPrompt : {p.prompt}") 38 | proc = process_images(p) 39 | infotexts.append(proc.info) 40 | proc.images[0] = simple_upscale(proc.images[0], upscale_factor) 41 | images.save_image(proc.images[0], p.outpath_samples, "", proc.seed, proc.prompt, opts.samples_format, info= proc.info, p=p) 42 | output_images += proc.images 43 | p.seed = proc.seed + 1 44 | 45 | return Processed(p, images, infotexts=infotexts,index_of_first_image=0) 46 | --------------------------------------------------------------------------------