dikdimon commited on
Commit
a0ef636
·
verified ·
1 Parent(s): ca9784f

Upload custom-hires-fix-for-automatic1111 using SD-Hub

Browse files
custom-hires-fix-for-automatic1111/README.md ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Custom Hires Fix (webui Extension)
2
+ ## Webui Extension for customizing highres fix and improve details (currently separated from original highres fix)
3
+
4
+
5
+ #### Update 16.10.23:
6
+ - added ControlNet support: choose preprocessor/model in CN settings, but don't enable unit
7
+ - added Lora support: put Lora in extension prompt to enable Lora only for upscaling, put Lora in negative prompt to disable active Lora
8
+
9
+ #### Update 02.07.23:
10
+ - code rewritten again
11
+ - simplified settings
12
+ - fixed batch generation and image saving
13
+
14
+ #### Update 13.06.23:
15
+ - added gaussian noise instead of random
16
+
17
+ #### Update 29.05.23:
18
+ - added ToMe optomization in second pass, latest Auto1111 update required, controlled via "Token merging ratio for high-res pass" in settings
19
+ - added "Sharp" setting, should be used only with "Smoothness" if image is too blurry
20
+
21
+ #### Update 12.05.23:
22
+ - added smoothness for negative, completely fix ghosting/smears/dirt on flat colors with high denoising
23
+
24
+ #### Update 02.04.23:
25
+ ###### Don't forget to clear ui-config.json!
26
+ - upscale separated from original high-res fix
27
+ - now works with img2img
28
+ - many fixes
29
+
custom-hires-fix-for-automatic1111/config.yaml ADDED
File without changes
custom-hires-fix-for-automatic1111/scripts/__pycache__/custom_hires_fix.cpython-310.pyc ADDED
Binary file (14.4 kB). View file
 
