enhance outcropping with ability to direct contents of new regions

- When outcropping an image you can now add a `--new_prompt` option, to specify
  a new prompt to be used instead of the original one used to generate the image.

- Similarly you can provide a new seed using `--seed` (or `-S`). A seed of zero
  will pick one randomly.

- This PR also fixes the crash that happened when trying to outcrop an image
  that does not contain InvokeAI metadata.
This commit is contained in:
Lincoln Stein 2022-11-08 17:27:42 +00:00
parent 5606af5083
commit 2487040ae3
5 changed files with 48 additions and 14 deletions

View File

@ -92,6 +92,21 @@ The new image is larger than the original (576x704) because 64 pixels were added
to the top and right sides. You will need enough VRAM to process an image of to the top and right sides. You will need enough VRAM to process an image of
this size. this size.
#### Outcropping non-InvokeAI images
You can outcrop an arbitrary image that was not generated by InvokeAI,
but your results will vary. The `inpainting-1.5` model is highly
recommended, but if not feasible, then you may be able to improve the
output by conditioning the outcropping with a text prompt that
describes the scene using the `--new_prompt` argument:
```bash
invoke> !fix images/vacation.png --outcrop top 128 --new_prompt "family vacation"
```
You may also provide a different seed for outcropping to use by passing
`-S<seed>`. A seed of "0" will generate a new random seed.
A number of caveats: A number of caveats:
1. Although you can specify any pixel values, they will be rounded up to the 1. Although you can specify any pixel values, they will be rounded up to the

View File

@ -561,18 +561,22 @@ class Generate:
): ):
# retrieve the seed from the image; # retrieve the seed from the image;
seed = None seed = None
image_metadata = None
prompt = None prompt = None
args = metadata_from_png(image_path) args = metadata_from_png(image_path)
seed = args.seed if opt.seed is not None:
prompt = args.prompt or '' seed = opt.seed
if seed == 0: elif args.seed >= 0:
seed = random.randrange(0, np.iinfo(np.uint32).max) seed = args.seed
opt.seed = seed
print(f'>> generated new seed {seed} and prompt "{prompt}" for {image_path}')
else: else:
print(f'>> retrieved seed {seed} and prompt "{prompt}" from {image_path}') seed = random.randrange(0, np.iinfo(np.uint32).max)
if opt.prompt is not None:
prompt = opt.prompt
else:
prompt = args.prompt
print(f'>> using seed {seed} and prompt "{prompt}" for {image_path}')
# try to reuse the same filename prefix as the original file. # try to reuse the same filename prefix as the original file.
# we take everything up to the first period # we take everything up to the first period
@ -619,6 +623,10 @@ class Generate:
extend_instructions[direction]=int(pixels) extend_instructions[direction]=int(pixels)
except ValueError: except ValueError:
print(f'** invalid extension instruction. Use <directions> <pixels>..., as in "top 64 left 128 right 64 bottom 64"') print(f'** invalid extension instruction. Use <directions> <pixels>..., as in "top 64 left 128 right 64 bottom 64"')
opt.seed = seed
opt.prompt = prompt
if len(extend_instructions)>0: if len(extend_instructions)>0:
restorer = Outcrop(image,self,) restorer = Outcrop(image,self,)
return restorer.process ( return restorer.process (

View File

@ -866,6 +866,11 @@ class Args(object):
default=32, default=32,
help='When outpainting, the tile size to use for filling outpaint areas', help='When outpainting, the tile size to use for filling outpaint areas',
) )
postprocessing_group.add_argument(
'--new_prompt',
type=str,
help='Change the text prompt applied during postprocessing (default, use original generation prompt)',
)
postprocessing_group.add_argument( postprocessing_group.add_argument(
'-ft', '-ft',
'--facetool', '--facetool',

View File

@ -32,8 +32,8 @@ class Outcrop(object):
image_callback(img,preferred_seed,use_prefix=prefix,**kwargs) image_callback(img,preferred_seed,use_prefix=prefix,**kwargs)
result= self.generate.prompt2image( result= self.generate.prompt2image(
orig_opt.prompt, opt.prompt,
seed = orig_opt.seed if orig_opt.seed>0 else opt.seed, seed = opt.seed if opt.seed else orig_opt.seed,
sampler = self.generate.sampler, sampler = self.generate.sampler,
steps = opt.steps, steps = opt.steps,
cfg_scale = opt.cfg_scale, cfg_scale = opt.cfg_scale,

View File

@ -277,7 +277,7 @@ def main_loop(gen, opt):
filename = f'{prefix}.{use_prefix}.{seed}.png' filename = f'{prefix}.{use_prefix}.{seed}.png'
tm = opt.text_mask[0] tm = opt.text_mask[0]
th = opt.text_mask[1] if len(opt.text_mask)>1 else 0.5 th = opt.text_mask[1] if len(opt.text_mask)>1 else 0.5
formatted_dream_prompt = f'!mask {opt.prompt} -tm {tm} {th}' formatted_dream_prompt = f'!mask {opt.input_file_path} -tm {tm} {th}'
path = file_writer.save_image_and_prompt_to_png( path = file_writer.save_image_and_prompt_to_png(
image = image, image = image,
dream_prompt = formatted_dream_prompt, dream_prompt = formatted_dream_prompt,
@ -317,7 +317,7 @@ def main_loop(gen, opt):
tool = re.match('postprocess:(\w+)',opt.last_operation).groups()[0] tool = re.match('postprocess:(\w+)',opt.last_operation).groups()[0]
add_postprocessing_to_metadata( add_postprocessing_to_metadata(
opt, opt,
opt.prompt, opt.input_file_path,
filename, filename,
tool, tool,
formatted_dream_prompt, formatted_dream_prompt,
@ -614,10 +614,16 @@ def do_textmask(gen, opt, callback):
) )
def do_postprocess (gen, opt, callback): def do_postprocess (gen, opt, callback):
file_path = opt.prompt # treat the prompt as the file pathname file_path = opt.prompt # treat the prompt as the file pathname
if opt.new_prompt is not None:
opt.prompt = opt.new_prompt
else:
opt.prompt = None
if os.path.dirname(file_path) == '': #basename given if os.path.dirname(file_path) == '': #basename given
file_path = os.path.join(opt.outdir,file_path) file_path = os.path.join(opt.outdir,file_path)
opt.input_file_path = file_path
tool=None tool=None
if opt.facetool_strength > 0: if opt.facetool_strength > 0:
tool = opt.facetool tool = opt.facetool
@ -707,7 +713,7 @@ def prepare_image_metadata(
elif len(prior_variations) > 0: elif len(prior_variations) > 0:
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed) formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed)
elif operation == 'postprocess': elif operation == 'postprocess':
formatted_dream_prompt = '!fix '+opt.dream_prompt_str(seed=seed) formatted_dream_prompt = '!fix '+opt.dream_prompt_str(seed=seed,prompt=opt.input_file_path)
else: else:
formatted_dream_prompt = opt.dream_prompt_str(seed=seed) formatted_dream_prompt = opt.dream_prompt_str(seed=seed)
return filename,formatted_dream_prompt return filename,formatted_dream_prompt