diff --git a/README.md b/README.md
index 48cd538..a1a1c78 100644
--- a/README.md
+++ b/README.md
@@ -61,6 +61,17 @@ with prompt-based masking.
+Want just quickly have some fun? Try `--suprise-me` to apply some pre-defined edits.
+```bash
+>> aimg edit --gif --suprise-me pearl_girl.jpg
+>> aimg edit --gif --suprise-me mona-lisa.jpg
+>> aimg edit --gif --suprise-me luke.jpg
+>> aimg edit --gif --suprise-me spock.jpg
+```
+
+
+
+
### Prompt Based Masking [by clipseg](https://github.com/timojl/clipseg)
Specify advanced text based masks using boolean logic and strength modifiers.
@@ -274,6 +285,8 @@ docker run -it --gpus all -v $HOME/.cache/huggingface:/root/.cache/huggingface -
**8.0.0**
- feature: 🎉 edit images with instructions alone!
+- feature: when editing an image add `--gif` to create a comparision gif
+- feature: `aimg edit --suprise-me --gif my-image.jpg` for some fun pre-programmed edits
- feature: prune-ckpt command also removes the non-ema weights
**7.6.0**
diff --git a/assets/gg-bridge-suprise.gif b/assets/gg-bridge-suprise.gif
new file mode 100644
index 0000000..849dcbe
Binary files /dev/null and b/assets/gg-bridge-suprise.gif differ
diff --git a/assets/gg-bridge.jpg b/assets/gg-bridge.jpg
new file mode 100644
index 0000000..94be687
Binary files /dev/null and b/assets/gg-bridge.jpg differ
diff --git a/assets/girl_with_a_pearl_earring_suprise.gif b/assets/girl_with_a_pearl_earring_suprise.gif
new file mode 100644
index 0000000..55f0913
Binary files /dev/null and b/assets/girl_with_a_pearl_earring_suprise.gif differ
diff --git a/assets/luke-suprise.gif b/assets/luke-suprise.gif
new file mode 100644
index 0000000..302e676
Binary files /dev/null and b/assets/luke-suprise.gif differ
diff --git a/assets/luke.jpg b/assets/luke.jpg
new file mode 100644
index 0000000..33da95c
Binary files /dev/null and b/assets/luke.jpg differ
diff --git a/assets/mona-lisa-suprise.gif b/assets/mona-lisa-suprise.gif
new file mode 100644
index 0000000..209452d
Binary files /dev/null and b/assets/mona-lisa-suprise.gif differ
diff --git a/assets/shire-suprise.gif b/assets/shire-suprise.gif
new file mode 100644
index 0000000..512294b
Binary files /dev/null and b/assets/shire-suprise.gif differ
diff --git a/assets/shire.jpg b/assets/shire.jpg
new file mode 100644
index 0000000..0e407c1
Binary files /dev/null and b/assets/shire.jpg differ
diff --git a/assets/spock-suprise.gif b/assets/spock-suprise.gif
new file mode 100644
index 0000000..e41ec4f
Binary files /dev/null and b/assets/spock-suprise.gif differ
diff --git a/assets/spock.jpg b/assets/spock.jpg
new file mode 100644
index 0000000..7e676b8
Binary files /dev/null and b/assets/spock.jpg differ
diff --git a/imaginairy/api.py b/imaginairy/api.py
index 3a0b335..68e684f 100755
--- a/imaginairy/api.py
+++ b/imaginairy/api.py
@@ -13,7 +13,11 @@ from imaginairy.enhancers.clip_masking import get_img_mask
from imaginairy.enhancers.describe_image_blip import generate_caption
from imaginairy.enhancers.face_restoration_codeformer import enhance_faces
from imaginairy.enhancers.upscale_realesrgan import upscale_image
-from imaginairy.img_utils import pillow_fit_image_within, pillow_img_to_torch_image
+from imaginairy.img_utils import (
+ make_gif_image,
+ pillow_fit_image_within,
+ pillow_img_to_torch_image,
+)
from imaginairy.log_utils import (
ImageLoggingContext,
log_conditioning,
@@ -55,6 +59,8 @@ def imagine_image_files(
record_step_images=False,
output_file_extension="jpg",
print_caption=False,
+ make_comparison_gif=False,
+ return_filename_type="generated",
):
generated_imgs_path = os.path.join(outdir, "generated")
os.makedirs(generated_imgs_path, exist_ok=True)
@@ -74,6 +80,7 @@ def imagine_image_files(
draw.text((10, 10), str(description))
img.save(destination)
+ result_filenames = []
for result in imagine(
prompts,
precision=precision,
@@ -97,9 +104,25 @@ def imagine_image_files(
)
result.save(filepath, image_type=image_type)
logger.info(f"🖼 [{image_type}] saved to: {filepath}")
+ if image_type == return_filename_type:
+ result_filenames.append(filepath)
+ if make_comparison_gif and prompt.init_image:
+ subpath = os.path.join(outdir, "gif")
+ os.makedirs(subpath, exist_ok=True)
+ filepath = os.path.join(subpath, f"{basefilename}.gif")
+ resized_init_image = pillow_fit_image_within(
+ prompt.init_image, prompt.width, prompt.height
+ )
+ make_gif_image(
+ filepath,
+ imgs=[result.images["generated"], resized_init_image],
+ duration=1750,
+ )
base_count += 1
del result
+ return result_filenames
+
def imagine(
prompts,
diff --git a/imaginairy/cmds.py b/imaginairy/cmds.py
index 2701d55..07f50de 100644
--- a/imaginairy/cmds.py
+++ b/imaginairy/cmds.py
@@ -11,6 +11,7 @@ from imaginairy.enhancers.prompt_expansion import expand_prompts
from imaginairy.log_utils import configure_logging
from imaginairy.samplers import SAMPLER_TYPE_OPTIONS
from imaginairy.schema import ImaginePrompt
+from imaginairy.suprise_me import create_suprise_me_images
from imaginairy.train import train_diffusion_model
from imaginairy.training_tools.image_prep import (
create_class_images,
@@ -220,6 +221,9 @@ logger = logging.getLogger(__name__)
is_flag=True,
help="Print the version and exit.",
)
+@click.option(
+ "--gif", "make_gif", default=False, is_flag=True, help="Generate a gif of the edit."
+)
@click.pass_context
def imagine_cmd(
ctx,
@@ -255,6 +259,7 @@ def imagine_cmd(
model_config_path,
prompt_library_path,
version, # noqa
+ make_gif,
):
"""Have the AI generate images. alias:imagine."""
return _imagine_cmd(
@@ -291,6 +296,7 @@ def imagine_cmd(
model_config_path,
prompt_library_path,
version, # noqa
+ make_gif
)
@@ -487,8 +493,22 @@ def imagine_cmd(
is_flag=True,
help="Print the version and exit.",
)
+@click.option(
+ "--gif",
+ "make_gif",
+ default=False,
+ is_flag=True,
+ help="Generate a gif comparing the original image to the modified one.",
+)
+@click.option(
+ "--suprise-me",
+ "suprise_me",
+ default=False,
+ is_flag=True,
+ help="make some fun edits to the provided image",
+)
@click.pass_context
-def edit_image(
+def edit_image( # noqa
ctx,
init_image,
prompt_texts,
@@ -521,8 +541,21 @@ def edit_image(
model_config_path,
prompt_library_path,
version, # noqa
+ make_gif,
+ suprise_me,
):
init_image_strength = 1
+ if suprise_me and prompt_texts:
+ raise ValueError("Cannot use suprise_me and prompt_texts together")
+
+ if suprise_me:
+ if quiet:
+ log_level = "ERROR"
+ configure_logging(log_level)
+ create_suprise_me_images(init_image, outdir=outdir, make_gif=make_gif)
+
+ return
+
return _imagine_cmd(
ctx,
prompt_texts,
@@ -557,6 +590,7 @@ def edit_image(
model_config_path,
prompt_library_path,
version, # noqa
+ make_gif,
)
@@ -593,7 +627,8 @@ def _imagine_cmd(
model_weights_path,
model_config_path,
prompt_library_path,
- version, # noqa
+ version=False, # noqa
+ make_gif=False,
):
"""Have the AI generate images. alias:imagine."""
if ctx.invoked_subcommand is not None:
@@ -670,6 +705,7 @@ def _imagine_cmd(
output_file_extension="jpg",
print_caption=caption,
precision=precision,
+ make_comparison_gif=make_gif,
)
diff --git a/data/DejaVuSans.ttf b/imaginairy/data/DejaVuSans.ttf
similarity index 100%
rename from data/DejaVuSans.ttf
rename to imaginairy/data/DejaVuSans.ttf
diff --git a/imaginairy/img_utils.py b/imaginairy/img_utils.py
index 165a0c7..9cb9bcb 100644
--- a/imaginairy/img_utils.py
+++ b/imaginairy/img_utils.py
@@ -70,3 +70,15 @@ def pillow_img_to_model_latent(model, img, batch_size=1, half=True):
model.encode_first_stage(init_image.half())
)
return model.get_first_stage_encoding(model.encode_first_stage(init_image))
+
+
+def make_gif_image(filepath, imgs, duration=1000, loop=0):
+
+ imgs[0].save(
+ filepath,
+ save_all=True,
+ append_images=imgs[1:],
+ duration=duration,
+ loop=loop,
+ optimize=False,
+ )
diff --git a/imaginairy/modules/diffusion/ddpm.py b/imaginairy/modules/diffusion/ddpm.py
index 18f0578..340be2a 100644
--- a/imaginairy/modules/diffusion/ddpm.py
+++ b/imaginairy/modules/diffusion/ddpm.py
@@ -32,6 +32,7 @@ from imaginairy.modules.diffusion.util import (
)
from imaginairy.modules.distributions import DiagonalGaussianDistribution
from imaginairy.modules.ema import LitEma
+from imaginairy.paths import PKG_ROOT
from imaginairy.samplers.kdiff import DPMPP2MSampler
from imaginairy.utils import instantiate_from_config
@@ -47,7 +48,7 @@ def log_txt_as_img(wh, xc, size=10):
for bi in range(b):
txt = Image.new("RGB", wh, color="white")
draw = ImageDraw.Draw(txt)
- font = ImageFont.truetype("data/DejaVuSans.ttf", size=size)
+ font = ImageFont.truetype(f"{PKG_ROOT}/data/DejaVuSans.ttf", size=size)
nc = int(40 * (wh[0] / 256))
lines = "\n".join(
xc[bi][start : start + nc] for start in range(0, len(xc[bi]), nc)
diff --git a/imaginairy/suprise_me.py b/imaginairy/suprise_me.py
new file mode 100644
index 0000000..79dc26f
--- /dev/null
+++ b/imaginairy/suprise_me.py
@@ -0,0 +1,128 @@
+"""
+
+
+aimg.
+"""
+
+import os.path
+
+from PIL import ImageDraw, ImageFont
+
+from imaginairy import ImaginePrompt, LazyLoadingImage, imagine_image_files
+from imaginairy.enhancers.facecrop import detect_faces
+from imaginairy.img_utils import make_gif_image, pillow_fit_image_within
+from imaginairy.paths import PKG_ROOT
+
+generic_prompts = [
+ ("make it anime style", 18, ""),
+ ("make it pen and ink style", 20, ""),
+ ("make it a thomas kinkade painting", 20, ""),
+ ("make it pixar style", 20, ""),
+ ("make it look like a marble statue", 15, ""),
+ ("make it look like a golden statue", 15, ""),
+ ("make it look like a snowstorm", 20, ""),
+ ("make it night", 15, ""),
+ ("make it a sunny day", 15, ""),
+ ("put fireworks in the background", 15, ""),
+ ("make it in a forest", 15, ""),
+]
+
+person_prompts = [
+ ("make the person close their eyes", 10, ""),
+ ("make the person wear clown makeup", 10, ""),
+ ("make the person a cyborg", 14, ""),
+ ("make the person wear shiny metal clothes", 14, ""),
+ ("make the person wear a tie-dye shirt", 7.5, ""),
+ ("make the person wear a suit", 7.5, ""),
+ ("make the person bald", 7.5, ""),
+ ("change the hair to pink", 7.5, ""),
+ (
+ "make it a color professional photo headshot. Canon EOS, sharp focus",
+ 10,
+ "old, ugly",
+ ),
+ ("make the face smiling", 5, ""),
+ # ("make the person sad", 20, ""),
+ # ("make the person angry", 20, ""),
+ ("make the person look like a celebrity", 10, ""),
+ ("make the person younger", 10, ""),
+ ("make the person older", 10, ""),
+ ("make the person a disney cartoon character", 7.5, ""),
+]
+
+
+def suprise_me_prompts(img, person=None):
+ prompts = []
+ if isinstance(img, str):
+ if img.startswith("http"):
+ img = LazyLoadingImage(url=img)
+ else:
+ img = LazyLoadingImage(filepath=img)
+
+ if person is None:
+ person = bool(detect_faces(img))
+
+ if person:
+ for prompt_text, strength, neg_prompt_text in person_prompts:
+ prompts.append(
+ ImaginePrompt(
+ prompt_text,
+ init_image=img,
+ prompt_strength=strength,
+ negative_prompt=neg_prompt_text,
+ model="edit",
+ steps=20,
+ )
+ )
+
+ for prompt_text, strength, neg_prompt_text in generic_prompts:
+ prompts.append(
+ ImaginePrompt(
+ prompt_text,
+ init_image=img,
+ prompt_strength=strength,
+ negative_prompt=neg_prompt_text,
+ model="edit",
+ steps=20,
+ )
+ )
+
+ return prompts
+
+
+def create_suprise_me_images(img, outdir, person=None, make_gif=True):
+ if isinstance(img, str):
+ if img.startswith("http"):
+ img = LazyLoadingImage(url=img)
+ else:
+ img = LazyLoadingImage(filepath=img)
+ prompts = suprise_me_prompts(img, person=person)
+ generated_filenames = imagine_image_files(
+ prompts,
+ outdir=outdir,
+ record_step_images=False,
+ output_file_extension="jpg",
+ print_caption=False,
+ make_comparison_gif=make_gif,
+ )
+ if make_gif:
+ imgs_path = os.path.join(outdir, "compilations")
+ os.makedirs(imgs_path, exist_ok=True)
+ base_count = len(os.listdir(imgs_path))
+ new_filename = os.path.join(imgs_path, f"suprise_me_{base_count:03d}.gif")
+ simg = pillow_fit_image_within(img, prompts[0].width, prompts[0].height)
+ gif_imgs = [simg]
+ for prompt, filename in zip(prompts, generated_filenames):
+ gen_img = LazyLoadingImage(filepath=filename)
+ draw = ImageDraw.Draw(gen_img)
+
+ font_size = 16
+ font = ImageFont.truetype(f"{PKG_ROOT}/data/DejaVuSans.ttf", font_size)
+
+ x = 15
+ y = 485
+
+ draw.text((x, y), prompt.prompt_text, font=font, fill=(255, 255, 255))
+ gif_imgs.append(gen_img)
+
+ make_gif_image(new_filename, gif_imgs)
diff --git a/setup.py b/setup.py
index f61d597..32428d6 100644
--- a/setup.py
+++ b/setup.py
@@ -25,6 +25,7 @@ setup(
package_data={
"imaginairy": [
"configs/*.yaml",
+ "data/*.*",
"enhancers/phraselists/*.txt",
"vendored/clip/*.txt.gz",
"vendored/clipseg/*.pth",