diff --git a/ldm/generate.py b/ldm/generate.py index 6c1ecfa803..4f8f486524 100644 --- a/ldm/generate.py +++ b/ldm/generate.py @@ -436,6 +436,7 @@ class Generate: fit=fit, text_mask=text_mask, invert_mask=invert_mask, + force_outpaint=force_outpaint, ) # TODO: Hacky selection of operation to perform. Needs to be refactored. @@ -657,6 +658,7 @@ class Generate: mask_image:Image.Image=None, embiggen:bool=False, hires_fix:bool=False, + force_outpaint:bool=False, ): inpainting_model_in_use = self.sampler.uses_inpainting_model() @@ -669,7 +671,7 @@ class Generate: if inpainting_model_in_use: return self._make_omnibus() - if (init_image is not None) and (mask_image is not None): + if ((init_image is not None) and (mask_image is not None)) or force_outpaint: return self._make_inpaint() if init_image is not None: @@ -686,6 +688,7 @@ class Generate: fit=False, text_mask=None, invert_mask=False, + force_outpaint=False, ): init_image = None init_mask = None @@ -699,7 +702,7 @@ class Generate: # if image has a transparent area and no mask was provided, then try to generate mask if self._has_transparency(image): - self._transparency_check_and_warning(image, mask) + self._transparency_check_and_warning(image, mask, force_outpaint) init_mask = self._create_init_mask(image, width, height, fit=fit) if (image.width * image.height) > (self.width * self.height) and self.size_matters: @@ -1009,11 +1012,11 @@ class Generate: colored += 1 return colored == 0 - def _transparency_check_and_warning(self,image, mask): + def _transparency_check_and_warning(self,image, mask, force_outpaint=False): if not mask: print( '>> Initial image has transparent areas. Will inpaint in these regions.') - if self._check_for_erasure(image): + if (not force_outpaint) and self._check_for_erasure(image): print( '>> WARNING: Colors underneath the transparent region seem to have been erased.\n', '>> Inpainting will be suboptimal. Please preserve the colors when making\n', diff --git a/ldm/invoke/args.py b/ldm/invoke/args.py index 91a5fa061a..406d179f72 100644 --- a/ldm/invoke/args.py +++ b/ldm/invoke/args.py @@ -181,13 +181,16 @@ class Args(object): else: # no initial quote, so get everything up to the first thing # that looks like a switch - match = re.match('^(.+?)\s(--?[a-zA-Z].+)',cmd_string) - if match: - prompt,switches = match.groups() + if cmd_string.startswith('-'): + prompt = '' + switches = cmd_string else: - prompt = cmd_string - switches = '' - + match = re.match('^(.+?)\s(--?[a-zA-Z].+)',cmd_string) + if match: + prompt,switches = match.groups() + else: + prompt = cmd_string + switches = '' try: self._cmd_switches = self._cmd_parser.parse_args(shlex.split(switches)) setattr(self._cmd_switches,'prompt',prompt) @@ -572,9 +575,12 @@ class Args(object): ) render_group = parser.add_argument_group('General rendering') img2img_group = parser.add_argument_group('Image-to-image and inpainting') + inpainting_group = parser.add_argument_group('Inpainting') + outpainting_group = parser.add_argument_group('Outpainting and outcropping') variation_group = parser.add_argument_group('Creating and combining variations') postprocessing_group = parser.add_argument_group('Post-processing') special_effects_group = parser.add_argument_group('Special effects') + deprecated_group = parser.add_argument_group('Deprecated options') render_group.add_argument( '--prompt', default='', @@ -711,17 +717,6 @@ class Args(object): type=str, help='Path to input image for img2img mode (supersedes width and height)', ) - img2img_group.add_argument( - '-M', - '--init_mask', - type=str, - help='Path to input mask for inpainting mode (supersedes width and height)', - ) - img2img_group.add_argument( - '--invert_mask', - action='store_true', - help='Invert the mask', - ) img2img_group.add_argument( '-tm', '--text_mask', @@ -749,29 +744,68 @@ class Args(object): help='Strength for noising/unnoising. 0.0 preserves image exactly, 1.0 replaces it completely', default=0.75, ) - img2img_group.add_argument( - '-D', - '--out_direction', - nargs='+', + inpainting_group.add_argument( + '-M', + '--init_mask', type=str, - metavar=('direction', 'pixels'), - help='Direction to extend the given image (left|right|top|bottom). If a distance pixel value is not specified it defaults to half the image size' + help='Path to input mask for inpainting mode (supersedes width and height)', ) - img2img_group.add_argument( - '-c', - '--outcrop', - nargs='+', - type=str, - metavar=('direction','pixels'), - help='Outcrop the image with one or more direction/pixel pairs: -c top 64 bottom 128 left 64 right 64', + inpainting_group.add_argument( + '--invert_mask', + action='store_true', + help='Invert the mask', ) - img2img_group.add_argument( + inpainting_group.add_argument( '-r', '--inpaint_replace', type=float, default=0.0, help='when inpainting, adjust how aggressively to replace the part of the picture under the mask, from 0.0 (a gentle merge) to 1.0 (replace entirely)', ) + outpainting_group.add_argument( + '-c', + '--outcrop', + nargs='+', + type=str, + metavar=('direction','pixels'), + help='Outcrop the image with one or more direction/pixel pairs: e.g. -c top 64 bottom 128 left 64 right 64', + ) + outpainting_group.add_argument( + '--force_outpaint', + action='store_true', + default=False, + help='Force outpainting if you have no inpainting mask to pass', + ) + outpainting_group.add_argument( + '--seam_size', + type=int, + default=0, + help='When outpainting, size of the mask around the seam between original and outpainted image', + ) + outpainting_group.add_argument( + '--seam_blur', + type=int, + default=0, + help='When outpainting, the amount to blur the seam inwards', + ) + outpainting_group.add_argument( + '--seam_strength', + type=float, + default=0.7, + help='When outpainting, the img2img strength to use when filling the seam. Values around 0.7 work well', + ) + outpainting_group.add_argument( + '--seam_steps', + type=int, + default=10, + help='When outpainting, the number of steps to use to fill the seam. Low values (~10) work well', + ) + outpainting_group.add_argument( + '--tile_size', + type=int, + default=32, + help='When outpainting, the tile size to use for filling outpaint areas', + ) postprocessing_group.add_argument( '-ft', '--facetool', @@ -855,7 +889,14 @@ class Args(object): dest='use_mps_noise', help='Simulate noise on M1 systems to get the same results' ) - + deprecated_group.add_argument( + '-D', + '--out_direction', + nargs='+', + type=str, + metavar=('direction', 'pixels'), + help='Older outcropping system. Direction to extend the given image (left|right|top|bottom). If a distance pixel value is not specified it defaults to half the image size' + ) return parser def format_metadata(**kwargs): diff --git a/ldm/invoke/generator/omnibus.py b/ldm/invoke/generator/omnibus.py index a72a2d5f30..e8426a9205 100644 --- a/ldm/invoke/generator/omnibus.py +++ b/ldm/invoke/generator/omnibus.py @@ -42,7 +42,7 @@ class Omnibus(Img2Img,Txt2Img): ) if isinstance(init_image, Image.Image): - if init_image.mode=='RGBA': + if init_image.mode != 'RGB': init_image = init_image.convert('RGB') init_image = self._image_to_tensor(init_image) diff --git a/scripts/invoke.py b/scripts/invoke.py index 1937d47ab5..671a8ad227 100644 --- a/scripts/invoke.py +++ b/scripts/invoke.py @@ -172,9 +172,8 @@ def main_loop(gen, opt): except (OSError, AttributeError, KeyError): pass -# if len(opt.prompt) == 0: -# print('\nTry again with a prompt!') -# continue + if len(opt.prompt) == 0: + opt.prompt = '' # width and height are set by model if not specified if not opt.width: