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,358 @@
1
+ '''
2
+ ldm.invoke.generator.inpaint descends from ldm.invoke.generator
3
+ '''
4
+
5
+ import math
6
+ import torch
7
+ import torchvision.transforms as T
8
+ import numpy as np
9
+ import cv2 as cv
10
+ import PIL
11
+ from PIL import Image, ImageFilter, ImageOps, ImageChops
12
+ from skimage.exposure.histogram_matching import match_histograms
13
+ from einops import rearrange, repeat
14
+ from ldm.invoke.devices import choose_autocast
15
+ from ldm.invoke.generator.img2img import Img2Img
16
+ from ldm.models.diffusion.ddim import DDIMSampler
17
+ from ldm.models.diffusion.ksampler import KSampler
18
+ from ldm.invoke.generator.base import downsampling
19
+ from ldm.util import debug_image
20
+ from ldm.invoke.patchmatch import PatchMatch
21
+ from ldm.invoke.globals import Globals
22
+
23
+ def infill_methods()->list[str]:
24
+ methods = list()
25
+ if PatchMatch.patchmatch_available():
26
+ methods.append('patchmatch')
27
+ methods.append('tile')
28
+ return methods
29
+
30
+ class Inpaint(Img2Img):
31
+ def __init__(self, model, precision):
32
+ self.init_latent = None
33
+ self.pil_image = None
34
+ self.pil_mask = None
35
+ self.mask_blur_radius = 0
36
+ self.infill_method = None
37
+ super().__init__(model, precision)
38
+
39
+ # Outpaint support code
40
+ def get_tile_images(self, image: np.ndarray, width=8, height=8):
41
+ _nrows, _ncols, depth = image.shape
42
+ _strides = image.strides
43
+
44
+ nrows, _m = divmod(_nrows, height)
45
+ ncols, _n = divmod(_ncols, width)
46
+ if _m != 0 or _n != 0:
47
+ return None
48
+
49
+ return np.lib.stride_tricks.as_strided(
50
+ np.ravel(image),
51
+ shape=(nrows, ncols, height, width, depth),
52
+ strides=(height * _strides[0], width * _strides[1], *_strides),
53
+ writeable=False
54
+ )
55
+
56
+ def infill_patchmatch(self, im: Image.Image) -> Image:
57
+ if im.mode != 'RGBA':
58
+ return im
59
+
60
+ # Skip patchmatch if patchmatch isn't available
61
+ if not PatchMatch.patchmatch_available():
62
+ return im
63
+
64
+ # Patchmatch (note, we may want to expose patch_size? Increasing it significantly impacts performance though)
65
+ im_patched_np = PatchMatch.inpaint(im.convert('RGB'), ImageOps.invert(im.split()[-1]), patch_size = 3)
66
+ im_patched = Image.fromarray(im_patched_np, mode = 'RGB')
67
+ return im_patched
68
+
69
+ def tile_fill_missing(self, im: Image.Image, tile_size: int = 16, seed: int = None) -> Image:
70
+ # Only fill if there's an alpha layer
71
+ if im.mode != 'RGBA':
72
+ return im
73
+
74
+ a = np.asarray(im, dtype=np.uint8)
75
+
76
+ tile_size = (tile_size, tile_size)
77
+
78
+ # Get the image as tiles of a specified size
79
+ tiles = self.get_tile_images(a,*tile_size).copy()
80
+
81
+ # Get the mask as tiles
82
+ tiles_mask = tiles[:,:,:,:,3]
83
+
84
+ # Find any mask tiles with any fully transparent pixels (we will be replacing these later)
85
+ tmask_shape = tiles_mask.shape
86
+ tiles_mask = tiles_mask.reshape(math.prod(tiles_mask.shape))
87
+ n,ny = (math.prod(tmask_shape[0:2])), math.prod(tmask_shape[2:])
88
+ tiles_mask = (tiles_mask > 0)
89
+ tiles_mask = tiles_mask.reshape((n,ny)).all(axis = 1)
90
+
91
+ # Get RGB tiles in single array and filter by the mask
92
+ tshape = tiles.shape
93
+ tiles_all = tiles.reshape((math.prod(tiles.shape[0:2]), * tiles.shape[2:]))
94
+ filtered_tiles = tiles_all[tiles_mask]
95
+
96
+ if len(filtered_tiles) == 0:
97
+ return im
98
+
99
+ # Find all invalid tiles and replace with a random valid tile
100
+ replace_count = (tiles_mask == False).sum()
101
+ rng = np.random.default_rng(seed = seed)
102
+ tiles_all[np.logical_not(tiles_mask)] = filtered_tiles[rng.choice(filtered_tiles.shape[0], replace_count),:,:,:]
103
+
104
+ # Convert back to an image
105
+ tiles_all = tiles_all.reshape(tshape)
106
+ tiles_all = tiles_all.swapaxes(1,2)
107
+ st = tiles_all.reshape((math.prod(tiles_all.shape[0:2]), math.prod(tiles_all.shape[2:4]), tiles_all.shape[4]))
108
+ si = Image.fromarray(st, mode='RGBA')
109
+
110
+ return si
111
+
112
+
113
+ def mask_edge(self, mask: Image, edge_size: int, edge_blur: int) -> Image:
114
+ npimg = np.asarray(mask, dtype=np.uint8)
115
+
116
+ # Detect any partially transparent regions
117
+ npgradient = np.uint8(255 * (1.0 - np.floor(np.abs(0.5 - np.float32(npimg) / 255.0) * 2.0)))
118
+
119
+ # Detect hard edges
120
+ npedge = cv.Canny(npimg, threshold1=100, threshold2=200)
121
+
122
+ # Combine
123
+ npmask = npgradient + npedge
124
+
125
+ # Expand
126
+ npmask = cv.dilate(npmask, np.ones((3,3), np.uint8), iterations = int(edge_size / 2))
127
+
128
+ new_mask = Image.fromarray(npmask)
129
+
130
+ if edge_blur > 0:
131
+ new_mask = new_mask.filter(ImageFilter.BoxBlur(edge_blur))
132
+
133
+ return ImageOps.invert(new_mask)
134
+
135
+
136
+ def seam_paint(self,
137
+ im: Image.Image,
138
+ seam_size: int,
139
+ seam_blur: int,
140
+ prompt,sampler,steps,cfg_scale,ddim_eta,
141
+ conditioning,strength,
142
+ noise,
143
+ step_callback
144
+ ) -> Image.Image:
145
+ hard_mask = self.pil_image.split()[-1].copy()
146
+ mask = self.mask_edge(hard_mask, seam_size, seam_blur)
147
+
148
+ make_image = self.get_make_image(
149
+ prompt,
150
+ sampler,
151
+ steps,
152
+ cfg_scale,
153
+ ddim_eta,
154
+ conditioning,
155
+ init_image = im.copy().convert('RGBA'),
156
+ mask_image = mask.convert('RGB'), # Code currently requires an RGB mask
157
+ strength = strength,
158
+ mask_blur_radius = 0,
159
+ seam_size = 0,
160
+ step_callback = step_callback,
161
+ inpaint_width = im.width,
162
+ inpaint_height = im.height
163
+ )
164
+
165
+ seam_noise = self.get_noise(im.width, im.height)
166
+
167
+ result = make_image(seam_noise)
168
+
169
+ return result
170
+
171
+
172
+ @torch.no_grad()
173
+ def get_make_image(self,prompt,sampler,steps,cfg_scale,ddim_eta,
174
+ conditioning,init_image,mask_image,strength,
175
+ mask_blur_radius: int = 8,
176
+ # Seam settings - when 0, doesn't fill seam
177
+ seam_size: int = 0,
178
+ seam_blur: int = 0,
179
+ seam_strength: float = 0.7,
180
+ seam_steps: int = 10,
181
+ tile_size: int = 32,
182
+ step_callback=None,
183
+ inpaint_replace=False, enable_image_debugging=False,
184
+ infill_method = None,
185
+ inpaint_width=None,
186
+ inpaint_height=None,
187
+ **kwargs):
188
+ """
189
+ Returns a function returning an image derived from the prompt and
190
+ the initial image + mask. Return value depends on the seed at
191
+ the time you call it. kwargs are 'init_latent' and 'strength'
192
+ """
193
+
194
+ self.enable_image_debugging = enable_image_debugging
195
+ self.infill_method = infill_method or infill_methods()[0], # The infill method to use
196
+
197
+ self.inpaint_width = inpaint_width
198
+ self.inpaint_height = inpaint_height
199
+
200
+ if isinstance(init_image, PIL.Image.Image):
201
+ self.pil_image = init_image.copy()
202
+
203
+ # Do infill
204
+ if infill_method == 'patchmatch' and PatchMatch.patchmatch_available():
205
+ init_filled = self.infill_patchmatch(self.pil_image.copy())
206
+ else: # if infill_method == 'tile': # Only two methods right now, so always use 'tile' if not patchmatch
207
+ init_filled = self.tile_fill_missing(
208
+ self.pil_image.copy(),
209
+ seed = self.seed,
210
+ tile_size = tile_size
211
+ )
212
+ init_filled.paste(init_image, (0,0), init_image.split()[-1])
213
+
214
+ # Resize if requested for inpainting
215
+ if inpaint_width and inpaint_height:
216
+ init_filled = init_filled.resize((inpaint_width, inpaint_height))
217
+
218
+ debug_image(init_filled, "init_filled", debug_status=self.enable_image_debugging)
219
+
220
+ # Create init tensor
221
+ init_image = self._image_to_tensor(init_filled.convert('RGB'))
222
+
223
+ if isinstance(mask_image, PIL.Image.Image):
224
+ self.pil_mask = mask_image.copy()
225
+ debug_image(mask_image, "mask_image BEFORE multiply with pil_image", debug_status=self.enable_image_debugging)
226
+
227
+ mask_image = ImageChops.multiply(mask_image, self.pil_image.split()[-1].convert('RGB'))
228
+ self.pil_mask = mask_image
229
+
230
+ # Resize if requested for inpainting
231
+ if inpaint_width and inpaint_height:
232
+ mask_image = mask_image.resize((inpaint_width, inpaint_height))
233
+
234
+ debug_image(mask_image, "mask_image AFTER multiply with pil_image", debug_status=self.enable_image_debugging)
235
+ mask_image = mask_image.resize(
236
+ (
237
+ mask_image.width // downsampling,
238
+ mask_image.height // downsampling
239
+ ),
240
+ resample=Image.Resampling.NEAREST
241
+ )
242
+ mask_image = self._image_to_tensor(mask_image,normalize=False)
243
+
244
+ self.mask_blur_radius = mask_blur_radius
245
+
246
+ # klms samplers not supported yet, so ignore previous sampler
247
+ if isinstance(sampler,KSampler):
248
+ print(
249
+ f">> Using recommended DDIM sampler for inpainting."
250
+ )
251
+ sampler = DDIMSampler(self.model, device=self.model.device)
252
+
253
+ sampler.make_schedule(
254
+ ddim_num_steps=steps, ddim_eta=ddim_eta, verbose=False
255
+ )
256
+
257
+ mask_image = mask_image[0][0].unsqueeze(0).repeat(4,1,1).unsqueeze(0)
258
+ mask_image = repeat(mask_image, '1 ... -> b ...', b=1)
259
+
260
+ scope = choose_autocast(self.precision)
261
+ with scope(self.model.device.type):
262
+ self.init_latent = self.model.get_first_stage_encoding(
263
+ self.model.encode_first_stage(init_image)
264
+ ) # move to latent space
265
+
266
+ t_enc = int(strength * steps)
267
+ # todo: support cross-attention control
268
+ uc, c, _ = conditioning
269
+
270
+ print(f">> target t_enc is {t_enc} steps")
271
+
272
+ @torch.no_grad()
273
+ def make_image(x_T):
274
+ # encode (scaled latent)
275
+ z_enc = sampler.stochastic_encode(
276
+ self.init_latent,
277
+ torch.tensor([t_enc - 1]).to(self.model.device),
278
+ noise=x_T
279
+ )
280
+
281
+ # to replace masked area with latent noise, weighted by inpaint_replace strength
282
+ if inpaint_replace > 0.0:
283
+ print(f'>> inpaint will replace what was under the mask with a strength of {inpaint_replace}')
284
+ l_noise = self.get_noise(kwargs['width'],kwargs['height'])
285
+ inverted_mask = 1.0-mask_image # there will be 1s where the mask is
286
+ masked_region = (1.0-inpaint_replace) * inverted_mask * z_enc + inpaint_replace * inverted_mask * l_noise
287
+ z_enc = z_enc * mask_image + masked_region
288
+
289
+ if self.free_gpu_mem and self.model.model.device != self.model.device:
290
+ self.model.model.to(self.model.device)
291
+
292
+ # decode it
293
+ samples = sampler.decode(
294
+ z_enc,
295
+ c,
296
+ t_enc,
297
+ img_callback = step_callback,
298
+ unconditional_guidance_scale = cfg_scale,
299
+ unconditional_conditioning = uc,
300
+ mask = mask_image,
301
+ init_latent = self.init_latent
302
+ )
303
+
304
+ result = self.sample_to_image(samples)
305
+
306
+ # Seam paint if this is our first pass (seam_size set to 0 during seam painting)
307
+ if seam_size > 0:
308
+ old_image = self.pil_image or init_image
309
+ old_mask = self.pil_mask or mask_image
310
+
311
+ result = self.seam_paint(
312
+ result,
313
+ seam_size,
314
+ seam_blur,
315
+ prompt,
316
+ sampler,
317
+ seam_steps,
318
+ cfg_scale,
319
+ ddim_eta,
320
+ conditioning,
321
+ seam_strength,
322
+ x_T,
323
+ step_callback)
324
+
325
+ # Restore original settings
326
+ self.get_make_image(prompt,sampler,steps,cfg_scale,ddim_eta,
327
+ conditioning,
328
+ old_image,
329
+ old_mask,
330
+ strength,
331
+ mask_blur_radius, seam_size, seam_blur, seam_strength,
332
+ seam_steps, tile_size, step_callback,
333
+ inpaint_replace, enable_image_debugging,
334
+ inpaint_width = inpaint_width,
335
+ inpaint_height = inpaint_height,
336
+ infill_method = infill_method,
337
+ **kwargs)
338
+
339
+ return result
340
+
341
+ return make_image
342
+
343
+
344
+ def sample_to_image(self, samples)->Image.Image:
345
+ gen_result = super().sample_to_image(samples).convert('RGB')
346
+ debug_image(gen_result, "gen_result", debug_status=self.enable_image_debugging)
347
+
348
+ # Resize if necessary
349
+ if self.inpaint_width and self.inpaint_height:
350
+ gen_result = gen_result.resize(self.pil_image.size)
351
+
352
+ if self.pil_image is None or self.pil_mask is None:
353
+ return gen_result
354
+
355
+ corrected_result = super().repaste_and_color_correct(gen_result, self.pil_image, self.pil_mask, self.mask_blur_radius)
356
+ debug_image(corrected_result, "corrected_result", debug_status=self.enable_image_debugging)
357
+
358
+ return corrected_result
@@ -0,0 +1,175 @@
1
+ """omnibus module to be used with the runwayml 9-channel custom inpainting model"""
2
+
3
+ import torch
4
+ import numpy as np
5
+ from einops import repeat
6
+ from PIL import Image, ImageOps, ImageChops
7
+ from ldm.invoke.devices import choose_autocast
8
+ from ldm.invoke.generator.base import downsampling
9
+ from ldm.invoke.generator.img2img import Img2Img
10
+ from ldm.invoke.generator.txt2img import Txt2Img
11
+
12
+ class Omnibus(Img2Img,Txt2Img):
13
+ def __init__(self, model, precision):
14
+ super().__init__(model, precision)
15
+ self.pil_mask = None
16
+ self.pil_image = None
17
+
18
+ def get_make_image(
19
+ self,
20
+ prompt,
21
+ sampler,
22
+ steps,
23
+ cfg_scale,
24
+ ddim_eta,
25
+ conditioning,
26
+ width,
27
+ height,
28
+ init_image = None,
29
+ mask_image = None,
30
+ strength = None,
31
+ step_callback=None,
32
+ threshold=0.0,
33
+ perlin=0.0,
34
+ mask_blur_radius: int = 8,
35
+ **kwargs):
36
+ """
37
+ Returns a function returning an image derived from the prompt and the initial image
38
+ Return value depends on the seed at the time you call it.
39
+ """
40
+ self.perlin = perlin
41
+ num_samples = 1
42
+
43
+ sampler.make_schedule(
44
+ ddim_num_steps=steps, ddim_eta=ddim_eta, verbose=False
45
+ )
46
+
47
+ if isinstance(init_image, Image.Image):
48
+ self.pil_image = init_image
49
+ if init_image.mode != 'RGB':
50
+ init_image = init_image.convert('RGB')
51
+ init_image = self._image_to_tensor(init_image)
52
+
53
+ if isinstance(mask_image, Image.Image):
54
+ self.pil_mask = mask_image
55
+
56
+ mask_image = ImageChops.multiply(mask_image.convert('L'), self.pil_image.split()[-1])
57
+ mask_image = self._image_to_tensor(ImageOps.invert(mask_image), normalize=False)
58
+
59
+ self.mask_blur_radius = mask_blur_radius
60
+
61
+ t_enc = steps
62
+
63
+ if init_image is not None and mask_image is not None: # inpainting
64
+ masked_image = init_image * (1 - mask_image) # masked image is the image masked by mask - masked regions zero
65
+
66
+ elif init_image is not None: # img2img
67
+ scope = choose_autocast(self.precision)
68
+
69
+ with scope(self.model.device.type):
70
+ self.init_latent = self.model.get_first_stage_encoding(
71
+ self.model.encode_first_stage(init_image)
72
+ ) # move to latent space
73
+
74
+ # create a completely black mask (1s)
75
+ mask_image = torch.ones(1, 1, init_image.shape[2], init_image.shape[3], device=self.model.device)
76
+ # and the masked image is just a copy of the original
77
+ masked_image = init_image
78
+
79
+ else: # txt2img
80
+ init_image = torch.zeros(1, 3, height, width, device=self.model.device)
81
+ mask_image = torch.ones(1, 1, height, width, device=self.model.device)
82
+ masked_image = init_image
83
+
84
+ self.init_latent = init_image
85
+ height = init_image.shape[2]
86
+ width = init_image.shape[3]
87
+ model = self.model
88
+
89
+ def make_image(x_T):
90
+ with torch.no_grad():
91
+ scope = choose_autocast(self.precision)
92
+ with scope(self.model.device.type):
93
+
94
+ batch = self.make_batch_sd(
95
+ init_image,
96
+ mask_image,
97
+ masked_image,
98
+ prompt=prompt,
99
+ device=model.device,
100
+ num_samples=num_samples,
101
+ )
102
+
103
+ c = model.cond_stage_model.encode(batch["txt"])
104
+ c_cat = list()
105
+ for ck in model.concat_keys:
106
+ cc = batch[ck].float()
107
+ if ck != model.masked_image_key:
108
+ bchw = [num_samples, 4, height//8, width//8]
109
+ cc = torch.nn.functional.interpolate(cc, size=bchw[-2:])
110
+ else:
111
+ cc = model.get_first_stage_encoding(model.encode_first_stage(cc))
112
+ c_cat.append(cc)
113
+ c_cat = torch.cat(c_cat, dim=1)
114
+
115
+ # cond
116
+ cond={"c_concat": [c_cat], "c_crossattn": [c]}
117
+
118
+ # uncond cond
119
+ uc_cross = model.get_unconditional_conditioning(num_samples, "")
120
+ uc_full = {"c_concat": [c_cat], "c_crossattn": [uc_cross]}
121
+ shape = [model.channels, height//8, width//8]
122
+
123
+ samples, _ = sampler.sample(
124
+ batch_size = 1,
125
+ S = steps,
126
+ x_T = x_T,
127
+ conditioning = cond,
128
+ shape = shape,
129
+ verbose = False,
130
+ unconditional_guidance_scale = cfg_scale,
131
+ unconditional_conditioning = uc_full,
132
+ eta = 1.0,
133
+ img_callback = step_callback,
134
+ threshold = threshold,
135
+ )
136
+ if self.free_gpu_mem:
137
+ self.model.model.to("cpu")
138
+ return self.sample_to_image(samples)
139
+
140
+ return make_image
141
+
142
+ def make_batch_sd(
143
+ self,
144
+ image,
145
+ mask,
146
+ masked_image,
147
+ prompt,
148
+ device,
149
+ num_samples=1):
150
+ batch = {
151
+ "image": repeat(image.to(device=device), "1 ... -> n ...", n=num_samples),
152
+ "txt": num_samples * [prompt],
153
+ "mask": repeat(mask.to(device=device), "1 ... -> n ...", n=num_samples),
154
+ "masked_image": repeat(masked_image.to(device=device), "1 ... -> n ...", n=num_samples),
155
+ }
156
+ return batch
157
+
158
+ def get_noise(self, width:int, height:int):
159
+ if self.init_latent is not None:
160
+ height = self.init_latent.shape[2]
161
+ width = self.init_latent.shape[3]
162
+ return Txt2Img.get_noise(self,width,height)
163
+
164
+
165
+ def sample_to_image(self, samples)->Image.Image:
166
+ gen_result = super().sample_to_image(samples).convert('RGB')
167
+
168
+ if self.pil_image is None or self.pil_mask is None:
169
+ return gen_result
170
+ if self.pil_image.size != self.pil_mask.size:
171
+ return gen_result
172
+
173
+ corrected_result = super(Img2Img, self).repaste_and_color_correct(gen_result, self.pil_image, self.pil_mask, self.mask_blur_radius)
174
+
175
+ return corrected_result
@@ -0,0 +1,88 @@
1
+ '''
2
+ ldm.invoke.generator.txt2img inherits from ldm.invoke.generator
3
+ '''
4
+
5
+ import torch
6
+ import numpy as np
7
+ from ldm.invoke.generator.base import Generator
8
+ from ldm.models.diffusion.shared_invokeai_diffusion import InvokeAIDiffuserComponent
9
+ import gc
10
+
11
+
12
+ class Txt2Img(Generator):
13
+ def __init__(self, model, precision):
14
+ super().__init__(model, precision)
15
+
16
+ @torch.no_grad()
17
+ def get_make_image(self,prompt,sampler,steps,cfg_scale,ddim_eta,
18
+ conditioning,width,height,step_callback=None,threshold=0.0,perlin=0.0,
19
+ attention_maps_callback=None,
20
+ **kwargs):
21
+ """
22
+ Returns a function returning an image derived from the prompt and the initial image
23
+ Return value depends on the seed at the time you call it
24
+ kwargs are 'width' and 'height'
25
+ """
26
+ self.perlin = perlin
27
+ uc, c, extra_conditioning_info = conditioning
28
+
29
+ @torch.no_grad()
30
+ def make_image(x_T):
31
+ shape = [
32
+ self.latent_channels,
33
+ height // self.downsampling_factor,
34
+ width // self.downsampling_factor,
35
+ ]
36
+
37
+ if self.free_gpu_mem and self.model.model.device != self.model.device:
38
+ self.model.model.to(self.model.device)
39
+
40
+ sampler.make_schedule(ddim_num_steps=steps, ddim_eta=ddim_eta, verbose=False)
41
+
42
+ samples, _ = sampler.sample(
43
+ batch_size = 1,
44
+ S = steps,
45
+ x_T = x_T,
46
+ conditioning = c,
47
+ shape = shape,
48
+ verbose = False,
49
+ unconditional_guidance_scale = cfg_scale,
50
+ unconditional_conditioning = uc,
51
+ extra_conditioning_info = extra_conditioning_info,
52
+ eta = ddim_eta,
53
+ img_callback = step_callback,
54
+ threshold = threshold,
55
+ attention_maps_callback = attention_maps_callback,
56
+ )
57
+
58
+ if self.free_gpu_mem:
59
+ self.model.model.to('cpu')
60
+ self.model.cond_stage_model.device = 'cpu'
61
+ self.model.cond_stage_model.to('cpu')
62
+ gc.collect()
63
+ torch.cuda.empty_cache()
64
+
65
+ return self.sample_to_image(samples)
66
+
67
+ return make_image
68
+
69
+
70
+ # returns a tensor filled with random numbers from a normal distribution
71
+ def get_noise(self,width,height):
72
+ device = self.model.device
73
+ if self.use_mps_noise or device.type == 'mps':
74
+ x = torch.randn([1,
75
+ self.latent_channels,
76
+ height // self.downsampling_factor,
77
+ width // self.downsampling_factor],
78
+ device='cpu').to(device)
79
+ else:
80
+ x = torch.randn([1,
81
+ self.latent_channels,
82
+ height // self.downsampling_factor,
83
+ width // self.downsampling_factor],
84
+ device=device)
85
+ if self.perlin > 0.0:
86
+ x = (1-self.perlin)*x + self.perlin*self.get_perlin_noise(width // self.downsampling_factor, height // self.downsampling_factor)
87
+ return x
88
+