mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Add patchmatch and infill_method parameter to prompt2image (options are 'patchmatch' or 'tile').
This commit is contained in:
parent
e3efcc620c
commit
98e3bbb3bd
@ -42,4 +42,5 @@ dependencies:
|
|||||||
- git+https://github.com/invoke-ai/Real-ESRGAN.git#egg=realesrgan
|
- git+https://github.com/invoke-ai/Real-ESRGAN.git#egg=realesrgan
|
||||||
- git+https://github.com/invoke-ai/GFPGAN.git#egg=gfpgan
|
- git+https://github.com/invoke-ai/GFPGAN.git#egg=gfpgan
|
||||||
- git+https://github.com/invoke-ai/clipseg.git@relaxed-python-requirement#egg=clipseg
|
- git+https://github.com/invoke-ai/clipseg.git@relaxed-python-requirement#egg=clipseg
|
||||||
|
- git+https://github.com/invoke-ai/PyPatchMatch@0.1.1#egg=pypatchmatch
|
||||||
- -e .
|
- -e .
|
||||||
|
@ -263,6 +263,8 @@ class Generate:
|
|||||||
), 'call to img2img() must include the init_img argument'
|
), 'call to img2img() must include the init_img argument'
|
||||||
return self.prompt2png(prompt, outdir, **kwargs)
|
return self.prompt2png(prompt, outdir, **kwargs)
|
||||||
|
|
||||||
|
from ldm.invoke.generator.inpaint import infill_methods
|
||||||
|
|
||||||
def prompt2image(
|
def prompt2image(
|
||||||
self,
|
self,
|
||||||
# these are common
|
# these are common
|
||||||
@ -323,8 +325,10 @@ class Generate:
|
|||||||
seam_strength: float = 0.7,
|
seam_strength: float = 0.7,
|
||||||
seam_steps: int = 10,
|
seam_steps: int = 10,
|
||||||
tile_size: int = 32,
|
tile_size: int = 32,
|
||||||
|
infill_method = infill_methods[0], # The infill method to use
|
||||||
force_outpaint: bool = False,
|
force_outpaint: bool = False,
|
||||||
enable_image_debugging = False,
|
enable_image_debugging = False,
|
||||||
|
|
||||||
**args,
|
**args,
|
||||||
): # eat up additional cruft
|
): # eat up additional cruft
|
||||||
"""
|
"""
|
||||||
@ -505,6 +509,7 @@ class Generate:
|
|||||||
seam_strength = seam_strength,
|
seam_strength = seam_strength,
|
||||||
seam_steps = seam_steps,
|
seam_steps = seam_steps,
|
||||||
tile_size = tile_size,
|
tile_size = tile_size,
|
||||||
|
infill_method = infill_method,
|
||||||
force_outpaint = force_outpaint,
|
force_outpaint = force_outpaint,
|
||||||
inpaint_height = inpaint_height,
|
inpaint_height = inpaint_height,
|
||||||
inpaint_width = inpaint_width,
|
inpaint_width = inpaint_width,
|
||||||
|
@ -17,6 +17,16 @@ from ldm.models.diffusion.ddim import DDIMSampler
|
|||||||
from ldm.models.diffusion.ksampler import KSampler
|
from ldm.models.diffusion.ksampler import KSampler
|
||||||
from ldm.invoke.generator.base import downsampling
|
from ldm.invoke.generator.base import downsampling
|
||||||
from ldm.util import debug_image
|
from ldm.util import debug_image
|
||||||
|
from patchmatch import patch_match
|
||||||
|
|
||||||
|
|
||||||
|
infill_methods: list[str] = list()
|
||||||
|
|
||||||
|
if patch_match.patchmatch_available:
|
||||||
|
infill_methods.append('patchmatch')
|
||||||
|
|
||||||
|
infill_methods.append('tile')
|
||||||
|
|
||||||
|
|
||||||
class Inpaint(Img2Img):
|
class Inpaint(Img2Img):
|
||||||
def __init__(self, model, precision):
|
def __init__(self, model, precision):
|
||||||
@ -43,18 +53,24 @@ class Inpaint(Img2Img):
|
|||||||
writeable=False
|
writeable=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def infill_patchmatch(self, im: Image.Image) -> Image:
|
||||||
|
if im.mode != 'RGBA':
|
||||||
|
return im
|
||||||
|
|
||||||
|
# Skip patchmatch if patchmatch isn't available
|
||||||
|
if not patch_match.patchmatch_available:
|
||||||
|
return im
|
||||||
|
|
||||||
|
# Patchmatch (note, we may want to expose patch_size? Increasing it significantly impacts performance though)
|
||||||
|
im_patched_np = patch_match.inpaint(im.convert('RGB'), ImageOps.invert(im.split()[-1]), patch_size = 3)
|
||||||
|
im_patched = Image.fromarray(im_patched_np, mode = 'RGB')
|
||||||
|
return im_patched
|
||||||
|
|
||||||
def tile_fill_missing(self, im: Image.Image, tile_size: int = 16, seed: int = None) -> Image:
|
def tile_fill_missing(self, im: Image.Image, tile_size: int = 16, seed: int = None) -> Image:
|
||||||
# Only fill if there's an alpha layer
|
# Only fill if there's an alpha layer
|
||||||
if im.mode != 'RGBA':
|
if im.mode != 'RGBA':
|
||||||
return im
|
return im
|
||||||
|
|
||||||
# # HACK PATCH MATCH
|
|
||||||
# from src.PyPatchMatch import patch_match
|
|
||||||
# im_patched_np = patch_match.inpaint(im.convert('RGB'), ImageOps.invert(im.split()[-1]), patch_size = 3)
|
|
||||||
# im_patched = Image.fromarray(im_patched_np, mode = 'RGB')
|
|
||||||
# return im_patched
|
|
||||||
# # /HACK
|
|
||||||
|
|
||||||
a = np.asarray(im, dtype=np.uint8)
|
a = np.asarray(im, dtype=np.uint8)
|
||||||
|
|
||||||
tile_size = (tile_size, tile_size)
|
tile_size = (tile_size, tile_size)
|
||||||
@ -161,6 +177,7 @@ class Inpaint(Img2Img):
|
|||||||
tile_size: int = 32,
|
tile_size: int = 32,
|
||||||
step_callback=None,
|
step_callback=None,
|
||||||
inpaint_replace=False, enable_image_debugging=False,
|
inpaint_replace=False, enable_image_debugging=False,
|
||||||
|
infill_method = infill_methods[0], # The infill method to use
|
||||||
**kwargs):
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Returns a function returning an image derived from the prompt and
|
Returns a function returning an image derived from the prompt and
|
||||||
@ -173,11 +190,13 @@ class Inpaint(Img2Img):
|
|||||||
if isinstance(init_image, PIL.Image.Image):
|
if isinstance(init_image, PIL.Image.Image):
|
||||||
self.pil_image = init_image.copy()
|
self.pil_image = init_image.copy()
|
||||||
|
|
||||||
# Fill missing areas of original image
|
# Do infill
|
||||||
|
if infill_method == 'patchmatch' and patch_match.patchmatch_available:
|
||||||
|
init_filled = self.infill_patchmatch(self.pil_image.copy())
|
||||||
|
else: # if infill_method == 'tile': # Only two methods right now, so always use 'tile' if not patchmatch
|
||||||
init_filled = self.tile_fill_missing(
|
init_filled = self.tile_fill_missing(
|
||||||
self.pil_image.copy(),
|
self.pil_image.copy(),
|
||||||
seed = self.seed if (self.seed is not None
|
seed = self.seed,
|
||||||
and self.seed >= 0) else self.new_seed(),
|
|
||||||
tile_size = tile_size
|
tile_size = tile_size
|
||||||
)
|
)
|
||||||
init_filled.paste(init_image, (0,0), init_image.split()[-1])
|
init_filled.paste(init_image, (0,0), init_image.split()[-1])
|
||||||
|
Loading…
Reference in New Issue
Block a user