.
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ultimate SD Upscale extension for [AUTOMATIC1111 Stable Diffusion web UI](https://github.com/AUTOMATIC1111/stable-diffusion-webui)
2 | Now you have the opportunity to use a large denoise (0.3-0.5) and not spawn many artifacts. Works on any video card, since you can use a 512x512 tile size and the image will converge.
3 |
4 | News channel: https://t.me/usdunews
5 |
6 | # Instructions
7 | All instructions can be found on the project's [wiki](https://github.com/Coyote-A/ultimate-upscale-for-automatic1111/wiki).
8 |
9 | # Refs
10 |
11 | https://github.com/ssitu/ComfyUI_UltimateSDUpscale - Implementation for ComfyUI
12 |
13 | # Examples
14 | More on [wiki page](https://github.com/Coyote-A/ultimate-upscale-for-automatic1111/wiki/Examples)
15 |
16 |
17 | E1
18 | Original image
19 |
20 | 
21 |
22 | 2k upscaled. **Tile size**: 512, **Padding**: 32, **Mask blur**: 16, **Denoise**: 0.4
23 | 
24 |
25 |
26 |
27 | E2
28 | Original image
29 |
30 | 
31 |
32 | 2k upscaled. **Tile size**: 768, **Padding**: 55, **Mask blur**: 20, **Denoise**: 0.35
33 | 
34 |
35 | 4k upscaled. **Tile size**: 768, **Padding**: 55, **Mask blur**: 20, **Denoise**: 0.35
36 | 
37 |
38 |
39 |
40 | E3
41 | Original image
42 |
43 | 
44 |
45 | 4k upscaled. **Tile size**: 768, **Padding**: 55, **Mask blur**: 20, **Denoise**: 0.4
46 | 
47 |
48 |
49 | # API Usage
50 |
51 | ```javascript
52 | {
53 | "script_name" : "ultimate sd upscale",
54 | "script_args" : [
55 | null, // _ (not used)
56 | 512, // tile_width
57 | 512, // tile_height
58 | 8, // mask_blur
59 | 32, // padding
60 | 64, // seams_fix_width
61 | 0.35, // seams_fix_denoise
62 | 32, // seams_fix_padding
63 | 0, // upscaler_index
64 | true, // save_upscaled_image a.k.a Upscaled
65 | 0, // redraw_mode
66 | false, // save_seams_fix_image a.k.a Seams fix
67 | 8, // seams_fix_mask_blur
68 | 0, // seams_fix_type
69 | 0, // target_size_type
70 | 2048, // custom_width
71 | 2048, // custom_height
72 | 2 // custom_scale
73 | ]
74 | }
75 | ```
76 | upscaler_index
77 | | Value | |
78 | |:-------------:| -----:|
79 | | 0 | None |
80 | | 1 | Lanczos |
81 | | 2 | Nearest |
82 | | 3 | ESRGAN_4x |
83 | | 4 | LDSR |
84 | | 5 | R-ESRGAN_4x+ |
85 | | 6 | R-ESRGAN 4x+ Anime6B |
86 | | 7 | ScuNET GAN |
87 | | 8 | ScuNET PSNR |
88 | | 9 | SwinIR 4x |
89 |
90 | redraw_mode
91 | | Value | |
92 | |:-------------:| -----:|
93 | | 0 | Linear |
94 | | 1 | Chess |
95 | | 2 | None |
96 |
97 | seams_fix_mask_blur
98 | | Value | |
99 | |:-------------:| -----:|
100 | | 0 | None |
101 | | 1 | BAND_PASS |
102 | | 2 | HALF_TILE |
103 | | 3 | HALF_TILE_PLUS_INTERSECTIONS |
104 |
105 | seams_fix_type
106 | | Value | |
107 | |:-------------:| -----:|
108 | | 0 | None |
109 | | 1 | Band pass |
110 | | 2 | Half tile offset pass |
111 | | 3 | Half tile offset pass + intersections |
112 |
113 | seams_fix_type
114 | | Value | |
115 | |:-------------:| -----:|
116 | | 0 | From img2img2 settings |
117 | | 1 | Custom size |
118 | | 2 | Scale from image size |
119 |
120 |
--------------------------------------------------------------------------------
/scripts/ultimate-upscale.py:
--------------------------------------------------------------------------------
1 | import math
2 | import gradio as gr
3 | from PIL import Image, ImageDraw, ImageOps
4 | from modules import processing, shared, images, devices, scripts
5 | from modules.processing import StableDiffusionProcessing
6 | from modules.processing import Processed
7 | from modules.shared import opts, state
8 | from enum import Enum
9 |
10 | elem_id_prefix = "ultimateupscale"
11 |
12 | class USDUMode(Enum):
13 | LINEAR = 0
14 | CHESS = 1
15 | NONE = 2
16 |
17 | class USDUSFMode(Enum):
18 | NONE = 0
19 | BAND_PASS = 1
20 | HALF_TILE = 2
21 | HALF_TILE_PLUS_INTERSECTIONS = 3
22 |
23 | class USDUpscaler():
24 |
25 | def __init__(self, p, image, upscaler_index:int, save_redraw, save_seams_fix, tile_width, tile_height) -> None:
26 | self.p:StableDiffusionProcessing = p
27 | self.image:Image = image
28 | self.scale_factor = math.ceil(max(p.width, p.height) / max(image.width, image.height))
29 | self.upscaler = shared.sd_upscalers[upscaler_index]
30 | self.redraw = USDURedraw()
31 | self.redraw.save = save_redraw
32 | self.redraw.tile_width = tile_width if tile_width > 0 else tile_height
33 | self.redraw.tile_height = tile_height if tile_height > 0 else tile_width
34 | self.seams_fix = USDUSeamsFix()
35 | self.seams_fix.save = save_seams_fix
36 | self.seams_fix.tile_width = tile_width if tile_width > 0 else tile_height
37 | self.seams_fix.tile_height = tile_height if tile_height > 0 else tile_width
38 | self.initial_info = None
39 | self.rows = math.ceil(self.p.height / self.redraw.tile_height)
40 | self.cols = math.ceil(self.p.width / self.redraw.tile_width)
41 |
42 | def get_factor(self, num):
43 | # Its just return, don't need elif
44 | if num == 1:
45 | return 2
46 | if num % 4 == 0:
47 | return 4
48 | if num % 3 == 0:
49 | return 3
50 | if num % 2 == 0:
51 | return 2
52 | return 0
53 |
54 | def get_factors(self):
55 | scales = []
56 | current_scale = 1
57 | current_scale_factor = self.get_factor(self.scale_factor)
58 | while current_scale_factor == 0:
59 | self.scale_factor += 1
60 | current_scale_factor = self.get_factor(self.scale_factor)
61 | while current_scale < self.scale_factor:
62 | current_scale_factor = self.get_factor(self.scale_factor // current_scale)
63 | scales.append(current_scale_factor)
64 | current_scale = current_scale * current_scale_factor
65 | if current_scale_factor == 0:
66 | break
67 | self.scales = enumerate(scales)
68 |
69 | def upscale(self):
70 | # Log info
71 | print(f"Canva size: {self.p.width}x{self.p.height}")
72 | print(f"Image size: {self.image.width}x{self.image.height}")
73 | print(f"Scale factor: {self.scale_factor}")
74 | # Check upscaler is not empty
75 | if self.upscaler.name == "None":
76 | self.image = self.image.resize((self.p.width, self.p.height), resample=Image.LANCZOS)
77 | return
78 | # Get list with scale factors
79 | self.get_factors()
80 | # Upscaling image over all factors
81 | for index, value in self.scales:
82 | print(f"Upscaling iteration {index+1} with scale factor {value}")
83 | self.image = self.upscaler.scaler.upscale(self.image, value, self.upscaler.data_path)
84 | # Resize image to set values
85 | self.image = self.image.resize((self.p.width, self.p.height), resample=Image.LANCZOS)
86 |
87 | def setup_redraw(self, redraw_mode, padding, mask_blur):
88 | self.redraw.mode = USDUMode(redraw_mode)
89 | self.redraw.enabled = self.redraw.mode != USDUMode.NONE
90 | self.redraw.padding = padding
91 | self.p.mask_blur = mask_blur
92 |
93 | def setup_seams_fix(self, padding, denoise, mask_blur, width, mode):
94 | self.seams_fix.padding = padding
95 | self.seams_fix.denoise = denoise
96 | self.seams_fix.mask_blur = mask_blur
97 | self.seams_fix.width = width
98 | self.seams_fix.mode = USDUSFMode(mode)
99 | self.seams_fix.enabled = self.seams_fix.mode != USDUSFMode.NONE
100 |
101 | def save_image(self):
102 | if type(self.p.prompt) != list:
103 | images.save_image(self.image, self.p.outpath_samples, "", self.p.seed, self.p.prompt, opts.samples_format, info=self.initial_info, p=self.p)
104 | else:
105 | images.save_image(self.image, self.p.outpath_samples, "", self.p.seed, self.p.prompt[0], opts.samples_format, info=self.initial_info, p=self.p)
106 |
107 | def calc_jobs_count(self):
108 | redraw_job_count = (self.rows * self.cols) if self.redraw.enabled else 0
109 | seams_job_count = 0
110 | if self.seams_fix.mode == USDUSFMode.BAND_PASS:
111 | seams_job_count = self.rows + self.cols - 2
112 | elif self.seams_fix.mode == USDUSFMode.HALF_TILE:
113 | seams_job_count = self.rows * (self.cols - 1) + (self.rows - 1) * self.cols
114 | elif self.seams_fix.mode == USDUSFMode.HALF_TILE_PLUS_INTERSECTIONS:
115 | seams_job_count = self.rows * (self.cols - 1) + (self.rows - 1) * self.cols + (self.rows - 1) * (self.cols - 1)
116 |
117 | state.job_count = redraw_job_count + seams_job_count
118 |
119 | def print_info(self):
120 | print(f"Tile size: {self.redraw.tile_width}x{self.redraw.tile_height}")
121 | print(f"Tiles amount: {self.rows * self.cols}")
122 | print(f"Grid: {self.rows}x{self.cols}")
123 | print(f"Redraw enabled: {self.redraw.enabled}")
124 | print(f"Seams fix mode: {self.seams_fix.mode.name}")
125 |
126 | def add_extra_info(self):
127 | self.p.extra_generation_params["Ultimate SD upscale upscaler"] = self.upscaler.name
128 | self.p.extra_generation_params["Ultimate SD upscale tile_width"] = self.redraw.tile_width
129 | self.p.extra_generation_params["Ultimate SD upscale tile_height"] = self.redraw.tile_height
130 | self.p.extra_generation_params["Ultimate SD upscale mask_blur"] = self.p.mask_blur
131 | self.p.extra_generation_params["Ultimate SD upscale padding"] = self.redraw.padding
132 |
133 | def process(self):
134 | state.begin()
135 | self.calc_jobs_count()
136 | self.result_images = []
137 | if self.redraw.enabled:
138 | self.image = self.redraw.start(self.p, self.image, self.rows, self.cols)
139 | self.initial_info = self.redraw.initial_info
140 | self.result_images.append(self.image)
141 | if self.redraw.save:
142 | self.save_image()
143 |
144 | if self.seams_fix.enabled:
145 | self.image = self.seams_fix.start(self.p, self.image, self.rows, self.cols)
146 | self.initial_info = self.seams_fix.initial_info
147 | self.result_images.append(self.image)
148 | if self.seams_fix.save:
149 | self.save_image()
150 | state.end()
151 |
152 | class USDURedraw():
153 |
154 | def init_draw(self, p, width, height):
155 | p.inpaint_full_res = True
156 | p.inpaint_full_res_padding = self.padding
157 | p.width = math.ceil((self.tile_width+self.padding) / 64) * 64
158 | p.height = math.ceil((self.tile_height+self.padding) / 64) * 64
159 | mask = Image.new("L", (width, height), "black")
160 | draw = ImageDraw.Draw(mask)
161 | return mask, draw
162 |
163 | def calc_rectangle(self, xi, yi):
164 | x1 = xi * self.tile_width
165 | y1 = yi * self.tile_height
166 | x2 = xi * self.tile_width + self.tile_width
167 | y2 = yi * self.tile_height + self.tile_height
168 |
169 | return x1, y1, x2, y2
170 |
171 | def linear_process(self, p, image, rows, cols):
172 | mask, draw = self.init_draw(p, image.width, image.height)
173 | for yi in range(rows):
174 | for xi in range(cols):
175 | if state.interrupted:
176 | break
177 | draw.rectangle(self.calc_rectangle(xi, yi), fill="white")
178 | p.init_images = [image]
179 | p.image_mask = mask
180 | processed = processing.process_images(p)
181 | draw.rectangle(self.calc_rectangle(xi, yi), fill="black")
182 | if (len(processed.images) > 0):
183 | image = processed.images[0]
184 |
185 | p.width = image.width
186 | p.height = image.height
187 | self.initial_info = processed.infotext(p, 0)
188 |
189 | return image
190 |
191 | def chess_process(self, p, image, rows, cols):
192 | mask, draw = self.init_draw(p, image.width, image.height)
193 | tiles = []
194 | # calc tiles colors
195 | for yi in range(rows):
196 | for xi in range(cols):
197 | if state.interrupted:
198 | break
199 | if xi == 0:
200 | tiles.append([])
201 | color = xi % 2 == 0
202 | if yi > 0 and yi % 2 != 0:
203 | color = not color
204 | tiles[yi].append(color)
205 |
206 | for yi in range(len(tiles)):
207 | for xi in range(len(tiles[yi])):
208 | if state.interrupted:
209 | break
210 | if not tiles[yi][xi]:
211 | tiles[yi][xi] = not tiles[yi][xi]
212 | continue
213 | tiles[yi][xi] = not tiles[yi][xi]
214 | draw.rectangle(self.calc_rectangle(xi, yi), fill="white")
215 | p.init_images = [image]
216 | p.image_mask = mask
217 | processed = processing.process_images(p)
218 | draw.rectangle(self.calc_rectangle(xi, yi), fill="black")
219 | if (len(processed.images) > 0):
220 | image = processed.images[0]
221 |
222 | for yi in range(len(tiles)):
223 | for xi in range(len(tiles[yi])):
224 | if state.interrupted:
225 | break
226 | if not tiles[yi][xi]:
227 | continue
228 | draw.rectangle(self.calc_rectangle(xi, yi), fill="white")
229 | p.init_images = [image]
230 | p.image_mask = mask
231 | processed = processing.process_images(p)
232 | draw.rectangle(self.calc_rectangle(xi, yi), fill="black")
233 | if (len(processed.images) > 0):
234 | image = processed.images[0]
235 |
236 | p.width = image.width
237 | p.height = image.height
238 | self.initial_info = processed.infotext(p, 0)
239 |
240 | return image
241 |
242 | def start(self, p, image, rows, cols):
243 | self.initial_info = None
244 | if self.mode == USDUMode.LINEAR:
245 | return self.linear_process(p, image, rows, cols)
246 | if self.mode == USDUMode.CHESS:
247 | return self.chess_process(p, image, rows, cols)
248 |
249 | class USDUSeamsFix():
250 |
251 | def init_draw(self, p):
252 | self.initial_info = None
253 | p.width = math.ceil((self.tile_width+self.padding) / 64) * 64
254 | p.height = math.ceil((self.tile_height+self.padding) / 64) * 64
255 |
256 | def half_tile_process(self, p, image, rows, cols):
257 |
258 | self.init_draw(p)
259 | processed = None
260 |
261 | gradient = Image.linear_gradient("L")
262 | row_gradient = Image.new("L", (self.tile_width, self.tile_height), "black")
263 | row_gradient.paste(gradient.resize(
264 | (self.tile_width, self.tile_height//2), resample=Image.BICUBIC), (0, 0))
265 | row_gradient.paste(gradient.rotate(180).resize(
266 | (self.tile_width, self.tile_height//2), resample=Image.BICUBIC),
267 | (0, self.tile_height//2))
268 | col_gradient = Image.new("L", (self.tile_width, self.tile_height), "black")
269 | col_gradient.paste(gradient.rotate(90).resize(
270 | (self.tile_width//2, self.tile_height), resample=Image.BICUBIC), (0, 0))
271 | col_gradient.paste(gradient.rotate(270).resize(
272 | (self.tile_width//2, self.tile_height), resample=Image.BICUBIC), (self.tile_width//2, 0))
273 |
274 | p.denoising_strength = self.denoise
275 | p.mask_blur = self.mask_blur
276 |
277 | for yi in range(rows-1):
278 | for xi in range(cols):
279 | if state.interrupted:
280 | break
281 | p.width = self.tile_width
282 | p.height = self.tile_height
283 | p.inpaint_full_res = True
284 | p.inpaint_full_res_padding = self.padding
285 | mask = Image.new("L", (image.width, image.height), "black")
286 | mask.paste(row_gradient, (xi*self.tile_width, yi*self.tile_height + self.tile_height//2))
287 |
288 | p.init_images = [image]
289 | p.image_mask = mask
290 | processed = processing.process_images(p)
291 | if (len(processed.images) > 0):
292 | image = processed.images[0]
293 |
294 | for yi in range(rows):
295 | for xi in range(cols-1):
296 | if state.interrupted:
297 | break
298 | p.width = self.tile_width
299 | p.height = self.tile_height
300 | p.inpaint_full_res = True
301 | p.inpaint_full_res_padding = self.padding
302 | mask = Image.new("L", (image.width, image.height), "black")
303 | mask.paste(col_gradient, (xi*self.tile_width+self.tile_width//2, yi*self.tile_height))
304 |
305 | p.init_images = [image]
306 | p.image_mask = mask
307 | processed = processing.process_images(p)
308 | if (len(processed.images) > 0):
309 | image = processed.images[0]
310 |
311 | p.width = image.width
312 | p.height = image.height
313 | if processed is not None:
314 | self.initial_info = processed.infotext(p, 0)
315 |
316 | return image
317 |
318 | def half_tile_process_corners(self, p, image, rows, cols):
319 | fixed_image = self.half_tile_process(p, image, rows, cols)
320 | processed = None
321 | self.init_draw(p)
322 | gradient = Image.radial_gradient("L").resize(
323 | (self.tile_width, self.tile_height), resample=Image.BICUBIC)
324 | gradient = ImageOps.invert(gradient)
325 | p.denoising_strength = self.denoise
326 | #p.mask_blur = 0
327 | p.mask_blur = self.mask_blur
328 |
329 | for yi in range(rows-1):
330 | for xi in range(cols-1):
331 | if state.interrupted:
332 | break
333 | p.width = self.tile_width
334 | p.height = self.tile_height
335 | p.inpaint_full_res = True
336 | p.inpaint_full_res_padding = 0
337 | mask = Image.new("L", (fixed_image.width, fixed_image.height), "black")
338 | mask.paste(gradient, (xi*self.tile_width + self.tile_width//2,
339 | yi*self.tile_height + self.tile_height//2))
340 |
341 | p.init_images = [fixed_image]
342 | p.image_mask = mask
343 | processed = processing.process_images(p)
344 | if (len(processed.images) > 0):
345 | fixed_image = processed.images[0]
346 |
347 | p.width = fixed_image.width
348 | p.height = fixed_image.height
349 | if processed is not None:
350 | self.initial_info = processed.infotext(p, 0)
351 |
352 | return fixed_image
353 |
354 | def band_pass_process(self, p, image, cols, rows):
355 |
356 | self.init_draw(p)
357 | processed = None
358 |
359 | p.denoising_strength = self.denoise
360 | p.mask_blur = 0
361 |
362 | gradient = Image.linear_gradient("L")
363 | mirror_gradient = Image.new("L", (256, 256), "black")
364 | mirror_gradient.paste(gradient.resize((256, 128), resample=Image.BICUBIC), (0, 0))
365 | mirror_gradient.paste(gradient.rotate(180).resize((256, 128), resample=Image.BICUBIC), (0, 128))
366 |
367 | row_gradient = mirror_gradient.resize((image.width, self.width), resample=Image.BICUBIC)
368 | col_gradient = mirror_gradient.rotate(90).resize((self.width, image.height), resample=Image.BICUBIC)
369 |
370 | for xi in range(1, rows):
371 | if state.interrupted:
372 | break
373 | p.width = self.width + self.padding * 2
374 | p.height = image.height
375 | p.inpaint_full_res = True
376 | p.inpaint_full_res_padding = self.padding
377 | mask = Image.new("L", (image.width, image.height), "black")
378 | mask.paste(col_gradient, (xi * self.tile_width - self.width // 2, 0))
379 |
380 | p.init_images = [image]
381 | p.image_mask = mask
382 | processed = processing.process_images(p)
383 | if (len(processed.images) > 0):
384 | image = processed.images[0]
385 | for yi in range(1, cols):
386 | if state.interrupted:
387 | break
388 | p.width = image.width
389 | p.height = self.width + self.padding * 2
390 | p.inpaint_full_res = True
391 | p.inpaint_full_res_padding = self.padding
392 | mask = Image.new("L", (image.width, image.height), "black")
393 | mask.paste(row_gradient, (0, yi * self.tile_height - self.width // 2))
394 |
395 | p.init_images = [image]
396 | p.image_mask = mask
397 | processed = processing.process_images(p)
398 | if (len(processed.images) > 0):
399 | image = processed.images[0]
400 |
401 | p.width = image.width
402 | p.height = image.height
403 | if processed is not None:
404 | self.initial_info = processed.infotext(p, 0)
405 |
406 | return image
407 |
408 | def start(self, p, image, rows, cols):
409 | if USDUSFMode(self.mode) == USDUSFMode.BAND_PASS:
410 | return self.band_pass_process(p, image, rows, cols)
411 | elif USDUSFMode(self.mode) == USDUSFMode.HALF_TILE:
412 | return self.half_tile_process(p, image, rows, cols)
413 | elif USDUSFMode(self.mode) == USDUSFMode.HALF_TILE_PLUS_INTERSECTIONS:
414 | return self.half_tile_process_corners(p, image, rows, cols)
415 | else:
416 | return image
417 |
418 | class Script(scripts.Script):
419 | def title(self):
420 | return "Ultimate SD upscale"
421 |
422 | def show(self, is_img2img):
423 | return is_img2img
424 |
425 | def ui(self, is_img2img):
426 |
427 | target_size_types = [
428 | "From img2img2 settings",
429 | "Custom size",
430 | "Scale from image size"
431 | ]
432 |
433 | seams_fix_types = [
434 | "None",
435 | "Band pass",
436 | "Half tile offset pass",
437 | "Half tile offset pass + intersections"
438 | ]
439 |
440 | redrow_modes = [
441 | "Linear",
442 | "Chess",
443 | "None"
444 | ]
445 |
446 | info = gr.HTML(
447 | "Will upscale the image depending on the selected target size type
")
448 |
449 | with gr.Row():
450 | target_size_type = gr.Dropdown(label="Target size type", elem_id=f"{elem_id_prefix}_target_size_type", choices=[k for k in target_size_types], type="index",
451 | value=next(iter(target_size_types)))
452 |
453 | custom_width = gr.Slider(label='Custom width', elem_id=f"{elem_id_prefix}_custom_width", minimum=64, maximum=8192, step=64, value=2048, visible=False, interactive=True)
454 | custom_height = gr.Slider(label='Custom height', elem_id=f"{elem_id_prefix}_custom_height", minimum=64, maximum=8192, step=64, value=2048, visible=False, interactive=True)
455 | custom_scale = gr.Slider(label='Scale', elem_id=f"{elem_id_prefix}_custom_scale", minimum=1, maximum=16, step=0.01, value=2, visible=False, interactive=True)
456 |
457 | gr.HTML("Redraw options:
")
458 | with gr.Row():
459 | upscaler_index = gr.Radio(label='Upscaler', elem_id=f"{elem_id_prefix}_upscaler_index", choices=[x.name for x in shared.sd_upscalers],
460 | value=shared.sd_upscalers[0].name, type="index")
461 | with gr.Row():
462 | redraw_mode = gr.Dropdown(label="Type", elem_id=f"{elem_id_prefix}_redraw_mode", choices=[k for k in redrow_modes], type="index", value=next(iter(redrow_modes)))
463 | tile_width = gr.Slider(elem_id=f"{elem_id_prefix}_tile_width", minimum=0, maximum=2048, step=64, label='Tile width', value=512)
464 | tile_height = gr.Slider(elem_id=f"{elem_id_prefix}_tile_height", minimum=0, maximum=2048, step=64, label='Tile height', value=0)
465 | mask_blur = gr.Slider(elem_id=f"{elem_id_prefix}_mask_blur", label='Mask blur', minimum=0, maximum=64, step=1, value=8)
466 | padding = gr.Slider(elem_id=f"{elem_id_prefix}_padding", label='Padding', minimum=0, maximum=512, step=1, value=32)
467 | gr.HTML("Seams fix:
")
468 | with gr.Row():
469 | seams_fix_type = gr.Dropdown(label="Type", elem_id=f"{elem_id_prefix}_seams_fix_type", choices=[k for k in seams_fix_types], type="index", value=next(iter(seams_fix_types)))
470 | seams_fix_denoise = gr.Slider(label='Denoise', elem_id=f"{elem_id_prefix}_seams_fix_denoise", minimum=0, maximum=1, step=0.01, value=0.35, visible=False, interactive=True)
471 | seams_fix_width = gr.Slider(label='Width', elem_id=f"{elem_id_prefix}_seams_fix_width", minimum=0, maximum=128, step=1, value=64, visible=False, interactive=True)
472 | seams_fix_mask_blur = gr.Slider(label='Mask blur', elem_id=f"{elem_id_prefix}_seams_fix_mask_blur", minimum=0, maximum=64, step=1, value=4, visible=False, interactive=True)
473 | seams_fix_padding = gr.Slider(label='Padding', elem_id=f"{elem_id_prefix}_seams_fix_padding", minimum=0, maximum=128, step=1, value=16, visible=False, interactive=True)
474 | gr.HTML("Save options:
")
475 | with gr.Row():
476 | save_upscaled_image = gr.Checkbox(label="Upscaled", elem_id=f"{elem_id_prefix}_save_upscaled_image", value=True)
477 | save_seams_fix_image = gr.Checkbox(label="Seams fix", elem_id=f"{elem_id_prefix}_save_seams_fix_image", value=False)
478 |
479 | def select_fix_type(fix_index):
480 | all_visible = fix_index != 0
481 | mask_blur_visible = fix_index == 2 or fix_index == 3
482 | width_visible = fix_index == 1
483 |
484 | return [gr.update(visible=all_visible),
485 | gr.update(visible=width_visible),
486 | gr.update(visible=mask_blur_visible),
487 | gr.update(visible=all_visible)]
488 |
489 | seams_fix_type.change(
490 | fn=select_fix_type,
491 | inputs=seams_fix_type,
492 | outputs=[seams_fix_denoise, seams_fix_width, seams_fix_mask_blur, seams_fix_padding]
493 | )
494 |
495 | def select_scale_type(scale_index):
496 | is_custom_size = scale_index == 1
497 | is_custom_scale = scale_index == 2
498 |
499 | return [gr.update(visible=is_custom_size),
500 | gr.update(visible=is_custom_size),
501 | gr.update(visible=is_custom_scale),
502 | ]
503 |
504 | target_size_type.change(
505 | fn=select_scale_type,
506 | inputs=target_size_type,
507 | outputs=[custom_width, custom_height, custom_scale]
508 | )
509 |
510 | def init_field(scale_name):
511 | try:
512 | scale_index = target_size_types.index(scale_name)
513 | custom_width.visible = custom_height.visible = scale_index == 1
514 | custom_scale.visible = scale_index == 2
515 | except:
516 | pass
517 |
518 | target_size_type.init_field = init_field
519 |
520 | return [info, tile_width, tile_height, mask_blur, padding, seams_fix_width, seams_fix_denoise, seams_fix_padding,
521 | upscaler_index, save_upscaled_image, redraw_mode, save_seams_fix_image, seams_fix_mask_blur,
522 | seams_fix_type, target_size_type, custom_width, custom_height, custom_scale]
523 |
524 | def run(self, p, _, tile_width, tile_height, mask_blur, padding, seams_fix_width, seams_fix_denoise, seams_fix_padding,
525 | upscaler_index, save_upscaled_image, redraw_mode, save_seams_fix_image, seams_fix_mask_blur,
526 | seams_fix_type, target_size_type, custom_width, custom_height, custom_scale):
527 |
528 | # Init
529 | processing.fix_seed(p)
530 | devices.torch_gc()
531 |
532 | p.do_not_save_grid = True
533 | p.do_not_save_samples = True
534 | p.inpaint_full_res = False
535 |
536 | p.inpainting_fill = 1
537 | p.n_iter = 1
538 | p.batch_size = 1
539 |
540 | seed = p.seed
541 |
542 | # Init image
543 | init_img = p.init_images[0]
544 | if init_img == None:
545 | return Processed(p, [], seed, "Empty image")
546 | init_img = images.flatten(init_img, opts.img2img_background_color)
547 |
548 | #override size
549 | if target_size_type == 1:
550 | p.width = custom_width
551 | p.height = custom_height
552 | if target_size_type == 2:
553 | p.width = math.ceil((init_img.width * custom_scale) / 64) * 64
554 | p.height = math.ceil((init_img.height * custom_scale) / 64) * 64
555 |
556 | # Upscaling
557 | upscaler = USDUpscaler(p, init_img, upscaler_index, save_upscaled_image, save_seams_fix_image, tile_width, tile_height)
558 | upscaler.upscale()
559 |
560 | # Drawing
561 | upscaler.setup_redraw(redraw_mode, padding, mask_blur)
562 | upscaler.setup_seams_fix(seams_fix_padding, seams_fix_denoise, seams_fix_mask_blur, seams_fix_width, seams_fix_type)
563 | upscaler.print_info()
564 | upscaler.add_extra_info()
565 | upscaler.process()
566 | result_images = upscaler.result_images
567 |
568 | return Processed(p, result_images, seed, upscaler.initial_info if upscaler.initial_info is not None else "")
569 |
570 |
--------------------------------------------------------------------------------