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.
Files changed (169) hide show
  1. backend/__init__.py +0 -0
  2. backend/invoke_ai_web_server.py +1724 -0
  3. backend/modules/__init__.py +0 -0
  4. backend/modules/create_cmd_parser.py +55 -0
  5. backend/modules/get_canvas_generation_mode.py +117 -0
  6. backend/modules/parameters.py +71 -0
  7. backend/modules/parse_seed_weights.py +47 -0
  8. configs/INITIAL_MODELS.yaml +80 -0
  9. configs/models.yaml.example +29 -0
  10. configs/sd-concepts.txt +803 -0
  11. configs/stable-diffusion/v1-finetune.yaml +110 -0
  12. configs/stable-diffusion/v1-finetune_style.yaml +103 -0
  13. configs/stable-diffusion/v1-inference.yaml +79 -0
  14. configs/stable-diffusion/v1-inpainting-inference.yaml +79 -0
  15. configs/stable-diffusion/v1-m1-finetune.yaml +110 -0
  16. docs/assets/invoke-web-server-1.png +0 -0
  17. docs/assets/invoke_ai_banner.png +0 -0
  18. invokeai-2.2.4.5.data/data/assets/caution.png +0 -0
  19. invokeai-2.2.4.5.data/data/configs/INITIAL_MODELS.yaml +80 -0
  20. invokeai-2.2.4.5.data/data/configs/models.yaml.example +29 -0
  21. invokeai-2.2.4.5.data/data/configs/sd-concepts.txt +803 -0
  22. invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-finetune.yaml +110 -0
  23. invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-finetune_style.yaml +103 -0
  24. invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-inference.yaml +79 -0
  25. invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-inpainting-inference.yaml +79 -0
  26. invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-m1-finetune.yaml +110 -0
  27. invokeai-2.2.4.5.data/data/frontend/dist/assets/Inter-Bold.790c108b.ttf +0 -0
  28. invokeai-2.2.4.5.data/data/frontend/dist/assets/Inter.b9a8e5e2.ttf +0 -0
  29. invokeai-2.2.4.5.data/data/frontend/dist/assets/favicon.0d253ced.ico +0 -0
  30. invokeai-2.2.4.5.data/data/frontend/dist/assets/index-legacy-b741077f.js +48 -0
  31. invokeai-2.2.4.5.data/data/frontend/dist/assets/index.0dadf5d0.css +1 -0
  32. invokeai-2.2.4.5.data/data/frontend/dist/assets/index.21ff81eb.js +625 -0
  33. invokeai-2.2.4.5.data/data/frontend/dist/assets/logo.13003d72.png +0 -0
  34. invokeai-2.2.4.5.data/data/frontend/dist/assets/polyfills-legacy-dde3a68a.js +4 -0
  35. invokeai-2.2.4.5.data/data/frontend/dist/assets/polyfills.1ff60148.js +1 -0
  36. invokeai-2.2.4.5.data/data/frontend/dist/index.html +23 -0
  37. invokeai-2.2.4.5.data/data/scripts/configure_invokeai.py +797 -0
  38. invokeai-2.2.4.5.data/data/scripts/create_root.py +43 -0
  39. invokeai-2.2.4.5.data/data/scripts/dream.py +10 -0
  40. invokeai-2.2.4.5.data/data/scripts/images2prompt.py +30 -0
  41. invokeai-2.2.4.5.data/data/scripts/invoke.py +5 -0
  42. invokeai-2.2.4.5.data/data/scripts/legacy_api.py +681 -0
  43. invokeai-2.2.4.5.data/data/scripts/load_models.py +12 -0
  44. invokeai-2.2.4.5.data/data/scripts/merge_embeddings.py +124 -0
  45. invokeai-2.2.4.5.data/data/scripts/preload_models.py +12 -0
  46. invokeai-2.2.4.5.data/data/scripts/sd-metadata.py +22 -0
  47. invokeai-2.2.4.5.dist-info/LICENSE +21 -0
  48. invokeai-2.2.4.5.dist-info/LICENSE-ModelWeights.txt +294 -0
  49. invokeai-2.2.4.5.dist-info/METADATA +288 -0
  50. invokeai-2.2.4.5.dist-info/RECORD +169 -0
  51. invokeai-2.2.4.5.dist-info/WHEEL +5 -0
  52. invokeai-2.2.4.5.dist-info/entry_points.txt +4 -0
  53. invokeai-2.2.4.5.dist-info/top_level.txt +6 -0
  54. invokeai-2.2.4.5.dist-info/zip-safe +1 -0
  55. ldm/__init__.py +0 -0
  56. ldm/data/__init__.py +0 -0
  57. ldm/data/base.py +31 -0
  58. ldm/data/imagenet.py +466 -0
  59. ldm/data/lsun.py +126 -0
  60. ldm/data/personalized.py +202 -0
  61. ldm/data/personalized_style.py +169 -0
  62. ldm/generate.py +1159 -0
  63. ldm/invoke/CLI.py +960 -0
  64. ldm/invoke/__init__.py +3 -0
  65. ldm/invoke/args.py +1257 -0
  66. ldm/invoke/concepts_lib.py +169 -0
  67. ldm/invoke/conditioning.py +289 -0
  68. ldm/invoke/devices.py +27 -0
  69. ldm/invoke/generator/__init__.py +4 -0
  70. ldm/invoke/generator/base.py +335 -0
  71. ldm/invoke/generator/embiggen.py +501 -0
  72. ldm/invoke/generator/img2img.py +97 -0
  73. ldm/invoke/generator/inpaint.py +358 -0
  74. ldm/invoke/generator/omnibus.py +175 -0
  75. ldm/invoke/generator/txt2img.py +88 -0
  76. ldm/invoke/generator/txt2img2img.py +182 -0
  77. ldm/invoke/globals.py +31 -0
  78. ldm/invoke/image_util.py +70 -0
  79. ldm/invoke/log.py +66 -0
  80. ldm/invoke/model_cache.py +449 -0
  81. ldm/invoke/patchmatch.py +44 -0
  82. ldm/invoke/pngwriter.py +113 -0
  83. ldm/invoke/prompt_parser.py +655 -0
  84. ldm/invoke/readline.py +442 -0
  85. ldm/invoke/restoration/__init__.py +4 -0
  86. ldm/invoke/restoration/base.py +38 -0
  87. ldm/invoke/restoration/codeformer.py +103 -0
  88. ldm/invoke/restoration/codeformer_arch.py +276 -0
  89. ldm/invoke/restoration/gfpgan.py +84 -0
  90. ldm/invoke/restoration/outcrop.py +108 -0
  91. ldm/invoke/restoration/outpaint.py +92 -0
  92. ldm/invoke/restoration/realesrgan.py +90 -0
  93. ldm/invoke/restoration/vqgan_arch.py +435 -0
  94. ldm/invoke/seamless.py +30 -0
  95. ldm/invoke/server.py +282 -0
  96. ldm/invoke/server_legacy.py +246 -0
  97. ldm/invoke/txt2mask.py +136 -0
  98. ldm/lr_scheduler.py +143 -0
  99. ldm/models/__init__.py +0 -0
  100. ldm/models/autoencoder.py +596 -0
  101. ldm/models/diffusion/__init__.py +0 -0
  102. ldm/models/diffusion/classifier.py +355 -0
  103. ldm/models/diffusion/cross_attention_control.py +443 -0
  104. ldm/models/diffusion/cross_attention_map_saving.py +95 -0
  105. ldm/models/diffusion/ddim.py +111 -0
  106. ldm/models/diffusion/ddpm.py +2263 -0
  107. ldm/models/diffusion/ksampler.py +312 -0
  108. ldm/models/diffusion/plms.py +146 -0
  109. ldm/models/diffusion/sampler.py +450 -0
  110. ldm/models/diffusion/shared_invokeai_diffusion.py +244 -0
  111. ldm/modules/__init__.py +0 -0
  112. ldm/modules/attention.py +274 -0
  113. ldm/modules/diffusionmodules/__init__.py +0 -0
  114. ldm/modules/diffusionmodules/model.py +894 -0
  115. ldm/modules/diffusionmodules/openaimodel.py +1036 -0
  116. ldm/modules/diffusionmodules/util.py +314 -0
  117. ldm/modules/distributions/__init__.py +0 -0
  118. ldm/modules/distributions/distributions.py +104 -0
  119. ldm/modules/ema.py +88 -0
  120. ldm/modules/embedding_manager.py +413 -0
  121. ldm/modules/encoders/__init__.py +0 -0
  122. ldm/modules/encoders/modules.py +772 -0
  123. ldm/modules/image_degradation/__init__.py +6 -0
  124. ldm/modules/image_degradation/bsrgan.py +846 -0
  125. ldm/modules/image_degradation/bsrgan_light.py +751 -0
  126. ldm/modules/image_degradation/utils_image.py +1024 -0
  127. ldm/modules/losses/__init__.py +1 -0
  128. ldm/modules/losses/contperceptual.py +175 -0
  129. ldm/modules/losses/vqperceptual.py +240 -0
  130. ldm/modules/x_transformer.py +752 -0
  131. ldm/simplet2i.py +13 -0
  132. ldm/util.py +264 -0
  133. scripts/configure_invokeai.py +797 -0
  134. scripts/create_root.py +43 -0
  135. scripts/dream.py +10 -0
  136. scripts/images2prompt.py +30 -0
  137. scripts/invoke.py +5 -0
  138. scripts/legacy_api.py +681 -0
  139. scripts/load_models.py +12 -0
  140. scripts/merge_embeddings.py +124 -0
  141. scripts/orig_scripts/img2img.py +296 -0
  142. scripts/orig_scripts/inpaint.py +98 -0
  143. scripts/orig_scripts/knn2img.py +397 -0
  144. scripts/orig_scripts/sample_diffusion.py +313 -0
  145. scripts/orig_scripts/train_searcher.py +147 -0
  146. scripts/orig_scripts/txt2img.py +324 -0
  147. scripts/preload_models.py +12 -0
  148. scripts/sd-metadata.py +22 -0
  149. vendored/clip/clip/__init__.py +1 -0
  150. vendored/clip/clip/bpe_simple_vocab_16e6.txt.gz +0 -0
  151. vendored/clip/clip/clip.py +237 -0
  152. vendored/clip/clip/model.py +436 -0
  153. vendored/clip/clip/simple_tokenizer.py +132 -0
  154. vendored/clip/hubconf.py +42 -0
  155. vendored/clip/setup.py +21 -0
  156. vendored/clip/tests/test_consistency.py +25 -0
  157. vendored/clipseg/datasets/coco_wrapper.py +99 -0
  158. vendored/clipseg/datasets/pascal_zeroshot.py +60 -0
  159. vendored/clipseg/datasets/pfe_dataset.py +129 -0
  160. vendored/clipseg/datasets/phrasecut.py +380 -0
  161. vendored/clipseg/datasets/utils.py +68 -0
  162. vendored/clipseg/evaluation_utils.py +292 -0
  163. vendored/clipseg/general_utils.py +272 -0
  164. vendored/clipseg/metrics.py +271 -0
  165. vendored/clipseg/models/clipseg.py +538 -0
  166. vendored/clipseg/models/vitseg.py +286 -0
  167. vendored/clipseg/score.py +453 -0
  168. vendored/clipseg/setup.py +30 -0
  169. 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)