feature: accept multiple input images to allow batch editing

- move "surprise me" to "edit-demo"
pull/240/head
Bryce 2 years ago committed by Bryce Drennan
parent 63f32846bb
commit d220819377

@ -69,12 +69,12 @@ with prompt-based masking.
<img src="assets/bowl_of_fruit_strawberries.jpg" height="256"><img src="assets/freckled_woman_cyborg.jpg" height="256"><br> <img src="assets/bowl_of_fruit_strawberries.jpg" height="256"><img src="assets/freckled_woman_cyborg.jpg" height="256"><br>
<img src="assets/girl-pearl-clown-compare.gif" height="256"><img src="assets/mona-lisa-headshot-anim.gif" height="256"><br> <img src="assets/girl-pearl-clown-compare.gif" height="256"><img src="assets/mona-lisa-headshot-anim.gif" height="256"><br>
Want just quickly have some fun? Try `--surprise-me` to apply some pre-defined edits. Want just quickly have some fun? Try `edit-demo` to apply some pre-defined edits.
```bash ```bash
>> aimg edit --gif --surprise-me pearl_girl.jpg >> aimg edit-demo pearl_girl.jpg
>> aimg edit --gif --surprise-me mona-lisa.jpg >> aimg edit-demo mona-lisa.jpg
>> aimg edit --gif --surprise-me luke.jpg >> aimg edit-demo luke.jpg
>> aimg edit --gif --surprise-me spock.jpg >> aimg edit-demo spock.jpg
``` ```
<img src="assets/girl_with_a_pearl_earring_suprise.gif" height="256"><img src="assets/mona-lisa-suprise.gif" height="256"><br> <img src="assets/girl_with_a_pearl_earring_suprise.gif" height="256"><img src="assets/mona-lisa-suprise.gif" height="256"><br>
<img src="assets/luke-suprise.gif" height="256"><img src="assets/spock-suprise.gif" height="256"><br> <img src="assets/luke-suprise.gif" height="256"><img src="assets/spock-suprise.gif" height="256"><br>
@ -299,6 +299,9 @@ docker run -it --gpus all -v $HOME/.cache/huggingface:/root/.cache/huggingface -
## ChangeLog ## ChangeLog
- perf: cli now has minimal overhead such that `aimg --help` runs in ~650ms instead of ~3400ms - perf: cli now has minimal overhead such that `aimg --help` runs in ~650ms instead of ~3400ms
- feature: `edit` and `imagine` commands now accept multiple images (which they will process separately). This allows
batch editing of images as requested in [#229](https://github.com/brycedrennan/imaginAIry/issues/229)
- refactor: move `--surprise-me` to its own subcommand `edit-demo`
**8.3.1** **8.3.1**
- fix: init-image-strength type - fix: init-image-strength type

@ -12,8 +12,8 @@ logger = logging.getLogger(__name__)
common_options = [ common_options = [
click.option( click.option(
"--negative-prompt", "--negative-prompt",
default=config.DEFAULT_NEGATIVE_PROMPT, default=None,
show_default=True, show_default=False,
help="Negative prompt. Things to try and exclude from images. Same negative prompt will be used for all images.", help="Negative prompt. Things to try and exclude from images. Same negative prompt will be used for all images.",
), ),
click.option( click.option(
@ -26,6 +26,7 @@ common_options = [
"--init-image", "--init-image",
metavar="PATH|URL", metavar="PATH|URL",
help="Starting image.", help="Starting image.",
multiple=True,
), ),
click.option( click.option(
"--init-image-strength", "--init-image-strength",
@ -395,27 +396,83 @@ def imagine_cmd(
) )
edit_options = common_options.copy() @aimg.command("edit-demo")
@click.argument("image_paths", metavar="PATH|URL", required=True, nargs=-1)
@click.option(
"--outdir",
default="./outputs",
show_default=True,
type=click.Path(),
help="Where to write results to.",
)
@click.option(
"-h",
"--height",
default=512,
show_default=True,
type=int,
help="Image height. Should be multiple of 8.",
)
@click.option(
"-w",
"--width",
default=512,
show_default=True,
type=int,
help="Image width. Should be multiple of 8.",
)
def edit_demo(image_paths, outdir, height, width):
from imaginairy.log_utils import configure_logging
from imaginairy.surprise_me import create_surprise_me_images
configure_logging()
for image_path in image_paths:
create_surprise_me_images(
image_path, outdir=outdir, make_gif=True, width=width, height=height
)
return
edit_options = common_options.copy()
remove_option(edit_options, "model_weights_path")
remove_option(edit_options, "init_image") remove_option(edit_options, "init_image")
remove_option(edit_options, "init_image_strength")
remove_option(edit_options, "prompt_strength")
remove_option(edit_options, "negative_prompt")
@aimg.command("edit") @aimg.command("edit")
@click.argument("init_image", metavar="PATH|URL", required=True, nargs=1) @click.argument("image_paths", metavar="PATH|URL", required=True, nargs=-1)
@click.argument("prompt_texts", nargs=-1)
@click.option( @click.option(
"--surprise-me", "--image-strength",
"surprise_me", default=1,
default=False, show_default=False,
is_flag=True, type=float,
help="make some fun edits to the provided image", help="Starting image strength. Between 0 and 1.",
) )
@add_options(common_options) @click.option("--prompt", "-p", required=True, multiple=True)
@click.option(
"--model-weights-path",
"--model",
help=f"Model to use. Should be one of {', '.join(config.MODEL_SHORT_NAMES)}, or a path to custom weights.",
show_default=True,
default="edit",
)
@click.option(
"--negative-prompt",
default=None,
show_default=False,
help="Negative prompt. Things to try and exclude from images. Same negative prompt will be used for all images. A default negative prompt is used if none is selected.",
)
@add_options(edit_options)
@click.pass_context @click.pass_context
def edit_image( # noqa def edit_image( # noqa
ctx, ctx,
init_image, image_paths,
prompt_texts, image_strength,
prompt,
negative_prompt, negative_prompt,
prompt_strength, prompt_strength,
outdir, outdir,
@ -447,41 +504,26 @@ def edit_image( # noqa
version, # noqa version, # noqa
make_gif, make_gif,
make_compare_gif, make_compare_gif,
surprise_me,
arg_schedules, arg_schedules,
make_compilation_animation, make_compilation_animation,
): ):
""" """
Edit an image via AI. Edit an image via AI.
Provide a path or URL to an image and directions on how to alter it. Provide paths or URLs to images and directions on how to alter them.
Example: aimg edit my-dog.jpg "make the dog red"
"""
from imaginairy.log_utils import configure_logging
from imaginairy.surprise_me import create_surprise_me_images
init_image_strength = 1
if surprise_me and prompt_texts:
raise ValueError("Cannot use surprise_me and prompt_texts together")
if surprise_me: Example: aimg edit --prompt "make the dog red" my-dog.jpg my-dog2.jpg
if quiet:
log_level = "ERROR"
configure_logging(log_level)
create_surprise_me_images(
init_image, outdir=outdir, make_gif=make_gif, width=width, height=height
)
return
Same as calling `aimg imagine --model edit --init-image my-dog.jpg --init-image-strength 1` except this command
can batch edit images.
"""
return _imagine_cmd( return _imagine_cmd(
ctx, ctx,
prompt_texts, prompt,
negative_prompt, negative_prompt,
prompt_strength, prompt_strength,
init_image, image_paths,
init_image_strength, image_strength,
outdir, outdir,
repeats, repeats,
height, height,
@ -582,15 +624,23 @@ def _imagine_cmd(
configure_logging(log_level) configure_logging(log_level)
total_image_count = len(prompt_texts) * repeats if isinstance(init_image, str):
init_images = [init_image]
else:
init_images = init_image
total_image_count = len(prompt_texts) * len(init_images) * repeats
logger.info( logger.info(
f"Received {len(prompt_texts)} prompt(s) and will repeat them {repeats} times to create {total_image_count} images." f"Received {len(prompt_texts)} prompt(s) and {len(init_images)} input image(s). Will repeat them {repeats} times to create {total_image_count} images."
) )
from imaginairy import ImaginePrompt, LazyLoadingImage, imagine_image_files from imaginairy import ImaginePrompt, LazyLoadingImage, imagine_image_files
if init_image and init_image.startswith("http"): new_init_images = []
init_image = LazyLoadingImage(url=init_image) for init_image in init_images:
if init_image and init_image.startswith("http"):
init_image = LazyLoadingImage(url=init_image)
new_init_images.append(init_image)
init_images = new_init_images
if mask_image and mask_image.startswith("http"): if mask_image and mask_image.startswith("http"):
mask_image = LazyLoadingImage(url=mask_image) mask_image = LazyLoadingImage(url=mask_image)
@ -622,38 +672,41 @@ def _imagine_cmd(
_tile_mode = "y" _tile_mode = "y"
else: else:
_tile_mode = "" _tile_mode = ""
for _init_image in init_images:
prompt = ImaginePrompt(
next(prompt_iterator),
negative_prompt=negative_prompt,
prompt_strength=prompt_strength,
init_image=_init_image,
init_image_strength=init_image_strength,
seed=seed,
sampler_type=sampler_type,
steps=steps,
height=height,
width=width,
mask_image=mask_image,
mask_prompt=mask_prompt,
mask_mode=mask_mode,
mask_modify_original=mask_modify_original,
outpaint=outpaint,
upscale=upscale,
fix_faces=fix_faces,
fix_faces_fidelity=fix_faces_fidelity,
tile_mode=_tile_mode,
model=model_weights_path,
model_config_path=model_config_path,
)
from imaginairy.prompt_schedules import (
parse_schedule_strs,
prompt_mutator,
)
prompt = ImaginePrompt( if arg_schedules:
next(prompt_iterator), schedules = parse_schedule_strs(arg_schedules)
negative_prompt=negative_prompt, for new_prompt in prompt_mutator(prompt, schedules):
prompt_strength=prompt_strength, prompts.append(new_prompt)
init_image=init_image, else:
init_image_strength=init_image_strength, prompts.append(prompt)
seed=seed,
sampler_type=sampler_type,
steps=steps,
height=height,
width=width,
mask_image=mask_image,
mask_prompt=mask_prompt,
mask_mode=mask_mode,
mask_modify_original=mask_modify_original,
outpaint=outpaint,
upscale=upscale,
fix_faces=fix_faces,
fix_faces_fidelity=fix_faces_fidelity,
tile_mode=_tile_mode,
model=model_weights_path,
model_config_path=model_config_path,
)
from imaginairy.prompt_schedules import parse_schedule_strs, prompt_mutator
if arg_schedules:
schedules = parse_schedule_strs(arg_schedules)
for new_prompt in prompt_mutator(prompt, schedules):
prompts.append(new_prompt)
else:
prompts.append(prompt)
filenames = imagine_image_files( filenames = imagine_image_files(
prompts, prompts,

Loading…
Cancel
Save