custom-hires-fix-for-automatic1111/scripts/custom_hires_fix.py ADDED
@@ -0,0 +1,443 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from os.path import exists
3
+
4
+ from tqdm import trange
5
+ from modules import scripts, shared, processing, sd_schedulers, sd_samplers, script_callbacks, rng
6
+ from modules import images, devices, prompt_parser, sd_models, ui_components, sd_models, extra_networks
7
+ import modules.images as images
8
+ import k_diffusion
9
+
10
+ import gradio as gr
11
+ import numpy as np
12
+ from PIL import Image, ImageEnhance
13
+ import torch
14
+ import importlib
15
+ from copy import copy
16
+ from PIL import Image
17
+ import json
18
+ import gradio as gr
19
+
20
+ quote_swap = str.maketrans('\'"', '"\'')
21
+
22
+ def safe_import(import_name, pkg_name = None):
23
+ try:
24
+ __import__(import_name)
25
+ except Exception:
26
+ pkg_name = pkg_name or import_name
27
+ import pip
28
+ if hasattr(pip, 'main'):
29
+ pip.main(['install', pkg_name])
30
+ else:
31
+ pip._internal.main(['install', pkg_name])
32
+ __import__(import_name)
33
+
34
+
35
+ safe_import('kornia')
36
+ safe_import('omegaconf')
37
+ safe_import('pathlib')
38
+ from omegaconf import DictConfig, OmegaConf
39
+ from pathlib import Path
40
+ import kornia
41
+ from skimage import exposure
42
+
43
+ config_path = Path(__file__).parent.resolve() / '../config.yaml'
44
+
45
+
46
+ class CustomHiresFix(scripts.Script):
47
+ def __init__(self):
48
+ super().__init__()
49
+ if not exists(config_path):
50
+ open(config_path, 'w').close()
51
+ self.config: DictConfig = OmegaConf.load(config_path)
52
+ self.callback_set = False
53
+ self.orig_clip_skip = None
54
+ self.cfg = 0
55
+ self.p: processing.StableDiffusionProcessing = None
56
+ self.pp = None
57
+ self.sampler = None
58
+ self.cond = None
59
+ self.uncond = None
60
+ self.prompt = ""
61
+ self.negative_prompt = ""
62
+ self.step = None
63
+ self.tv = None
64
+ self.width = None
65
+ self.height = None
66
+ self.extra_data = None
67
+ self.use_cn = False
68
+ self.external_code = None
69
+ self.cn_image = None
70
+ self.cn_units = []
71
+
72
+ def title(self):
73
+ return "Custom Hires Fix"
74
+
75
+ def show(self, is_img2img):
76
+ return scripts.AlwaysVisible
77
+
78
+ def ui(self, is_img2img):
79
+ sampler_names = ['Restart + DPM++ 3M SDE'] + [x.name for x in sd_samplers.visible_samplers()]
80
+ scheduler_names = ['Use same scheduler'] + [x.label for x in sd_schedulers.schedulers]
81
+
82
+ with gr.Accordion(label='Custom hires fix', open=False):
83
+ enable = gr.Checkbox(label='Enable extension', value=self.config.get('enable', False))
84
+ with gr.Row():
85
+ width = gr.Slider(minimum=512, maximum=2048, step=8,
86
+ label="Upscale width to",
87
+ value=self.config.get('width', 1024), allow_flagging='never', show_progress=False)
88
+ height = gr.Slider(minimum=512, maximum=2048, step=8,
89
+ label="Upscale height to",
90
+ value=self.config.get('height', 0), allow_flagging='never', show_progress=False)
91
+ steps = gr.Slider(minimum=8, maximum=25, step=1,
92
+ label="Steps",
93
+ value=self.config.get('steps', 15))
94
+
95
+ with gr.Row():
96
+ prompt = gr.Textbox(label='Prompt for upscale (added to generation prompt)',
97
+ placeholder='Leave empty for using generation prompt',
98
+ value=self.prompt)
99
+ with gr.Row():
100
+ negative_prompt = gr.Textbox(label='Negative prompt for upscale (replaces generation prompt)',
101
+ placeholder='Leave empty for using generation negative prompt',
102
+ value=self.negative_prompt)
103
+ with gr.Row():
104
+ first_upscaler = gr.Dropdown([*[x.name for x in shared.sd_upscalers
105
+ if x.name not in ['None', 'Nearest', 'LDSR']]],
106
+ label='First upscaler',
107
+ value=self.config.get('first_upscaler', 'R-ESRGAN 4x+'))
108
+ second_upscaler = gr.Dropdown([*[x.name for x in shared.sd_upscalers
109
+ if x.name not in ['None', 'Nearest', 'LDSR']]],
110
+ label='Second upscaler',
111
+ value=self.config.get('second_upscaler', 'R-ESRGAN 4x+'))
112
+ with gr.Row():
113
+ first_latent = gr.Slider(minimum=0.0, maximum=1.0, step=0.01,
114
+ label="Latent upscale ratio (1)",
115
+ value=self.config.get('first_latent', 0.3))
116
+ second_latent = gr.Slider(minimum=0.0, maximum=1.0, step=0.01,
117
+ label="Latent upscale ratio (2)",
118
+ value=self.config.get('second_latent', 0.1))
119
+ with gr.Row():
120
+ filter = gr.Dropdown(['Noise sync (sharp)', 'Morphological (smooth)', 'Combined (balanced)'],
121
+ label='Filter mode',
122
+ value=self.config.get('filter', 'Noise sync (sharp)'))
123
+ strength = gr.Slider(minimum=1.0, maximum=3.5, step=0.1, label="Generation strength",
124
+ value=self.config.get('strength', 2.0))
125
+ denoise_offset = gr.Slider(minimum=-0.05, maximum=0.15, step=0.01,
126
+ label="Denoise offset",
127
+ value=self.config.get('denoise_offset', 0.05))
128
+ with gr.Accordion(label='Extra', open=False):
129
+ with gr.Row():
130
+ filter_offset = gr.Slider(minimum=-1.0, maximum=1.0, step=0.1,
131
+ label="Filter offset (higher - smoother)",
132
+ value=self.config.get('filter_offset', 0.0))
133
+ clip_skip = gr.Slider(minimum=0, maximum=5, step=1,
134
+ label="Clip skip for upscale (0 - not change)",
135
+ value=self.config.get('clip_skip', 0))
136
+ with gr.Row():
137
+ start_control_at = gr.Slider(minimum=0.0, maximum=0.7, step=0.01,
138
+ label="CN start for enabled units",
139
+ value=self.config.get('start_control_at', 0.0))
140
+ cn_ref = gr.Checkbox(label='Use last image for reference', value=self.config.get('cn_ref', False))
141
+ with gr.Row():
142
+ sampler = gr.Dropdown(sampler_names, label='Sampler', value=sampler_names[0])
143
+ scheduler = gr.Dropdown(
144
+ label='Schedule type',
145
+ elem_id="custom_hires_fix_scheduler",
146
+ choices=scheduler_names,
147
+ value=scheduler_names[0]
148
+ )
149
+ cfg = gr.Slider(minimum=0, maximum=30, step=0.5, label="CFG Scale", value=self.cfg)
150
+
151
+
152
+ if is_img2img:
153
+ width.change(fn=lambda x: gr.update(value=0), inputs=width, outputs=height)
154
+ height.change(fn=lambda x: gr.update(value=0), inputs=height, outputs=width)
155
+ else:
156
+ width.change(fn=lambda x: gr.update(value=0), inputs=width, outputs=height)
157
+ height.change(fn=lambda x: gr.update(value=0), inputs=height, outputs=width)
158
+
159
+ ui = [enable, width, height, steps, first_upscaler, second_upscaler, first_latent, second_latent, prompt,
160
+ negative_prompt, strength, filter, filter_offset, denoise_offset, clip_skip, sampler, cfg, scheduler, cn_ref, start_control_at]
161
+ for elem in ui:
162
+ setattr(elem, "do_not_save_to_config", True)
163
+ return ui
164
+
165
+ def process(self, p, *args, **kwargs):
166
+ self.p = p
167
+ self.cn_units = []
168
+ try:
169
+ self.external_code = importlib.import_module('extensions.sd-webui-controlnet.scripts.external_code', 'external_code')
170
+ cn_units = self.external_code.get_all_units_in_processing(p)
171
+ for unit in cn_units:
172
+ self.cn_units += [unit]
173
+ self.use_cn = len(self.cn_units) > 0
174
+ except ImportError:
175
+ self.use_cn = False
176
+
177
+ def postprocess_image(self, p, pp: scripts.PostprocessImageArgs,
178
+ enable, width, height, steps, first_upscaler, second_upscaler, first_latent, second_latent, prompt,
179
+ negative_prompt, strength, filter, filter_offset, denoise_offset, clip_skip, sampler, cfg, scheduler, cn_ref, start_control_at
180
+ ):
181
+ if not enable:
182
+ return
183
+ self.step = 0
184
+ self.pp = pp
185
+ self.config.width = width
186
+ self.config.height = height
187
+ self.config.prompt = prompt.strip()
188
+ self.config.negative_prompt = negative_prompt.strip()
189
+ self.config.steps = steps
190
+ self.config.first_upscaler = first_upscaler
191
+ self.config.second_upscaler = second_upscaler
192
+ self.config.first_latent = first_latent
193
+ self.config.second_latent = second_latent
194
+ self.config.strength = strength
195
+ self.config.filter = filter
196
+ self.config.filter_offset = filter_offset
197
+ self.config.denoise_offset = denoise_offset
198
+ self.config.clip_skip = clip_skip
199
+ self.config.sampler = sampler
200
+ self.config.cn_ref = cn_ref
201
+ self.config.start_control_at = start_control_at
202
+ self.orig_clip_skip = shared.opts.CLIP_stop_at_last_layers
203
+ self.cfg = cfg if cfg else p.cfg_scale
204
+
205
+ if clip_skip > 0:
206
+ shared.opts.CLIP_stop_at_last_layers = clip_skip
207
+ if 'Restart' in self.config.sampler:
208
+ self.sampler = sd_samplers.create_sampler('Restart', p.sd_model)
209
+ else:
210
+ self.sampler = sd_samplers.create_sampler(sampler, p.sd_model)
211
+
212
+ def denoise_callback(params: script_callbacks.CFGDenoiserParams):
213
+ if params.sampling_step > 0:
214
+ p.cfg_scale = self.cfg
215
+ if self.step == 1 and self.config.strength != 1.0:
216
+ params.sigma[-1] = params.sigma[0] * (1 - (1 - self.config.strength) / 100)
217
+ elif self.step == 2 and self.config.filter == 'Noise sync (sharp)':
218
+ params.sigma[-1] = params.sigma[0] * (1 - (self.tv - 1 + self.config.filter_offset - (self.config.denoise_offset * 5)) / 50)
219
+ elif self.step == 2 and self.config.filter == 'Combined (balanced)':
220
+ params.sigma[-1] = params.sigma[0] * (1 - (self.tv - 1 + self.config.filter_offset - (self.config.denoise_offset * 5)) / 100)
221
+
222
+ if self.callback_set is False:
223
+ script_callbacks.on_cfg_denoiser(denoise_callback)
224
+ self.callback_set = True
225
+
226
+ _, loras_act = extra_networks.parse_prompt(prompt)
227
+ extra_networks.activate(p, loras_act)
228
+ _, loras_deact = extra_networks.parse_prompt(negative_prompt)
229
+ extra_networks.deactivate(p, loras_deact)
230
+
231
+ self.cn_image = pp.image
232
+
233
+ try:
234
+ with devices.autocast():
235
+ shared.state.nextjob()
236
+ x = self.gen(pp.image)
237
+ shared.state.nextjob()
238
+ x = self.filter(x)
239
+ sd_models.apply_token_merging(p.sd_model, p.get_token_merging_ratio())
240
+ pp.image = x
241
+ finally:
242
+ # Always restore and cleanup even if an exception occurs mid-way.
243
+ shared.opts.CLIP_stop_at_last_layers = self.orig_clip_skip
244
+ extra_networks.deactivate(p, loras_act)
245
+ OmegaConf.save(self.config, config_path)
246
+
247
+ def enable_cn(self, image: np.ndarray):
248
+ for unit in self.cn_units:
249
+ if unit.model != 'None':
250
+ unit.guidance_start = self.config.start_control_at if unit.enabled else unit.guidance_start
251
+ # Use the smaller side of the image (height vs width)
252
+ unit.processor_res = min(image.shape[0], image.shape[1])
253
+ unit.enabled = True
254
+ if unit.image is None:
255
+ unit.image = image
256
+ self.p.width = image.shape[1]
257
+ self.p.height = image.shape[0]
258
+ self.external_code.update_cn_script_in_processing(self.p, self.cn_units)
259
+ for script in self.p.scripts.alwayson_scripts:
260
+ if script.title().lower() == 'controlnet':
261
+ script.controlnet_hack(self.p)
262
+
263
+ def process_prompt(self):
264
+ prompt = self.p.prompt.strip().split('AND', 1)[0]
265
+ if self.config.prompt != '':
266
+ prompt = f'{prompt} {self.config.prompt}'
267
+
268
+ if self.config.negative_prompt != '':
269
+ negative_prompt = self.config.negative_prompt
270
+ else:
271
+ negative_prompt = self.p.negative_prompt.strip()
272
+
273
+ with devices.autocast():
274
+ if self.width is not None and self.height is not None and hasattr(prompt_parser, 'SdConditioning'):
275
+ c = prompt_parser.SdConditioning([prompt], False, self.width, self.height)
276
+ uc = prompt_parser.SdConditioning([negative_prompt], False, self.width, self.height)
277
+ else:
278
+ c = [prompt]
279
+ uc = [negative_prompt]
280
+ self.cond = prompt_parser.get_multicond_learned_conditioning(shared.sd_model, c, self.config.steps)
281
+ self.uncond = prompt_parser.get_learned_conditioning(shared.sd_model, uc, self.config.steps)
282
+
283
+ def gen(self, x):
284
+ self.step = 1
285
+ ratio = x.width / x.height
286
+ self.width = self.config.width if self.config.width > 0 else int(self.config.height * ratio)
287
+ self.height = self.config.height if self.config.height > 0 else int(self.config.width / ratio)
288
+ self.width = int((self.width - x.width) // 2 + x.width)
289
+ self.height = int((self.height - x.height) // 2 + x.height)
290
+ sd_models.apply_token_merging(self.p.sd_model, self.p.get_token_merging_ratio(for_hr=True) / 2)
291
+
292
+ if self.use_cn:
293
+ self.enable_cn(np.array(self.cn_image.resize((self.width, self.height))))
294
+
295
+ with devices.autocast(), torch.inference_mode():
296
+ self.process_prompt()
297
+
298
+ x_big = None
299
+ if self.config.first_latent > 0:
300
+ image = np.array(x).astype(np.float32) / 255.0
301
+ image = np.moveaxis(image, 2, 0)
302
+ decoded_sample = torch.from_numpy(image)
303
+ decoded_sample = decoded_sample.to(shared.device).to(devices.dtype_vae)
304
+ decoded_sample = 2.0 * decoded_sample - 1.0
305
+ encoded_sample = shared.sd_model.encode_first_stage(decoded_sample.unsqueeze(0).to(devices.dtype_vae))
306
+ sample = shared.sd_model.get_first_stage_encoding(encoded_sample)
307
+ x_big = torch.nn.functional.interpolate(sample, (self.height // 8, self.width // 8), mode='nearest')
308
+
309
+ if self.config.first_latent < 1:
310
+ x = images.resize_image(0, x, self.width, self.height,
311
+ upscaler_name=self.config.first_upscaler)
312
+ image = np.array(x).astype(np.float32) / 255.0
313
+ image = np.moveaxis(image, 2, 0)
314
+ decoded_sample = torch.from_numpy(image)
315
+ decoded_sample = decoded_sample.to(shared.device).to(devices.dtype_vae)
316
+ decoded_sample = 2.0 * decoded_sample - 1.0
317
+ encoded_sample = shared.sd_model.encode_first_stage(decoded_sample.unsqueeze(0).to(devices.dtype_vae))
318
+ sample = shared.sd_model.get_first_stage_encoding(encoded_sample)
319
+ else:
320
+ sample = x_big
321
+ if x_big is not None and self.config.first_latent != 1:
322
+ sample = (sample * (1 - self.config.first_latent)) + (x_big * self.config.first_latent)
323
+ image_conditioning = self.p.img2img_image_conditioning(decoded_sample, sample)
324
+
325
+ noise = torch.zeros_like(sample)
326
+ noise = kornia.augmentation.RandomGaussianNoise(mean=0.0, std=1.0, p=1.0)(noise)
327
+ steps = int(max(((self.p.steps - self.config.steps) / 2) + self.config.steps, self.config.steps))
328
+ self.p.denoising_strength = 0.45 + self.config.denoise_offset * 0.2
329
+ self.p.cfg_scale = self.cfg + 3
330
+
331
+ def denoiser_override(n):
332
+ sigmas = k_diffusion.sampling.get_sigmas_polyexponential(n, 0.01, 15, 0.5, devices.device)
333
+ return sigmas
334
+
335
+ self.p.rng = rng.ImageRNG(sample.shape[1:], self.p.seeds, subseeds=self.p.subseeds,
336
+ subseed_strength=self.p.subseed_strength,
337
+ seed_resize_from_h=self.p.seed_resize_from_h, seed_resize_from_w=self.p.seed_resize_from_w)
338
+
339
+ self.p.sampler_noise_scheduler_override = denoiser_override
340
+ self.p.batch_size = 1
341
+ sample = self.sampler.sample_img2img(self.p, sample.to(devices.dtype), noise, self.cond, self.uncond,
342
+ steps=steps, image_conditioning=image_conditioning).to(devices.dtype_vae)
343
+ b, c, w, h = sample.size()
344
+ self.tv = kornia.losses.TotalVariation()(sample).mean() / (w * h)
345
+ devices.torch_gc()
346
+ decoded_sample = processing.decode_first_stage(shared.sd_model, sample)
347
+ if math.isnan(decoded_sample.min()):
348
+ devices.torch_gc()
349
+ sample = torch.clamp(sample, -3, 3)
350
+ decoded_sample = processing.decode_first_stage(shared.sd_model, sample)
351
+ decoded_sample = torch.clamp((decoded_sample + 1.0) / 2.0, min=0.0, max=1.0).squeeze()
352
+ x_sample = 255. * np.moveaxis(decoded_sample.cpu().numpy(), 0, 2)
353
+ x_sample = x_sample.astype(np.uint8)
354
+ image = Image.fromarray(x_sample)
355
+ return image
356
+
357
+
358
+ def filter(self, x):
359
+ # Choose sampler for the 2nd stage.
360
+ if 'Restart' in self.config.sampler and 'DPM++ 3M SDE' in self.config.sampler:
361
+ # UI option "Restart + DPM++ 3M SDE":
362
+ # 1st pass uses Restart (см. postprocess_image), 2nd pass uses DPM++ 3M SDE.
363
+ self.sampler = sd_samplers.create_sampler('DPM++ 3M SDE', shared.sd_model)
364
+ else:
365
+ # Otherwise, respect the chosen sampler as-is.
366
+ self.sampler = sd_samplers.create_sampler(self.config.sampler, shared.sd_model)
367
+ self.step = 2
368
+ ratio = x.width / x.height
369
+ self.width = self.config.width if self.config.width > 0 else int(self.config.height * ratio)
370
+ self.height = self.config.height if self.config.height > 0 else int(self.config.width / ratio)
371
+ sd_models.apply_token_merging(self.p.sd_model, self.p.get_token_merging_ratio(for_hr=True))
372
+
373
+ if self.use_cn:
374
+ self.cn_image = x if self.config.cn_ref else self.cn_image
375
+ self.enable_cn(np.array(self.cn_image.resize((self.width, self.height))))
376
+
377
+ with devices.autocast(), torch.inference_mode():
378
+ self.process_prompt()
379
+
380
+ x_big = None
381
+ if self.config.second_latent > 0:
382
+ image = np.array(x).astype(np.float32) / 255.0
383
+ image = np.moveaxis(image, 2, 0)
384
+ decoded_sample = torch.from_numpy(image)
385
+ decoded_sample = decoded_sample.to(shared.device).to(devices.dtype_vae)
386
+ decoded_sample = 2.0 * decoded_sample - 1.0
387
+ encoded_sample = shared.sd_model.encode_first_stage(decoded_sample.unsqueeze(0).to(devices.dtype_vae))
388
+ sample = shared.sd_model.get_first_stage_encoding(encoded_sample)
389
+ x_big = torch.nn.functional.interpolate(sample, (self.height // 8, self.width // 8), mode='nearest')
390
+
391
+ if self.config.second_latent < 1:
392
+ x = images.resize_image(0, x, self.width, self.height, upscaler_name=self.config.second_upscaler)
393
+ image = np.array(x).astype(np.float32) / 255.0
394
+ image = np.moveaxis(image, 2, 0)
395
+ decoded_sample = torch.from_numpy(image)
396
+ decoded_sample = decoded_sample.to(shared.device).to(devices.dtype_vae)
397
+ decoded_sample = 2.0 * decoded_sample - 1.0
398
+ encoded_sample = shared.sd_model.encode_first_stage(decoded_sample.unsqueeze(0).to(devices.dtype_vae))
399
+ sample = shared.sd_model.get_first_stage_encoding(encoded_sample)
400
+ else:
401
+ sample = x_big
402
+ if x_big is not None and self.config.second_latent != 1:
403
+ sample = (sample * (1 - self.config.second_latent)) + (x_big * self.config.second_latent)
404
+ image_conditioning = self.p.img2img_image_conditioning(decoded_sample, sample)
405
+
406
+ noise = torch.zeros_like(sample)
407
+ noise = kornia.augmentation.RandomGaussianNoise(mean=0.0, std=1.0, p=1.0)(noise)
408
+ self.p.denoising_strength = 0.45 + self.config.denoise_offset
409
+ self.p.cfg_scale = self.cfg + 3
410
+
411
+ if self.config.filter == 'Morphological (smooth)':
412
+ noise_mask = kornia.morphology.gradient(sample, torch.ones(5, 5).to(devices.device))
413
+ noise_mask = kornia.filters.median_blur(noise_mask, (3, 3))
414
+ noise_mask = (0.1 + noise_mask / noise_mask.max()) * (max(
415
+ (1.75 - (self.tv - 1) * 4), 1.75) - self.config.filter_offset)
416
+ noise = noise * noise_mask
417
+ elif self.config.filter == 'Combined (balanced)':
418
+ noise_mask = kornia.morphology.gradient(sample, torch.ones(5, 5).to(devices.device))
419
+ noise_mask = kornia.filters.median_blur(noise_mask, (3, 3))
420
+ noise_mask = (0.1 + noise_mask / noise_mask.max()) * (max(
421
+ (1.75 - (self.tv - 1) / 2), 1.75) - self.config.filter_offset)
422
+ noise = noise * noise_mask
423
+
424
+ def denoiser_override(n):
425
+ return k_diffusion.sampling.get_sigmas_polyexponential(n, 0.01, 7, 0.5, devices.device)
426
+
427
+ self.p.sampler_noise_scheduler_override = denoiser_override
428
+ self.p.batch_size = 1
429
+ samples = self.sampler.sample_img2img(self.p, sample.to(devices.dtype), noise, self.cond, self.uncond,
430
+ steps=self.config.steps, image_conditioning=image_conditioning
431
+ ).to(devices.dtype_vae)
432
+ devices.torch_gc()
433
+ self.p.iteration += 1
434
+ decoded_sample = processing.decode_first_stage(shared.sd_model, samples)
435
+ if math.isnan(decoded_sample.min()):
436
+ devices.torch_gc()
437
+ samples = torch.clamp(samples, -3, 3)
438
+ decoded_sample = processing.decode_first_stage(shared.sd_model, samples)
439
+ decoded_sample = torch.clamp((decoded_sample + 1.0) / 2.0, min=0.0, max=1.0).squeeze()
440
+ x_sample = 255. * np.moveaxis(decoded_sample.cpu().numpy(), 0, 2)
441
+ x_sample = x_sample.astype(np.uint8)
442
+ image = Image.fromarray(x_sample)
443
+ return image