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