InvokeAI 2.2.4.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- backend/__init__.py +0 -0
- backend/invoke_ai_web_server.py +1724 -0
- backend/modules/__init__.py +0 -0
- backend/modules/create_cmd_parser.py +55 -0
- backend/modules/get_canvas_generation_mode.py +117 -0
- backend/modules/parameters.py +71 -0
- backend/modules/parse_seed_weights.py +47 -0
- configs/INITIAL_MODELS.yaml +80 -0
- configs/models.yaml.example +29 -0
- configs/sd-concepts.txt +803 -0
- configs/stable-diffusion/v1-finetune.yaml +110 -0
- configs/stable-diffusion/v1-finetune_style.yaml +103 -0
- configs/stable-diffusion/v1-inference.yaml +79 -0
- configs/stable-diffusion/v1-inpainting-inference.yaml +79 -0
- configs/stable-diffusion/v1-m1-finetune.yaml +110 -0
- docs/assets/invoke-web-server-1.png +0 -0
- docs/assets/invoke_ai_banner.png +0 -0
- invokeai-2.2.4.5.data/data/assets/caution.png +0 -0
- invokeai-2.2.4.5.data/data/configs/INITIAL_MODELS.yaml +80 -0
- invokeai-2.2.4.5.data/data/configs/models.yaml.example +29 -0
- invokeai-2.2.4.5.data/data/configs/sd-concepts.txt +803 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-finetune.yaml +110 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-finetune_style.yaml +103 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-inference.yaml +79 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-inpainting-inference.yaml +79 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-m1-finetune.yaml +110 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/Inter-Bold.790c108b.ttf +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/Inter.b9a8e5e2.ttf +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/favicon.0d253ced.ico +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/index-legacy-b741077f.js +48 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/index.0dadf5d0.css +1 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/index.21ff81eb.js +625 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/logo.13003d72.png +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/polyfills-legacy-dde3a68a.js +4 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/polyfills.1ff60148.js +1 -0
- invokeai-2.2.4.5.data/data/frontend/dist/index.html +23 -0
- invokeai-2.2.4.5.data/data/scripts/configure_invokeai.py +797 -0
- invokeai-2.2.4.5.data/data/scripts/create_root.py +43 -0
- invokeai-2.2.4.5.data/data/scripts/dream.py +10 -0
- invokeai-2.2.4.5.data/data/scripts/images2prompt.py +30 -0
- invokeai-2.2.4.5.data/data/scripts/invoke.py +5 -0
- invokeai-2.2.4.5.data/data/scripts/legacy_api.py +681 -0
- invokeai-2.2.4.5.data/data/scripts/load_models.py +12 -0
- invokeai-2.2.4.5.data/data/scripts/merge_embeddings.py +124 -0
- invokeai-2.2.4.5.data/data/scripts/preload_models.py +12 -0
- invokeai-2.2.4.5.data/data/scripts/sd-metadata.py +22 -0
- invokeai-2.2.4.5.dist-info/LICENSE +21 -0
- invokeai-2.2.4.5.dist-info/LICENSE-ModelWeights.txt +294 -0
- invokeai-2.2.4.5.dist-info/METADATA +288 -0
- invokeai-2.2.4.5.dist-info/RECORD +169 -0
- invokeai-2.2.4.5.dist-info/WHEEL +5 -0
- invokeai-2.2.4.5.dist-info/entry_points.txt +4 -0
- invokeai-2.2.4.5.dist-info/top_level.txt +6 -0
- invokeai-2.2.4.5.dist-info/zip-safe +1 -0
- ldm/__init__.py +0 -0
- ldm/data/__init__.py +0 -0
- ldm/data/base.py +31 -0
- ldm/data/imagenet.py +466 -0
- ldm/data/lsun.py +126 -0
- ldm/data/personalized.py +202 -0
- ldm/data/personalized_style.py +169 -0
- ldm/generate.py +1159 -0
- ldm/invoke/CLI.py +960 -0
- ldm/invoke/__init__.py +3 -0
- ldm/invoke/args.py +1257 -0
- ldm/invoke/concepts_lib.py +169 -0
- ldm/invoke/conditioning.py +289 -0
- ldm/invoke/devices.py +27 -0
- ldm/invoke/generator/__init__.py +4 -0
- ldm/invoke/generator/base.py +335 -0
- ldm/invoke/generator/embiggen.py +501 -0
- ldm/invoke/generator/img2img.py +97 -0
- ldm/invoke/generator/inpaint.py +358 -0
- ldm/invoke/generator/omnibus.py +175 -0
- ldm/invoke/generator/txt2img.py +88 -0
- ldm/invoke/generator/txt2img2img.py +182 -0
- ldm/invoke/globals.py +31 -0
- ldm/invoke/image_util.py +70 -0
- ldm/invoke/log.py +66 -0
- ldm/invoke/model_cache.py +449 -0
- ldm/invoke/patchmatch.py +44 -0
- ldm/invoke/pngwriter.py +113 -0
- ldm/invoke/prompt_parser.py +655 -0
- ldm/invoke/readline.py +442 -0
- ldm/invoke/restoration/__init__.py +4 -0
- ldm/invoke/restoration/base.py +38 -0
- ldm/invoke/restoration/codeformer.py +103 -0
- ldm/invoke/restoration/codeformer_arch.py +276 -0
- ldm/invoke/restoration/gfpgan.py +84 -0
- ldm/invoke/restoration/outcrop.py +108 -0
- ldm/invoke/restoration/outpaint.py +92 -0
- ldm/invoke/restoration/realesrgan.py +90 -0
- ldm/invoke/restoration/vqgan_arch.py +435 -0
- ldm/invoke/seamless.py +30 -0
- ldm/invoke/server.py +282 -0
- ldm/invoke/server_legacy.py +246 -0
- ldm/invoke/txt2mask.py +136 -0
- ldm/lr_scheduler.py +143 -0
- ldm/models/__init__.py +0 -0
- ldm/models/autoencoder.py +596 -0
- ldm/models/diffusion/__init__.py +0 -0
- ldm/models/diffusion/classifier.py +355 -0
- ldm/models/diffusion/cross_attention_control.py +443 -0
- ldm/models/diffusion/cross_attention_map_saving.py +95 -0
- ldm/models/diffusion/ddim.py +111 -0
- ldm/models/diffusion/ddpm.py +2263 -0
- ldm/models/diffusion/ksampler.py +312 -0
- ldm/models/diffusion/plms.py +146 -0
- ldm/models/diffusion/sampler.py +450 -0
- ldm/models/diffusion/shared_invokeai_diffusion.py +244 -0
- ldm/modules/__init__.py +0 -0
- ldm/modules/attention.py +274 -0
- ldm/modules/diffusionmodules/__init__.py +0 -0
- ldm/modules/diffusionmodules/model.py +894 -0
- ldm/modules/diffusionmodules/openaimodel.py +1036 -0
- ldm/modules/diffusionmodules/util.py +314 -0
- ldm/modules/distributions/__init__.py +0 -0
- ldm/modules/distributions/distributions.py +104 -0
- ldm/modules/ema.py +88 -0
- ldm/modules/embedding_manager.py +413 -0
- ldm/modules/encoders/__init__.py +0 -0
- ldm/modules/encoders/modules.py +772 -0
- ldm/modules/image_degradation/__init__.py +6 -0
- ldm/modules/image_degradation/bsrgan.py +846 -0
- ldm/modules/image_degradation/bsrgan_light.py +751 -0
- ldm/modules/image_degradation/utils_image.py +1024 -0
- ldm/modules/losses/__init__.py +1 -0
- ldm/modules/losses/contperceptual.py +175 -0
- ldm/modules/losses/vqperceptual.py +240 -0
- ldm/modules/x_transformer.py +752 -0
- ldm/simplet2i.py +13 -0
- ldm/util.py +264 -0
- scripts/configure_invokeai.py +797 -0
- scripts/create_root.py +43 -0
- scripts/dream.py +10 -0
- scripts/images2prompt.py +30 -0
- scripts/invoke.py +5 -0
- scripts/legacy_api.py +681 -0
- scripts/load_models.py +12 -0
- scripts/merge_embeddings.py +124 -0
- scripts/orig_scripts/img2img.py +296 -0
- scripts/orig_scripts/inpaint.py +98 -0
- scripts/orig_scripts/knn2img.py +397 -0
- scripts/orig_scripts/sample_diffusion.py +313 -0
- scripts/orig_scripts/train_searcher.py +147 -0
- scripts/orig_scripts/txt2img.py +324 -0
- scripts/preload_models.py +12 -0
- scripts/sd-metadata.py +22 -0
- vendored/clip/clip/__init__.py +1 -0
- vendored/clip/clip/bpe_simple_vocab_16e6.txt.gz +0 -0
- vendored/clip/clip/clip.py +237 -0
- vendored/clip/clip/model.py +436 -0
- vendored/clip/clip/simple_tokenizer.py +132 -0
- vendored/clip/hubconf.py +42 -0
- vendored/clip/setup.py +21 -0
- vendored/clip/tests/test_consistency.py +25 -0
- vendored/clipseg/datasets/coco_wrapper.py +99 -0
- vendored/clipseg/datasets/pascal_zeroshot.py +60 -0
- vendored/clipseg/datasets/pfe_dataset.py +129 -0
- vendored/clipseg/datasets/phrasecut.py +380 -0
- vendored/clipseg/datasets/utils.py +68 -0
- vendored/clipseg/evaluation_utils.py +292 -0
- vendored/clipseg/general_utils.py +272 -0
- vendored/clipseg/metrics.py +271 -0
- vendored/clipseg/models/clipseg.py +538 -0
- vendored/clipseg/models/vitseg.py +286 -0
- vendored/clipseg/score.py +453 -0
- vendored/clipseg/setup.py +30 -0
- vendored/clipseg/training.py +266 -0
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
'''
|
|
2
|
+
ldm.invoke.generator.embiggen descends from ldm.invoke.generator
|
|
3
|
+
and generates with ldm.invoke.generator.img2img
|
|
4
|
+
'''
|
|
5
|
+
|
|
6
|
+
import torch
|
|
7
|
+
import numpy as np
|
|
8
|
+
from tqdm import trange
|
|
9
|
+
from PIL import Image
|
|
10
|
+
from ldm.invoke.generator.base import Generator
|
|
11
|
+
from ldm.invoke.generator.img2img import Img2Img
|
|
12
|
+
from ldm.invoke.devices import choose_autocast
|
|
13
|
+
from ldm.models.diffusion.ddim import DDIMSampler
|
|
14
|
+
|
|
15
|
+
class Embiggen(Generator):
|
|
16
|
+
def __init__(self, model, precision):
|
|
17
|
+
super().__init__(model, precision)
|
|
18
|
+
self.init_latent = None
|
|
19
|
+
|
|
20
|
+
# Replace generate because Embiggen doesn't need/use most of what it does normallly
|
|
21
|
+
def generate(self,prompt,iterations=1,seed=None,
|
|
22
|
+
image_callback=None, step_callback=None,
|
|
23
|
+
**kwargs):
|
|
24
|
+
|
|
25
|
+
scope = choose_autocast(self.precision)
|
|
26
|
+
make_image = self.get_make_image(
|
|
27
|
+
prompt,
|
|
28
|
+
step_callback = step_callback,
|
|
29
|
+
**kwargs
|
|
30
|
+
)
|
|
31
|
+
results = []
|
|
32
|
+
seed = seed if seed else self.new_seed()
|
|
33
|
+
|
|
34
|
+
# Noise will be generated by the Img2Img generator when called
|
|
35
|
+
with scope(self.model.device.type), self.model.ema_scope():
|
|
36
|
+
for n in trange(iterations, desc='Generating'):
|
|
37
|
+
# make_image will call Img2Img which will do the equivalent of get_noise itself
|
|
38
|
+
image = make_image()
|
|
39
|
+
results.append([image, seed])
|
|
40
|
+
if image_callback is not None:
|
|
41
|
+
image_callback(image, seed, prompt_in=prompt)
|
|
42
|
+
seed = self.new_seed()
|
|
43
|
+
return results
|
|
44
|
+
|
|
45
|
+
@torch.no_grad()
|
|
46
|
+
def get_make_image(
|
|
47
|
+
self,
|
|
48
|
+
prompt,
|
|
49
|
+
sampler,
|
|
50
|
+
steps,
|
|
51
|
+
cfg_scale,
|
|
52
|
+
ddim_eta,
|
|
53
|
+
conditioning,
|
|
54
|
+
init_img,
|
|
55
|
+
strength,
|
|
56
|
+
width,
|
|
57
|
+
height,
|
|
58
|
+
embiggen,
|
|
59
|
+
embiggen_tiles,
|
|
60
|
+
step_callback=None,
|
|
61
|
+
**kwargs
|
|
62
|
+
):
|
|
63
|
+
"""
|
|
64
|
+
Returns a function returning an image derived from the prompt and multi-stage twice-baked potato layering over the img2img on the initial image
|
|
65
|
+
Return value depends on the seed at the time you call it
|
|
66
|
+
"""
|
|
67
|
+
assert not sampler.uses_inpainting_model(), "--embiggen is not supported by inpainting models"
|
|
68
|
+
|
|
69
|
+
# Construct embiggen arg array, and sanity check arguments
|
|
70
|
+
if embiggen == None: # embiggen can also be called with just embiggen_tiles
|
|
71
|
+
embiggen = [1.0] # If not specified, assume no scaling
|
|
72
|
+
elif embiggen[0] < 0:
|
|
73
|
+
embiggen[0] = 1.0
|
|
74
|
+
print(
|
|
75
|
+
'>> Embiggen scaling factor cannot be negative, fell back to the default of 1.0 !')
|
|
76
|
+
if len(embiggen) < 2:
|
|
77
|
+
embiggen.append(0.75)
|
|
78
|
+
elif embiggen[1] > 1.0 or embiggen[1] < 0:
|
|
79
|
+
embiggen[1] = 0.75
|
|
80
|
+
print('>> Embiggen upscaling strength for ESRGAN must be between 0 and 1, fell back to the default of 0.75 !')
|
|
81
|
+
if len(embiggen) < 3:
|
|
82
|
+
embiggen.append(0.25)
|
|
83
|
+
elif embiggen[2] < 0:
|
|
84
|
+
embiggen[2] = 0.25
|
|
85
|
+
print('>> Overlap size for Embiggen must be a positive ratio between 0 and 1 OR a number of pixels, fell back to the default of 0.25 !')
|
|
86
|
+
|
|
87
|
+
# Convert tiles from their user-freindly count-from-one to count-from-zero, because we need to do modulo math
|
|
88
|
+
# and then sort them, because... people.
|
|
89
|
+
if embiggen_tiles:
|
|
90
|
+
embiggen_tiles = list(map(lambda n: n-1, embiggen_tiles))
|
|
91
|
+
embiggen_tiles.sort()
|
|
92
|
+
|
|
93
|
+
if strength >= 0.5:
|
|
94
|
+
print(f'* WARNING: Embiggen may produce mirror motifs if the strength (-f) is too high (currently {strength}). Try values between 0.35-0.45.')
|
|
95
|
+
|
|
96
|
+
# Prep img2img generator, since we wrap over it
|
|
97
|
+
gen_img2img = Img2Img(self.model,self.precision)
|
|
98
|
+
|
|
99
|
+
# Open original init image (not a tensor) to manipulate
|
|
100
|
+
initsuperimage = Image.open(init_img)
|
|
101
|
+
|
|
102
|
+
with Image.open(init_img) as img:
|
|
103
|
+
initsuperimage = img.convert('RGB')
|
|
104
|
+
|
|
105
|
+
# Size of the target super init image in pixels
|
|
106
|
+
initsuperwidth, initsuperheight = initsuperimage.size
|
|
107
|
+
|
|
108
|
+
# Increase by scaling factor if not already resized, using ESRGAN as able
|
|
109
|
+
if embiggen[0] != 1.0:
|
|
110
|
+
initsuperwidth = round(initsuperwidth*embiggen[0])
|
|
111
|
+
initsuperheight = round(initsuperheight*embiggen[0])
|
|
112
|
+
if embiggen[1] > 0: # No point in ESRGAN upscaling if strength is set zero
|
|
113
|
+
from ldm.invoke.restoration.realesrgan import ESRGAN
|
|
114
|
+
esrgan = ESRGAN()
|
|
115
|
+
print(
|
|
116
|
+
f'>> ESRGAN upscaling init image prior to cutting with Embiggen with strength {embiggen[1]}')
|
|
117
|
+
if embiggen[0] > 2:
|
|
118
|
+
initsuperimage = esrgan.process(
|
|
119
|
+
initsuperimage,
|
|
120
|
+
embiggen[1], # upscale strength
|
|
121
|
+
self.seed,
|
|
122
|
+
4, # upscale scale
|
|
123
|
+
)
|
|
124
|
+
else:
|
|
125
|
+
initsuperimage = esrgan.process(
|
|
126
|
+
initsuperimage,
|
|
127
|
+
embiggen[1], # upscale strength
|
|
128
|
+
self.seed,
|
|
129
|
+
2, # upscale scale
|
|
130
|
+
)
|
|
131
|
+
# We could keep recursively re-running ESRGAN for a requested embiggen[0] larger than 4x
|
|
132
|
+
# but from personal experiance it doesn't greatly improve anything after 4x
|
|
133
|
+
# Resize to target scaling factor resolution
|
|
134
|
+
initsuperimage = initsuperimage.resize(
|
|
135
|
+
(initsuperwidth, initsuperheight), Image.Resampling.LANCZOS)
|
|
136
|
+
|
|
137
|
+
# Use width and height as tile widths and height
|
|
138
|
+
# Determine buffer size in pixels
|
|
139
|
+
if embiggen[2] < 1:
|
|
140
|
+
if embiggen[2] < 0:
|
|
141
|
+
embiggen[2] = 0
|
|
142
|
+
overlap_size_x = round(embiggen[2] * width)
|
|
143
|
+
overlap_size_y = round(embiggen[2] * height)
|
|
144
|
+
else:
|
|
145
|
+
overlap_size_x = round(embiggen[2])
|
|
146
|
+
overlap_size_y = round(embiggen[2])
|
|
147
|
+
|
|
148
|
+
# With overall image width and height known, determine how many tiles we need
|
|
149
|
+
def ceildiv(a, b):
|
|
150
|
+
return -1 * (-a // b)
|
|
151
|
+
|
|
152
|
+
# X and Y needs to be determined independantly (we may have savings on one based on the buffer pixel count)
|
|
153
|
+
# (initsuperwidth - width) is the area remaining to the right that we need to layers tiles to fill
|
|
154
|
+
# (width - overlap_size_x) is how much new we can fill with a single tile
|
|
155
|
+
emb_tiles_x = 1
|
|
156
|
+
emb_tiles_y = 1
|
|
157
|
+
if (initsuperwidth - width) > 0:
|
|
158
|
+
emb_tiles_x = ceildiv(initsuperwidth - width,
|
|
159
|
+
width - overlap_size_x) + 1
|
|
160
|
+
if (initsuperheight - height) > 0:
|
|
161
|
+
emb_tiles_y = ceildiv(initsuperheight - height,
|
|
162
|
+
height - overlap_size_y) + 1
|
|
163
|
+
# Sanity
|
|
164
|
+
assert emb_tiles_x > 1 or emb_tiles_y > 1, f'ERROR: Based on the requested dimensions of {initsuperwidth}x{initsuperheight} and tiles of {width}x{height} you don\'t need to Embiggen! Check your arguments.'
|
|
165
|
+
|
|
166
|
+
# Prep alpha layers --------------
|
|
167
|
+
# https://stackoverflow.com/questions/69321734/how-to-create-different-transparency-like-gradient-with-python-pil
|
|
168
|
+
# agradientL is Left-side transparent
|
|
169
|
+
agradientL = Image.linear_gradient('L').rotate(
|
|
170
|
+
90).resize((overlap_size_x, height))
|
|
171
|
+
# agradientT is Top-side transparent
|
|
172
|
+
agradientT = Image.linear_gradient('L').resize((width, overlap_size_y))
|
|
173
|
+
# radial corner is the left-top corner, made full circle then cut to just the left-top quadrant
|
|
174
|
+
agradientC = Image.new('L', (256, 256))
|
|
175
|
+
for y in range(256):
|
|
176
|
+
for x in range(256):
|
|
177
|
+
# Find distance to lower right corner (numpy takes arrays)
|
|
178
|
+
distanceToLR = np.sqrt([(255 - x) ** 2 + (255 - y) ** 2])[0]
|
|
179
|
+
# Clamp values to max 255
|
|
180
|
+
if distanceToLR > 255:
|
|
181
|
+
distanceToLR = 255
|
|
182
|
+
#Place the pixel as invert of distance
|
|
183
|
+
agradientC.putpixel((x, y), round(255 - distanceToLR))
|
|
184
|
+
|
|
185
|
+
# Create alternative asymmetric diagonal corner to use on "tailing" intersections to prevent hard edges
|
|
186
|
+
# Fits for a left-fading gradient on the bottom side and full opacity on the right side.
|
|
187
|
+
agradientAsymC = Image.new('L', (256, 256))
|
|
188
|
+
for y in range(256):
|
|
189
|
+
for x in range(256):
|
|
190
|
+
value = round(max(0, x-(255-y)) * (255 / max(1,y)))
|
|
191
|
+
#Clamp values
|
|
192
|
+
value = max(0, value)
|
|
193
|
+
value = min(255, value)
|
|
194
|
+
agradientAsymC.putpixel((x, y), value)
|
|
195
|
+
|
|
196
|
+
# Create alpha layers default fully white
|
|
197
|
+
alphaLayerL = Image.new("L", (width, height), 255)
|
|
198
|
+
alphaLayerT = Image.new("L", (width, height), 255)
|
|
199
|
+
alphaLayerLTC = Image.new("L", (width, height), 255)
|
|
200
|
+
# Paste gradients into alpha layers
|
|
201
|
+
alphaLayerL.paste(agradientL, (0, 0))
|
|
202
|
+
alphaLayerT.paste(agradientT, (0, 0))
|
|
203
|
+
alphaLayerLTC.paste(agradientL, (0, 0))
|
|
204
|
+
alphaLayerLTC.paste(agradientT, (0, 0))
|
|
205
|
+
alphaLayerLTC.paste(agradientC.resize((overlap_size_x, overlap_size_y)), (0, 0))
|
|
206
|
+
# make masks with an asymmetric upper-right corner so when the curved transparent corner of the next tile
|
|
207
|
+
# to its right is placed it doesn't reveal a hard trailing semi-transparent edge in the overlapping space
|
|
208
|
+
alphaLayerTaC = alphaLayerT.copy()
|
|
209
|
+
alphaLayerTaC.paste(agradientAsymC.rotate(270).resize((overlap_size_x, overlap_size_y)), (width - overlap_size_x, 0))
|
|
210
|
+
alphaLayerLTaC = alphaLayerLTC.copy()
|
|
211
|
+
alphaLayerLTaC.paste(agradientAsymC.rotate(270).resize((overlap_size_x, overlap_size_y)), (width - overlap_size_x, 0))
|
|
212
|
+
|
|
213
|
+
if embiggen_tiles:
|
|
214
|
+
# Individual unconnected sides
|
|
215
|
+
alphaLayerR = Image.new("L", (width, height), 255)
|
|
216
|
+
alphaLayerR.paste(agradientL.rotate(
|
|
217
|
+
180), (width - overlap_size_x, 0))
|
|
218
|
+
alphaLayerB = Image.new("L", (width, height), 255)
|
|
219
|
+
alphaLayerB.paste(agradientT.rotate(
|
|
220
|
+
180), (0, height - overlap_size_y))
|
|
221
|
+
alphaLayerTB = Image.new("L", (width, height), 255)
|
|
222
|
+
alphaLayerTB.paste(agradientT, (0, 0))
|
|
223
|
+
alphaLayerTB.paste(agradientT.rotate(
|
|
224
|
+
180), (0, height - overlap_size_y))
|
|
225
|
+
alphaLayerLR = Image.new("L", (width, height), 255)
|
|
226
|
+
alphaLayerLR.paste(agradientL, (0, 0))
|
|
227
|
+
alphaLayerLR.paste(agradientL.rotate(
|
|
228
|
+
180), (width - overlap_size_x, 0))
|
|
229
|
+
|
|
230
|
+
# Sides and corner Layers
|
|
231
|
+
alphaLayerRBC = Image.new("L", (width, height), 255)
|
|
232
|
+
alphaLayerRBC.paste(agradientL.rotate(
|
|
233
|
+
180), (width - overlap_size_x, 0))
|
|
234
|
+
alphaLayerRBC.paste(agradientT.rotate(
|
|
235
|
+
180), (0, height - overlap_size_y))
|
|
236
|
+
alphaLayerRBC.paste(agradientC.rotate(180).resize(
|
|
237
|
+
(overlap_size_x, overlap_size_y)), (width - overlap_size_x, height - overlap_size_y))
|
|
238
|
+
alphaLayerLBC = Image.new("L", (width, height), 255)
|
|
239
|
+
alphaLayerLBC.paste(agradientL, (0, 0))
|
|
240
|
+
alphaLayerLBC.paste(agradientT.rotate(
|
|
241
|
+
180), (0, height - overlap_size_y))
|
|
242
|
+
alphaLayerLBC.paste(agradientC.rotate(90).resize(
|
|
243
|
+
(overlap_size_x, overlap_size_y)), (0, height - overlap_size_y))
|
|
244
|
+
alphaLayerRTC = Image.new("L", (width, height), 255)
|
|
245
|
+
alphaLayerRTC.paste(agradientL.rotate(
|
|
246
|
+
180), (width - overlap_size_x, 0))
|
|
247
|
+
alphaLayerRTC.paste(agradientT, (0, 0))
|
|
248
|
+
alphaLayerRTC.paste(agradientC.rotate(270).resize(
|
|
249
|
+
(overlap_size_x, overlap_size_y)), (width - overlap_size_x, 0))
|
|
250
|
+
|
|
251
|
+
# All but X layers
|
|
252
|
+
alphaLayerABT = Image.new("L", (width, height), 255)
|
|
253
|
+
alphaLayerABT.paste(alphaLayerLBC, (0, 0))
|
|
254
|
+
alphaLayerABT.paste(agradientL.rotate(
|
|
255
|
+
180), (width - overlap_size_x, 0))
|
|
256
|
+
alphaLayerABT.paste(agradientC.rotate(180).resize(
|
|
257
|
+
(overlap_size_x, overlap_size_y)), (width - overlap_size_x, height - overlap_size_y))
|
|
258
|
+
alphaLayerABL = Image.new("L", (width, height), 255)
|
|
259
|
+
alphaLayerABL.paste(alphaLayerRTC, (0, 0))
|
|
260
|
+
alphaLayerABL.paste(agradientT.rotate(
|
|
261
|
+
180), (0, height - overlap_size_y))
|
|
262
|
+
alphaLayerABL.paste(agradientC.rotate(180).resize(
|
|
263
|
+
(overlap_size_x, overlap_size_y)), (width - overlap_size_x, height - overlap_size_y))
|
|
264
|
+
alphaLayerABR = Image.new("L", (width, height), 255)
|
|
265
|
+
alphaLayerABR.paste(alphaLayerLBC, (0, 0))
|
|
266
|
+
alphaLayerABR.paste(agradientT, (0, 0))
|
|
267
|
+
alphaLayerABR.paste(agradientC.resize(
|
|
268
|
+
(overlap_size_x, overlap_size_y)), (0, 0))
|
|
269
|
+
alphaLayerABB = Image.new("L", (width, height), 255)
|
|
270
|
+
alphaLayerABB.paste(alphaLayerRTC, (0, 0))
|
|
271
|
+
alphaLayerABB.paste(agradientL, (0, 0))
|
|
272
|
+
alphaLayerABB.paste(agradientC.resize(
|
|
273
|
+
(overlap_size_x, overlap_size_y)), (0, 0))
|
|
274
|
+
|
|
275
|
+
# All-around layer
|
|
276
|
+
alphaLayerAA = Image.new("L", (width, height), 255)
|
|
277
|
+
alphaLayerAA.paste(alphaLayerABT, (0, 0))
|
|
278
|
+
alphaLayerAA.paste(agradientT, (0, 0))
|
|
279
|
+
alphaLayerAA.paste(agradientC.resize(
|
|
280
|
+
(overlap_size_x, overlap_size_y)), (0, 0))
|
|
281
|
+
alphaLayerAA.paste(agradientC.rotate(270).resize(
|
|
282
|
+
(overlap_size_x, overlap_size_y)), (width - overlap_size_x, 0))
|
|
283
|
+
|
|
284
|
+
# Clean up temporary gradients
|
|
285
|
+
del agradientL
|
|
286
|
+
del agradientT
|
|
287
|
+
del agradientC
|
|
288
|
+
|
|
289
|
+
def make_image():
|
|
290
|
+
# Make main tiles -------------------------------------------------
|
|
291
|
+
if embiggen_tiles:
|
|
292
|
+
print(f'>> Making {len(embiggen_tiles)} Embiggen tiles...')
|
|
293
|
+
else:
|
|
294
|
+
print(
|
|
295
|
+
f'>> Making {(emb_tiles_x * emb_tiles_y)} Embiggen tiles ({emb_tiles_x}x{emb_tiles_y})...')
|
|
296
|
+
|
|
297
|
+
emb_tile_store = []
|
|
298
|
+
# Although we could use the same seed for every tile for determinism, at higher strengths this may
|
|
299
|
+
# produce duplicated structures for each tile and make the tiling effect more obvious
|
|
300
|
+
# instead track and iterate a local seed we pass to Img2Img
|
|
301
|
+
seed = self.seed
|
|
302
|
+
seedintlimit = np.iinfo(np.uint32).max - 1 # only retreive this one from numpy
|
|
303
|
+
|
|
304
|
+
for tile in range(emb_tiles_x * emb_tiles_y):
|
|
305
|
+
# Don't iterate on first tile
|
|
306
|
+
if tile != 0:
|
|
307
|
+
if seed < seedintlimit:
|
|
308
|
+
seed += 1
|
|
309
|
+
else:
|
|
310
|
+
seed = 0
|
|
311
|
+
|
|
312
|
+
# Determine if this is a re-run and replace
|
|
313
|
+
if embiggen_tiles and not tile in embiggen_tiles:
|
|
314
|
+
continue
|
|
315
|
+
# Get row and column entries
|
|
316
|
+
emb_row_i = tile // emb_tiles_x
|
|
317
|
+
emb_column_i = tile % emb_tiles_x
|
|
318
|
+
# Determine bounds to cut up the init image
|
|
319
|
+
# Determine upper-left point
|
|
320
|
+
if emb_column_i + 1 == emb_tiles_x:
|
|
321
|
+
left = initsuperwidth - width
|
|
322
|
+
else:
|
|
323
|
+
left = round(emb_column_i * (width - overlap_size_x))
|
|
324
|
+
if emb_row_i + 1 == emb_tiles_y:
|
|
325
|
+
top = initsuperheight - height
|
|
326
|
+
else:
|
|
327
|
+
top = round(emb_row_i * (height - overlap_size_y))
|
|
328
|
+
right = left + width
|
|
329
|
+
bottom = top + height
|
|
330
|
+
|
|
331
|
+
# Cropped image of above dimension (does not modify the original)
|
|
332
|
+
newinitimage = initsuperimage.crop((left, top, right, bottom))
|
|
333
|
+
# DEBUG:
|
|
334
|
+
# newinitimagepath = init_img[0:-4] + f'_emb_Ti{tile}.png'
|
|
335
|
+
# newinitimage.save(newinitimagepath)
|
|
336
|
+
|
|
337
|
+
if embiggen_tiles:
|
|
338
|
+
print(
|
|
339
|
+
f'Making tile #{tile + 1} ({embiggen_tiles.index(tile) + 1} of {len(embiggen_tiles)} requested)')
|
|
340
|
+
else:
|
|
341
|
+
print(
|
|
342
|
+
f'Starting {tile + 1} of {(emb_tiles_x * emb_tiles_y)} tiles')
|
|
343
|
+
|
|
344
|
+
# create a torch tensor from an Image
|
|
345
|
+
newinitimage = np.array(
|
|
346
|
+
newinitimage).astype(np.float32) / 255.0
|
|
347
|
+
newinitimage = newinitimage[None].transpose(0, 3, 1, 2)
|
|
348
|
+
newinitimage = torch.from_numpy(newinitimage)
|
|
349
|
+
newinitimage = 2.0 * newinitimage - 1.0
|
|
350
|
+
newinitimage = newinitimage.to(self.model.device)
|
|
351
|
+
|
|
352
|
+
tile_results = gen_img2img.generate(
|
|
353
|
+
prompt,
|
|
354
|
+
iterations = 1,
|
|
355
|
+
seed = seed,
|
|
356
|
+
sampler = DDIMSampler(self.model, device=self.model.device),
|
|
357
|
+
steps = steps,
|
|
358
|
+
cfg_scale = cfg_scale,
|
|
359
|
+
conditioning = conditioning,
|
|
360
|
+
ddim_eta = ddim_eta,
|
|
361
|
+
image_callback = None, # called only after the final image is generated
|
|
362
|
+
step_callback = step_callback, # called after each intermediate image is generated
|
|
363
|
+
width = width,
|
|
364
|
+
height = height,
|
|
365
|
+
init_image = newinitimage, # notice that init_image is different from init_img
|
|
366
|
+
mask_image = None,
|
|
367
|
+
strength = strength,
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
emb_tile_store.append(tile_results[0][0])
|
|
371
|
+
# DEBUG (but, also has other uses), worth saving if you want tiles without a transparency overlap to manually composite
|
|
372
|
+
# emb_tile_store[-1].save(init_img[0:-4] + f'_emb_To{tile}.png')
|
|
373
|
+
del newinitimage
|
|
374
|
+
|
|
375
|
+
# Sanity check we have them all
|
|
376
|
+
if len(emb_tile_store) == (emb_tiles_x * emb_tiles_y) or (embiggen_tiles != [] and len(emb_tile_store) == len(embiggen_tiles)):
|
|
377
|
+
outputsuperimage = Image.new(
|
|
378
|
+
"RGBA", (initsuperwidth, initsuperheight))
|
|
379
|
+
if embiggen_tiles:
|
|
380
|
+
outputsuperimage.alpha_composite(
|
|
381
|
+
initsuperimage.convert('RGBA'), (0, 0))
|
|
382
|
+
for tile in range(emb_tiles_x * emb_tiles_y):
|
|
383
|
+
if embiggen_tiles:
|
|
384
|
+
if tile in embiggen_tiles:
|
|
385
|
+
intileimage = emb_tile_store.pop(0)
|
|
386
|
+
else:
|
|
387
|
+
continue
|
|
388
|
+
else:
|
|
389
|
+
intileimage = emb_tile_store[tile]
|
|
390
|
+
intileimage = intileimage.convert('RGBA')
|
|
391
|
+
# Get row and column entries
|
|
392
|
+
emb_row_i = tile // emb_tiles_x
|
|
393
|
+
emb_column_i = tile % emb_tiles_x
|
|
394
|
+
if emb_row_i == 0 and emb_column_i == 0 and not embiggen_tiles:
|
|
395
|
+
left = 0
|
|
396
|
+
top = 0
|
|
397
|
+
else:
|
|
398
|
+
# Determine upper-left point
|
|
399
|
+
if emb_column_i + 1 == emb_tiles_x:
|
|
400
|
+
left = initsuperwidth - width
|
|
401
|
+
else:
|
|
402
|
+
left = round(emb_column_i *
|
|
403
|
+
(width - overlap_size_x))
|
|
404
|
+
if emb_row_i + 1 == emb_tiles_y:
|
|
405
|
+
top = initsuperheight - height
|
|
406
|
+
else:
|
|
407
|
+
top = round(emb_row_i * (height - overlap_size_y))
|
|
408
|
+
# Handle gradients for various conditions
|
|
409
|
+
# Handle emb_rerun case
|
|
410
|
+
if embiggen_tiles:
|
|
411
|
+
# top of image
|
|
412
|
+
if emb_row_i == 0:
|
|
413
|
+
if emb_column_i == 0:
|
|
414
|
+
if (tile+1) in embiggen_tiles: # Look-ahead right
|
|
415
|
+
if (tile+emb_tiles_x) not in embiggen_tiles: # Look-ahead down
|
|
416
|
+
intileimage.putalpha(alphaLayerB)
|
|
417
|
+
# Otherwise do nothing on this tile
|
|
418
|
+
elif (tile+emb_tiles_x) in embiggen_tiles: # Look-ahead down only
|
|
419
|
+
intileimage.putalpha(alphaLayerR)
|
|
420
|
+
else:
|
|
421
|
+
intileimage.putalpha(alphaLayerRBC)
|
|
422
|
+
elif emb_column_i == emb_tiles_x - 1:
|
|
423
|
+
if (tile+emb_tiles_x) in embiggen_tiles: # Look-ahead down
|
|
424
|
+
intileimage.putalpha(alphaLayerL)
|
|
425
|
+
else:
|
|
426
|
+
intileimage.putalpha(alphaLayerLBC)
|
|
427
|
+
else:
|
|
428
|
+
if (tile+1) in embiggen_tiles: # Look-ahead right
|
|
429
|
+
if (tile+emb_tiles_x) in embiggen_tiles: # Look-ahead down
|
|
430
|
+
intileimage.putalpha(alphaLayerL)
|
|
431
|
+
else:
|
|
432
|
+
intileimage.putalpha(alphaLayerLBC)
|
|
433
|
+
elif (tile+emb_tiles_x) in embiggen_tiles: # Look-ahead down only
|
|
434
|
+
intileimage.putalpha(alphaLayerLR)
|
|
435
|
+
else:
|
|
436
|
+
intileimage.putalpha(alphaLayerABT)
|
|
437
|
+
# bottom of image
|
|
438
|
+
elif emb_row_i == emb_tiles_y - 1:
|
|
439
|
+
if emb_column_i == 0:
|
|
440
|
+
if (tile+1) in embiggen_tiles: # Look-ahead right
|
|
441
|
+
intileimage.putalpha(alphaLayerTaC)
|
|
442
|
+
else:
|
|
443
|
+
intileimage.putalpha(alphaLayerRTC)
|
|
444
|
+
elif emb_column_i == emb_tiles_x - 1:
|
|
445
|
+
# No tiles to look ahead to
|
|
446
|
+
intileimage.putalpha(alphaLayerLTC)
|
|
447
|
+
else:
|
|
448
|
+
if (tile+1) in embiggen_tiles: # Look-ahead right
|
|
449
|
+
intileimage.putalpha(alphaLayerLTaC)
|
|
450
|
+
else:
|
|
451
|
+
intileimage.putalpha(alphaLayerABB)
|
|
452
|
+
# vertical middle of image
|
|
453
|
+
else:
|
|
454
|
+
if emb_column_i == 0:
|
|
455
|
+
if (tile+1) in embiggen_tiles: # Look-ahead right
|
|
456
|
+
if (tile+emb_tiles_x) in embiggen_tiles: # Look-ahead down
|
|
457
|
+
intileimage.putalpha(alphaLayerTaC)
|
|
458
|
+
else:
|
|
459
|
+
intileimage.putalpha(alphaLayerTB)
|
|
460
|
+
elif (tile+emb_tiles_x) in embiggen_tiles: # Look-ahead down only
|
|
461
|
+
intileimage.putalpha(alphaLayerRTC)
|
|
462
|
+
else:
|
|
463
|
+
intileimage.putalpha(alphaLayerABL)
|
|
464
|
+
elif emb_column_i == emb_tiles_x - 1:
|
|
465
|
+
if (tile+emb_tiles_x) in embiggen_tiles: # Look-ahead down
|
|
466
|
+
intileimage.putalpha(alphaLayerLTC)
|
|
467
|
+
else:
|
|
468
|
+
intileimage.putalpha(alphaLayerABR)
|
|
469
|
+
else:
|
|
470
|
+
if (tile+1) in embiggen_tiles: # Look-ahead right
|
|
471
|
+
if (tile+emb_tiles_x) in embiggen_tiles: # Look-ahead down
|
|
472
|
+
intileimage.putalpha(alphaLayerLTaC)
|
|
473
|
+
else:
|
|
474
|
+
intileimage.putalpha(alphaLayerABR)
|
|
475
|
+
elif (tile+emb_tiles_x) in embiggen_tiles: # Look-ahead down only
|
|
476
|
+
intileimage.putalpha(alphaLayerABB)
|
|
477
|
+
else:
|
|
478
|
+
intileimage.putalpha(alphaLayerAA)
|
|
479
|
+
# Handle normal tiling case (much simpler - since we tile left to right, top to bottom)
|
|
480
|
+
else:
|
|
481
|
+
if emb_row_i == 0 and emb_column_i >= 1:
|
|
482
|
+
intileimage.putalpha(alphaLayerL)
|
|
483
|
+
elif emb_row_i >= 1 and emb_column_i == 0:
|
|
484
|
+
if emb_column_i + 1 == emb_tiles_x: # If we don't have anything that can be placed to the right
|
|
485
|
+
intileimage.putalpha(alphaLayerT)
|
|
486
|
+
else:
|
|
487
|
+
intileimage.putalpha(alphaLayerTaC)
|
|
488
|
+
else:
|
|
489
|
+
if emb_column_i + 1 == emb_tiles_x: # If we don't have anything that can be placed to the right
|
|
490
|
+
intileimage.putalpha(alphaLayerLTC)
|
|
491
|
+
else:
|
|
492
|
+
intileimage.putalpha(alphaLayerLTaC)
|
|
493
|
+
# Layer tile onto final image
|
|
494
|
+
outputsuperimage.alpha_composite(intileimage, (left, top))
|
|
495
|
+
else:
|
|
496
|
+
print(f'Error: could not find all Embiggen output tiles in memory? Something must have gone wrong with img2img generation.')
|
|
497
|
+
|
|
498
|
+
# after internal loops and patching up return Embiggen image
|
|
499
|
+
return outputsuperimage
|
|
500
|
+
# end of function declaration
|
|
501
|
+
return make_image
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'''
|
|
2
|
+
ldm.invoke.generator.img2img descends from ldm.invoke.generator
|
|
3
|
+
'''
|
|
4
|
+
|
|
5
|
+
import torch
|
|
6
|
+
import numpy as np
|
|
7
|
+
import PIL
|
|
8
|
+
from torch import Tensor
|
|
9
|
+
from PIL import Image
|
|
10
|
+
from ldm.invoke.devices import choose_autocast
|
|
11
|
+
from ldm.invoke.generator.base import Generator
|
|
12
|
+
from ldm.models.diffusion.ddim import DDIMSampler
|
|
13
|
+
from ldm.models.diffusion.shared_invokeai_diffusion import InvokeAIDiffuserComponent
|
|
14
|
+
|
|
15
|
+
class Img2Img(Generator):
|
|
16
|
+
def __init__(self, model, precision):
|
|
17
|
+
super().__init__(model, precision)
|
|
18
|
+
self.init_latent = None # by get_noise()
|
|
19
|
+
|
|
20
|
+
def get_make_image(self,prompt,sampler,steps,cfg_scale,ddim_eta,
|
|
21
|
+
conditioning,init_image,strength,step_callback=None,threshold=0.0,perlin=0.0,**kwargs):
|
|
22
|
+
"""
|
|
23
|
+
Returns a function returning an image derived from the prompt and the initial image
|
|
24
|
+
Return value depends on the seed at the time you call it.
|
|
25
|
+
"""
|
|
26
|
+
self.perlin = perlin
|
|
27
|
+
|
|
28
|
+
sampler.make_schedule(
|
|
29
|
+
ddim_num_steps=steps, ddim_eta=ddim_eta, verbose=False
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if isinstance(init_image, PIL.Image.Image):
|
|
33
|
+
init_image = self._image_to_tensor(init_image.convert('RGB'))
|
|
34
|
+
|
|
35
|
+
scope = choose_autocast(self.precision)
|
|
36
|
+
with scope(self.model.device.type):
|
|
37
|
+
self.init_latent = self.model.get_first_stage_encoding(
|
|
38
|
+
self.model.encode_first_stage(init_image)
|
|
39
|
+
) # move to latent space
|
|
40
|
+
|
|
41
|
+
t_enc = int(strength * steps)
|
|
42
|
+
uc, c, extra_conditioning_info = conditioning
|
|
43
|
+
|
|
44
|
+
def make_image(x_T):
|
|
45
|
+
# encode (scaled latent)
|
|
46
|
+
z_enc = sampler.stochastic_encode(
|
|
47
|
+
self.init_latent,
|
|
48
|
+
torch.tensor([t_enc - 1]).to(self.model.device),
|
|
49
|
+
noise=x_T
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if self.free_gpu_mem and self.model.model.device != self.model.device:
|
|
53
|
+
self.model.model.to(self.model.device)
|
|
54
|
+
|
|
55
|
+
# decode it
|
|
56
|
+
samples = sampler.decode(
|
|
57
|
+
z_enc,
|
|
58
|
+
c,
|
|
59
|
+
t_enc,
|
|
60
|
+
img_callback = step_callback,
|
|
61
|
+
unconditional_guidance_scale=cfg_scale,
|
|
62
|
+
unconditional_conditioning=uc,
|
|
63
|
+
init_latent = self.init_latent, # changes how noising is performed in ksampler
|
|
64
|
+
extra_conditioning_info = extra_conditioning_info,
|
|
65
|
+
all_timesteps_count = steps
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if self.free_gpu_mem:
|
|
69
|
+
self.model.model.to("cpu")
|
|
70
|
+
|
|
71
|
+
return self.sample_to_image(samples)
|
|
72
|
+
|
|
73
|
+
return make_image
|
|
74
|
+
|
|
75
|
+
def get_noise(self,width,height):
|
|
76
|
+
device = self.model.device
|
|
77
|
+
init_latent = self.init_latent
|
|
78
|
+
assert init_latent is not None,'call to get_noise() when init_latent not set'
|
|
79
|
+
if device.type == 'mps':
|
|
80
|
+
x = torch.randn_like(init_latent, device='cpu').to(device)
|
|
81
|
+
else:
|
|
82
|
+
x = torch.randn_like(init_latent, device=device)
|
|
83
|
+
if self.perlin > 0.0:
|
|
84
|
+
shape = init_latent.shape
|
|
85
|
+
x = (1-self.perlin)*x + self.perlin*self.get_perlin_noise(shape[3], shape[2])
|
|
86
|
+
return x
|
|
87
|
+
|
|
88
|
+
def _image_to_tensor(self, image:Image, normalize:bool=True)->Tensor:
|
|
89
|
+
image = np.array(image).astype(np.float32) / 255.0
|
|
90
|
+
if len(image.shape) == 2: # 'L' image, as in a mask
|
|
91
|
+
image = image[None,None]
|
|
92
|
+
else: # 'RGB' image
|
|
93
|
+
image = image[None].transpose(0, 3, 1, 2)
|
|
94
|
+
image = torch.from_numpy(image)
|
|
95
|
+
if normalize:
|
|
96
|
+
image = 2.0 * image - 1.0
|
|
97
|
+
return image.to(self.model.device)
|