diff --git a/Makefile b/Makefile index 4ceef51b..37fdf8c1 100644 --- a/Makefile +++ b/Makefile @@ -88,6 +88,11 @@ require_pyenv: echo -e "\033[0;32m ✔️ pyenv-virtualenv installed\033[0m";\ fi +.PHONY: docs + +docs: + mkdocs serve + update-stablestudio: @echo "Updating stablestudio" cd ../imaginAIry-StableStudio && \ diff --git a/docs/assets/000005_1_ddim50_PS7.5_wide_shot_of_sun_setting_on_a_green_valley_[generated].jpg b/docs/assets/000005_1_ddim50_PS7.5_wide_shot_of_sun_setting_on_a_green_valley_[generated].jpg new file mode 100644 index 00000000..14c77004 Binary files /dev/null and b/docs/assets/000005_1_ddim50_PS7.5_wide_shot_of_sun_setting_on_a_green_valley_[generated].jpg differ diff --git a/docs/assets/000032_337692011_PLMS40_PS7.5_a_photo_of_a_dog.jpg b/docs/assets/000032_337692011_PLMS40_PS7.5_a_photo_of_a_dog.jpg new file mode 100644 index 00000000..b8b4ca5d Binary files /dev/null and b/docs/assets/000032_337692011_PLMS40_PS7.5_a_photo_of_a_dog.jpg differ diff --git a/docs/assets/000078_260972468_PLMS40_PS7.5_portrait_photo_of_a_freckled_woman.jpg b/docs/assets/000078_260972468_PLMS40_PS7.5_portrait_photo_of_a_freckled_woman.jpg new file mode 100644 index 00000000..5af579c5 Binary files /dev/null and b/docs/assets/000078_260972468_PLMS40_PS7.5_portrait_photo_of_a_freckled_woman.jpg differ diff --git a/docs/assets/013986_1_kdpmpp2m59_PS7.5_a_bluejay_[generated].jpg b/docs/assets/013986_1_kdpmpp2m59_PS7.5_a_bluejay_[generated].jpg new file mode 100644 index 00000000..99ffc7b4 Binary files /dev/null and b/docs/assets/013986_1_kdpmpp2m59_PS7.5_a_bluejay_[generated].jpg differ diff --git a/docs/assets/026882_1_ddim50_PS7.5_a_scenic_landscape_[generated].jpg b/docs/assets/026882_1_ddim50_PS7.5_a_scenic_landscape_[generated].jpg new file mode 100644 index 00000000..dd553542 Binary files /dev/null and b/docs/assets/026882_1_ddim50_PS7.5_a_scenic_landscape_[generated].jpg differ diff --git a/docs/assets/026884_1_ddim50_PS7.5_photo_of_a_dog_[generated].jpg b/docs/assets/026884_1_ddim50_PS7.5_photo_of_a_dog_[generated].jpg new file mode 100644 index 00000000..dfa1e5a2 Binary files /dev/null and b/docs/assets/026884_1_ddim50_PS7.5_photo_of_a_dog_[generated].jpg differ diff --git a/docs/assets/026885_1_ddim50_PS7.5_girl_with_a_pearl_earring_[generated].jpg b/docs/assets/026885_1_ddim50_PS7.5_girl_with_a_pearl_earring_[generated].jpg new file mode 100644 index 00000000..ce42152b Binary files /dev/null and b/docs/assets/026885_1_ddim50_PS7.5_girl_with_a_pearl_earring_[generated].jpg differ diff --git a/docs/assets/026890_1_ddim50_PS7.5_photo_of_a_bowl_of_fruit._still_life_[generated].jpg b/docs/assets/026890_1_ddim50_PS7.5_photo_of_a_bowl_of_fruit._still_life_[generated].jpg new file mode 100644 index 00000000..90f6bd53 Binary files /dev/null and b/docs/assets/026890_1_ddim50_PS7.5_photo_of_a_bowl_of_fruit._still_life_[generated].jpg differ diff --git a/docs/assets/026891_1_ddim50_PS7.5_close-up_photo_of_a_bluejay_[generated].jpg b/docs/assets/026891_1_ddim50_PS7.5_close-up_photo_of_a_bluejay_[generated].jpg new file mode 100644 index 00000000..be8b0de0 Binary files /dev/null and b/docs/assets/026891_1_ddim50_PS7.5_close-up_photo_of_a_bluejay_[generated].jpg differ diff --git a/docs/assets/026893_1_ddim50_PS7.5_macro_photo_of_a_flower_[generated].jpg b/docs/assets/026893_1_ddim50_PS7.5_macro_photo_of_a_flower_[generated].jpg new file mode 100644 index 00000000..0a92f80e Binary files /dev/null and b/docs/assets/026893_1_ddim50_PS7.5_macro_photo_of_a_flower_[generated].jpg differ diff --git a/docs/assets/bird-normal-generated.jpg b/docs/assets/bird-normal-generated.jpg new file mode 100644 index 00000000..8d9ecd10 Binary files /dev/null and b/docs/assets/bird-normal-generated.jpg differ diff --git a/docs/assets/bird-normal.jpg b/docs/assets/bird-normal.jpg new file mode 100644 index 00000000..07434e6b Binary files /dev/null and b/docs/assets/bird-normal.jpg differ diff --git a/docs/assets/dog-hed-boundary-dalmation.jpg b/docs/assets/dog-hed-boundary-dalmation.jpg new file mode 100644 index 00000000..3f46c924 Binary files /dev/null and b/docs/assets/dog-hed-boundary-dalmation.jpg differ diff --git a/docs/assets/dog-hed-boundary.jpg b/docs/assets/dog-hed-boundary.jpg new file mode 100644 index 00000000..a9efddc6 Binary files /dev/null and b/docs/assets/dog-hed-boundary.jpg differ diff --git a/docs/assets/fancy-living-depth-generated.jpg b/docs/assets/fancy-living-depth-generated.jpg new file mode 100644 index 00000000..19261641 Binary files /dev/null and b/docs/assets/fancy-living-depth-generated.jpg differ diff --git a/docs/assets/fancy-living-depth.jpg b/docs/assets/fancy-living-depth.jpg new file mode 100644 index 00000000..34156418 Binary files /dev/null and b/docs/assets/fancy-living-depth.jpg differ diff --git a/docs/assets/fancy-living.jpg b/docs/assets/fancy-living.jpg new file mode 100644 index 00000000..7a04008d Binary files /dev/null and b/docs/assets/fancy-living.jpg differ diff --git a/docs/assets/girl_with_a_pearl_earring.jpg b/docs/assets/girl_with_a_pearl_earring.jpg new file mode 100644 index 00000000..009d1d6f Binary files /dev/null and b/docs/assets/girl_with_a_pearl_earring.jpg differ diff --git a/docs/assets/indiana-pose-polar-bear.jpg b/docs/assets/indiana-pose-polar-bear.jpg new file mode 100644 index 00000000..6ef7d248 Binary files /dev/null and b/docs/assets/indiana-pose-polar-bear.jpg differ diff --git a/docs/assets/indiana-pose.jpg b/docs/assets/indiana-pose.jpg new file mode 100644 index 00000000..510f4671 Binary files /dev/null and b/docs/assets/indiana-pose.jpg differ diff --git a/docs/assets/indiana.jpg b/docs/assets/indiana.jpg new file mode 100644 index 00000000..56c10fc1 Binary files /dev/null and b/docs/assets/indiana.jpg differ diff --git a/docs/assets/lena-canny-generated.jpg b/docs/assets/lena-canny-generated.jpg new file mode 100644 index 00000000..884239e0 Binary files /dev/null and b/docs/assets/lena-canny-generated.jpg differ diff --git a/docs/assets/lena-canny.jpg b/docs/assets/lena-canny.jpg new file mode 100644 index 00000000..13e4767e Binary files /dev/null and b/docs/assets/lena-canny.jpg differ diff --git a/docs/assets/lena.png b/docs/assets/lena.png new file mode 100644 index 00000000..59ef68aa Binary files /dev/null and b/docs/assets/lena.png differ diff --git a/docs/assets/pearl-gray.jpg b/docs/assets/pearl-gray.jpg new file mode 100644 index 00000000..bcb904bb Binary files /dev/null and b/docs/assets/pearl-gray.jpg differ diff --git a/docs/assets/pearl-recolor-a.jpg b/docs/assets/pearl-recolor-a.jpg new file mode 100644 index 00000000..b8a3ab52 Binary files /dev/null and b/docs/assets/pearl-recolor-a.jpg differ diff --git a/docs/assets/pearl_anime_019537_521829407_kdpmpp2m30_PS9.0_img2img-0.01_make_it_anime.jpg b/docs/assets/pearl_anime_019537_521829407_kdpmpp2m30_PS9.0_img2img-0.01_make_it_anime.jpg new file mode 100644 index 00000000..37a97c2d Binary files /dev/null and b/docs/assets/pearl_anime_019537_521829407_kdpmpp2m30_PS9.0_img2img-0.01_make_it_anime.jpg differ diff --git a/docs/assets/pearl_beach_019561_862735879_kdpmpp2m30_PS7.0_img2img-0.01_make_it_at_the_beach.jpg b/docs/assets/pearl_beach_019561_862735879_kdpmpp2m30_PS7.0_img2img-0.01_make_it_at_the_beach.jpg new file mode 100644 index 00000000..0775adb2 Binary files /dev/null and b/docs/assets/pearl_beach_019561_862735879_kdpmpp2m30_PS7.0_img2img-0.01_make_it_at_the_beach.jpg differ diff --git a/docs/assets/pearl_shuffle_019331_1_kdpmpp2m15_PS7.5_img2img-0.0_a_clown.jpg b/docs/assets/pearl_shuffle_019331_1_kdpmpp2m15_PS7.5_img2img-0.0_a_clown.jpg new file mode 100644 index 00000000..82de8ee3 Binary files /dev/null and b/docs/assets/pearl_shuffle_019331_1_kdpmpp2m15_PS7.5_img2img-0.0_a_clown.jpg differ diff --git a/docs/assets/pearl_shuffle_clown_019331_1_kdpmpp2m15_PS7.5_img2img-0.0_a_clown.jpg b/docs/assets/pearl_shuffle_clown_019331_1_kdpmpp2m15_PS7.5_img2img-0.0_a_clown.jpg new file mode 100644 index 00000000..b73c0ac2 Binary files /dev/null and b/docs/assets/pearl_shuffle_clown_019331_1_kdpmpp2m15_PS7.5_img2img-0.0_a_clown.jpg differ diff --git a/docs/assets/svd-rocket.gif b/docs/assets/svd-rocket.gif new file mode 100644 index 00000000..e68b8ef8 Binary files /dev/null and b/docs/assets/svd-rocket.gif differ diff --git a/docs/assets/wishbone_headshot_badscale.jpg b/docs/assets/wishbone_headshot_badscale.jpg new file mode 100644 index 00000000..7323223e Binary files /dev/null and b/docs/assets/wishbone_headshot_badscale.jpg differ diff --git a/docs/assets/wishbone_headshot_details.jpg b/docs/assets/wishbone_headshot_details.jpg new file mode 100644 index 00000000..59a55426 Binary files /dev/null and b/docs/assets/wishbone_headshot_details.jpg differ diff --git a/docs/docs/CLI/colorize.md b/docs/docs/CLI/colorize.md new file mode 100644 index 00000000..4b79de63 --- /dev/null +++ b/docs/docs/CLI/colorize.md @@ -0,0 +1,4 @@ +::: mkdocs-click + :module: imaginairy.cli.colorize + :command: colorize_cmd + :prog_name: colorize \ No newline at end of file diff --git a/docs/docs/CLI/describe.md b/docs/docs/CLI/describe.md new file mode 100644 index 00000000..bc18aa2a --- /dev/null +++ b/docs/docs/CLI/describe.md @@ -0,0 +1,4 @@ +::: mkdocs-click + :module: imaginairy.cli.describe + :command: describe_cmd + :prog_name: describe \ No newline at end of file diff --git a/docs/docs/CLI/edit.md b/docs/docs/CLI/edit.md new file mode 100644 index 00000000..db7ed420 --- /dev/null +++ b/docs/docs/CLI/edit.md @@ -0,0 +1,4 @@ +::: mkdocs-click + :module: imaginairy.cli.edit + :command: edit_cmd + :prog_name: edit \ No newline at end of file diff --git a/docs/docs/CLI/imagine.md b/docs/docs/CLI/imagine.md new file mode 100644 index 00000000..02c76a09 --- /dev/null +++ b/docs/docs/CLI/imagine.md @@ -0,0 +1,3 @@ +::: mkdocs-click + :module: imaginairy.cli.imagine + :command: imagine_cmd \ No newline at end of file diff --git a/docs/docs/CLI/upscale.md b/docs/docs/CLI/upscale.md new file mode 100644 index 00000000..05078c22 --- /dev/null +++ b/docs/docs/CLI/upscale.md @@ -0,0 +1,4 @@ +::: mkdocs-click + :module: imaginairy.cli.upscale + :command: upscale_cmd + :prog_name: upscale \ No newline at end of file diff --git a/docs/docs/CLI/videogen.md b/docs/docs/CLI/videogen.md new file mode 100644 index 00000000..3b233536 --- /dev/null +++ b/docs/docs/CLI/videogen.md @@ -0,0 +1,4 @@ +::: mkdocs-click + :module: imaginairy.cli.videogen + :command: videogen_cmd + :prog_name: videogen \ No newline at end of file diff --git a/docs/docs/Python/ControlInput.md b/docs/docs/Python/ControlInput.md new file mode 100644 index 00000000..19a400ba --- /dev/null +++ b/docs/docs/Python/ControlInput.md @@ -0,0 +1,2 @@ + +::: imaginairy.schema.ControlInput diff --git a/docs/docs/Python/ImaginePrompt.md b/docs/docs/Python/ImaginePrompt.md new file mode 100644 index 00000000..1c52a1ba --- /dev/null +++ b/docs/docs/Python/ImaginePrompt.md @@ -0,0 +1,2 @@ + +::: imaginairy.schema.ImaginePrompt diff --git a/docs/docs/Python/LazyLoadingImage.md b/docs/docs/Python/LazyLoadingImage.md new file mode 100644 index 00000000..f60c4497 --- /dev/null +++ b/docs/docs/Python/LazyLoadingImage.md @@ -0,0 +1,2 @@ + +::: imaginairy.schema.LazyLoadingImage diff --git a/docs/docs/Python/WeightedPrompt.md b/docs/docs/Python/WeightedPrompt.md new file mode 100644 index 00000000..2c4deff3 --- /dev/null +++ b/docs/docs/Python/WeightedPrompt.md @@ -0,0 +1,2 @@ + +::: imaginairy.schema.WeightedPrompt diff --git a/docs/docs/Python/colorize-img.md b/docs/docs/Python/colorize-img.md new file mode 100644 index 00000000..714a3473 --- /dev/null +++ b/docs/docs/Python/colorize-img.md @@ -0,0 +1,2 @@ + +::: imaginairy.api.colorize.colorize_img diff --git a/docs/docs/Python/generate-video.md b/docs/docs/Python/generate-video.md new file mode 100644 index 00000000..c5de8490 --- /dev/null +++ b/docs/docs/Python/generate-video.md @@ -0,0 +1,2 @@ + +::: imaginairy.api.video_sample.generate_video diff --git a/docs/docs/Python/imagine-image-files.md b/docs/docs/Python/imagine-image-files.md new file mode 100644 index 00000000..71fffae1 --- /dev/null +++ b/docs/docs/Python/imagine-image-files.md @@ -0,0 +1,3 @@ + + +::: imaginairy.api.generate.imagine_image_files diff --git a/docs/docs/Python/imagine.md b/docs/docs/Python/imagine.md new file mode 100644 index 00000000..c13f6382 --- /dev/null +++ b/docs/docs/Python/imagine.md @@ -0,0 +1,2 @@ + +::: imaginairy.api.generate.imagine diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..026e319d --- /dev/null +++ b/docs/index.md @@ -0,0 +1,324 @@ + +#ImaginAIry 🤖🧠 +**Pythonic AI generation of images and videos** + +[![Downloads](https://pepy.tech/badge/imaginairy)](https://pepy.tech/project/imaginairy) +[![PyPI Version](https://img.shields.io/pypi/v/imaginairy.svg)](https://pypi.org/project/imaginairy/) +[![MIT License](https://img.shields.io/badge/license-MIT-green)](https://github.com/brycedrennan/imaginAIry/blob/master/LICENSE/) +[![Discord Community](https://flat.badgen.net/discord/members/FdD7ut3YjW)](https://discord.gg/FdD7ut3YjW) + +

+ + + + + + +

+ +## Features + +- **Image Generation**: Create with SDXL, Openjourney, OpenDalle, and many others. +- **Stable Video Diffusion**: Turn images into videos. +- **Image Manipulation with ControlNet**: Keep the pose, but make the person a bear, and more. +--- + +## Installation + +```bash +# on macOS, make sure rust is installed first +# be sure to use Python 3.10, Python 3.11 is not supported at the moment +pip install imaginairy + +``` + +--- + + +## Image Generation + +=== "CLI" + ```bash + aimg imagine --seed 1 --model sd-xl "wide shot of sun setting on a green valley" + ``` + +=== "Python" + ``` py + from imaginairy.api.generate import imagine + from imaginairy.schema import ImaginePrompt + + prompt = ImaginePrompt(prompt="wide shot of sun setting on a green valley", seed=1, model_weights="sd-xl") + + result = next(imagine(prompts=prompt)) + result.img.save("sun_set_green_valley.png") + ``` + +portrait photo of a freckled woman + + +--- + + +## Stable Video Diffusion + +=== "CLI" + ```bash + aimg videogen --start-image assets/rocket-wide.png + ``` + +=== "Python" + ``` py + from imaginairy.api.video_sample import generate_video + + generate_video(input_path="assets/rocket-wide.png") + + ``` +portrait photo of a freckled woman + +## Image Structure Control [by ControlNet](https://github.com/lllyasviel/ControlNet) +Generate images guided by body poses, depth maps, canny edges, hed boundaries, or normal maps. + +#### Openpose Control + +=== "CLI" + ```bash + imagine --control-image assets/indiana.jpg --control-mode openpose --caption-text openpose "photo of a polar bear" + ``` + +=== "Python" + ``` py + from imaginairy.api.generate import imagine + from imaginairy.schema import ImaginePrompt, ControlInput, LazyLoadingImage + + image = LazyLoadingImage(filepath="assets/indiana.jpg") + control_mode = ControlInput(mode="openpose", image=image) + prompt = ImaginePrompt(prompt="photo of a polar bear", control_inputs=[control_mode], seed=1) + + result = next(imagine(prompts=prompt)) + result.img.save("assets/indiana-pose-polar-bear.jpg") + ``` + +

+ + + +

+ +#### Canny Edge Control +=== "CLI" + + ```bash + imagine --control-image assets/lena.png --control-mode canny "photo of a woman with a hat looking at the camera" + ``` + +=== "Python" + ``` py + from imaginairy.api.generate import imagine + from imaginairy.schema import ImaginePrompt, ControlInput, LazyLoadingImage + + image = LazyLoadingImage(filepath="assets/lena.png") + control_mode = ControlInput(mode="canny", image=image) + prompt = ImaginePrompt(prompt="photo of a woman with a hat looking at the camera", control_inputs=[control_mode], seed=1) + + result = next(imagine(prompts=prompt)) + result.img.save("assets/lena-canny-generated.jpg") + ``` + + +

+ + + +

+ +#### HED Boundary Control + +=== "CLI" + ```bash + imagine --control-image dog.jpg --control-mode hed "photo of a dalmation" + ``` + +=== "Python" + ``` py + from imaginairy.api.generate import imagine + from imaginairy.schema import ImaginePrompt, ControlInput, LazyLoadingImage + + image = LazyLoadingImage(filepath="assets/000032_337692011_PLMS40_PS7.5_a_photo_of_a_dog.jpg") + control_mode = ControlInput(mode="hed", image=image) + prompt = ImaginePrompt(prompt="photo of a dalmation", control_inputs=[control_mode], seed=1) + + result = next(imagine(prompts=prompt)) + result.img.save("assets/dog-hed-boundary-dalmation.jpg") + ``` + +

+ + + +

+ +#### Depth Map Control +=== "CLI" + ```bash + imagine --control-image fancy-living.jpg --control-mode depth "a modern living room" + ``` + +=== "Python" + ``` py + from imaginairy.api.generate import imagine + from imaginairy.schema import ImaginePrompt, ControlInput, LazyLoadingImage + + image = LazyLoadingImage(filepath="assets/fancy-living.jpg") + control_mode = ControlInput(mode="depth", image=image) + prompt = ImaginePrompt(prompt="a modern living room", control_inputs=[control_mode], seed=1) + + result = next(imagine(prompts=prompt)) + result.img.save("assets/fancy-living-depth-generated.jpg") + ``` + +

+ + + +

+ +#### Normal Map Control +=== "CLI" + ```bash + imagine --control-image bird.jpg --control-mode normal "a bird" + ``` + +=== "Python" + ``` py + from imaginairy.api.generate import imagine + from imaginairy.schema import ImaginePrompt, ControlInput, LazyLoadingImage + + image = LazyLoadingImage(filepath="assets/013986_1_kdpmpp2m59_PS7.5_a_bluejay_[generated].jpg") + control_mode = ControlInput(mode="normal", image=image) + prompt = ImaginePrompt(prompt="a bird", control_inputs=[control_mode], seed=1) + + result = next(imagine(prompts=prompt)) + result.img.save("assets/bird-normal-generated.jpg") + ``` + +

+ + + +

+ +#### Image Shuffle Control + +Generates the image based on elements of the control image. Kind of similar to style transfer. +=== "CLI" + ```bash + imagine --control-image pearl-girl.jpg --control-mode shuffle "a clown" + ``` + +=== "Python" + ``` py + from imaginairy.api.generate import imagine + from imaginairy.schema import ImaginePrompt, ControlInput, LazyLoadingImage + + image = LazyLoadingImage(filepath="assets/girl_with_a_pearl_earring.jpg") + control_mode = ControlInput(mode="shuffle", image=image) + prompt = ImaginePrompt(prompt="a clown", control_inputs=[control_mode], seed=1) + + result = next(imagine(prompts=prompt)) + result.img.save("assets/pearl_shuffle_clown_019331_1_kdpmpp2m15_PS7.5_img2img-0.0_a_clown.jpg") + ``` + +The middle image is the "shuffled" input image +

+ + + +

+ +#### Editing Instructions Control + +Similar to instructPix2Pix (below) but works with any SD 1.5 based model. +=== "CLI" + ```bash + imagine --control-image pearl-girl.jpg --control-mode edit --init-image-strength 0.01 --steps 30 --negative-prompt "" --model openjourney-v2 "make it anime" "make it at the beach" + ``` + +=== "Python" + ``` py + from imaginairy.api.generate import imagine + from imaginairy.schema import ImaginePrompt, ControlInput, LazyLoadingImage + + image = LazyLoadingImage(filepath="assets/girl_with_a_pearl_earring.jpg") + control_mode = ControlInput(mode="edit", image=image) + + prompts = [ImaginePrompt(prompt="make it anime", control_inputs=[control_mode], init_image_strength=0.01, steps=30, negative_prompt="", model_weights="openjourney-v2"), + ImaginePrompt(prompt="make it at the beach", control_inputs=[control_mode], init_image_strength=0.01, steps=30, negative_prompt="", model_weights="openjourney-v2")] + + imagine_iterator = imagine(prompts=prompts) + + result = next(imagine_iterator) + result.img.save("assets/pearl_anime_019537_521829407_kdpmpp2m30_PS9.0_img2img-0.01_make_it_anime.jpg") + + result = next(imagine_iterator) + result.img.save("assets/pearl_beach_019561_862735879_kdpmpp2m30_PS7.0_img2img-0.01_make_it_at_the_beach.jpg") + ``` + +

+ + + +

+ +#### Add Details Control (upscaling/super-resolution) + +Replaces existing details in an image. Good to use with --init-image-strength 0.2 + +=== "CLI" + ```bash + imagine --control-image "assets/wishbone.jpg" --control-mode details "sharp focus, high-resolution" --init-image-strength 0.2 --steps 30 --size 2048x2048 + ``` + +=== "Python" + ``` py + from imaginairy.api.generate import imagine + from imaginairy.schema import ImaginePrompt, ControlInput, LazyLoadingImage + + image = LazyLoadingImage(filepath="assets/wishbone_headshot_badscale.jpg") + control_mode = ControlInput(mode="details", image=image) + prompt = ImaginePrompt(prompt="sharp focus, high-resolution", control_inputs=[control_mode], init_image_strength=0.2) + + result = next(imagine(prompts=prompt)) + result.img.save("assets/wishbone_headshot_details.jpg") + ``` + +

+ + +

+ + +## Image (re)Colorization (using brightness control) +Colorize black and white images or re-color existing images. + +The generated colors will be applied back to the original image. You can either provide a caption or +allow the tool to generate one for you. + +=== "CLI" + ```bash + aimg colorize pearl-girl.jpg --caption "photo of a woman" + ``` +=== "Python" + ``` py + from imaginairy.api.colorize import colorize_img + from PIL import Image, ImageEnhance, ImageStat + + init_image = Image.open("assets/girl_with_a_pearl_earring.jpg") + image = colorize_img(img=init_image, caption="photo of a woman") + image.save("assets/pearl-colorized.jpg") + ``` + +

+ + + +

diff --git a/imaginairy/api/colorize.py b/imaginairy/api/colorize.py index 554d6cf4..2dbfbcd1 100644 --- a/imaginairy/api/colorize.py +++ b/imaginairy/api/colorize.py @@ -1,4 +1,4 @@ -"""Functions for colorizing black and white images""" +"""Functions for colorizing images""" import logging @@ -12,6 +12,19 @@ def colorize_img(img, max_width=1024, max_height=1024, caption=None): + """ + Colorizes black and white images or re-colors existing images. Optionally adds a caption. + + Args: + img (Image): The image to be colorized. + max_width (int, optional): The maximum width of the output image, defaults to 1024. + max_height (int, optional): The maximum height of the output image, defaults to 1024. + caption (str, optional): A caption for the image. If None, a caption is generated and modified. + + Returns: + Image: The colorized version of the input image. + + """ if not caption: caption = generate_caption(img, min_length=10) caption = caption.replace("black and white", "color") diff --git a/imaginairy/api/generate.py b/imaginairy/api/generate.py index bb72d9c3..472ee451 100755 --- a/imaginairy/api/generate.py +++ b/imaginairy/api/generate.py @@ -34,6 +34,27 @@ def imagine_image_files( return_filename_type: str = "generated", videogen: bool = False, ): + """ + Generates and saves image files based on given prompts, with options for animations and videos. + + Args: + prompts (list[ImaginePrompt] | ImaginePrompt): A prompt or list of prompts for image generation. + outdir (str): Directory path where the generated images and other files will be saved. + precision (str, optional): Precision mode for image generation, defaults to 'autocast'. + record_step_images (bool, optional): If True, saves step-by-step images of the generation process, defaults to False. + output_file_extension (str, optional): File extension for output images, must be 'jpg' or 'png', defaults to 'jpg'. + print_caption (bool, optional): If True, prints captions on the generated images, defaults to False. + make_gif (bool, optional): If True, creates a GIF from the generation steps, defaults to False. + make_compare_gif (bool, optional): If True, creates a comparison GIF with initial and generated images, defaults to False. + return_filename_type (str, optional): Type of filenames to return, defaults to 'generated'. + videogen (bool, optional): If True, generates a video from the generated images, defaults to False. + + Returns: + list[str]: A list of filenames of the generated images. + + Raises: + ValueError: If the output file extension is not 'jpg' or 'png'. + """ from PIL import ImageDraw from imaginairy.api.video_sample import generate_video @@ -157,6 +178,24 @@ def imagine( add_caption: bool = False, unsafe_retry_count: int = 1, ): + """ + Generates images based on the provided prompts using the ImaginAIry API. + + Args: + prompts (list[ImaginePrompt] | str | ImaginePrompt): A prompt or list of prompts for image generation. + Can be a string, a single ImaginePrompt instance, or a list of ImaginePrompt instances. + precision (str, optional): The precision mode for image generation, defaults to 'autocast'. + debug_img_callback (Callable, optional): Callback function for debugging images, defaults to None. + progress_img_callback (Callable, optional): Callback function called at intervals with progress images, defaults to None. + progress_img_interval_steps (int, optional): Number of steps between each progress image callback, defaults to 3. + progress_img_interval_min_s (float, optional): Minimum seconds between each progress image callback, defaults to 0.1. + half_mode: If set, determines whether to use half precision mode for image generation, defaults to None. + add_caption (bool, optional): Flag to add captions to the generated images, defaults to False. + unsafe_retry_count (int, optional): Number of retries for generating an image if it is deemed unsafe, defaults to 1. + + Yields: + The generated image(s) based on the provided prompts. + """ import torch.nn from imaginairy.api.generate_refiners import generate_single_image diff --git a/imaginairy/api/video_sample.py b/imaginairy/api/video_sample.py index 128a36f0..6a63c0fb 100644 --- a/imaginairy/api/video_sample.py +++ b/imaginairy/api/video_sample.py @@ -48,8 +48,27 @@ def generate_video( repetitions=1, ): """ - Simple script to generate a single sample conditioned on an image `input_path` or multiple images, one for each - image file in folder `input_path`. If you run out of VRAM, try decreasing `decoding_t`. + Generates a video from a single image or multiple images, conditioned on the provided input_path. + + Args: + input_path (str): Path to an image file or a directory containing image files. + output_folder (str | None, optional): Directory where the generated video will be saved. + Defaults to "outputs/video/" if None. + num_frames (int, optional): Number of frames in the generated video. Defaults to 6. + num_steps (int, optional): Number of steps for the generation process. Defaults to 30. + model_name (str, optional): Name of the model to use for generation. Defaults to "svd_xt". + fps_id (int, optional): Frame rate identifier used in generation. Defaults to 6. + output_fps (int, optional): Frame rate of the output video. Defaults to 6. + motion_bucket_id (int, optional): Identifier for motion bucket. Defaults to 127. + cond_aug (float, optional): Conditional augmentation value. Defaults to 0.02. + seed (Optional[int], optional): Random seed for generation. If None, a random seed is chosen. + decoding_t (int, optional): Number of frames decoded at a time, affecting VRAM usage. + Reduce if necessary. Defaults to 1. + device (Optional[str], optional): Device to run the generation on. Defaults to the detected device. + repetitions (int, optional): Number of times to repeat the video generation process. Defaults to 1. + + Returns: + None: The function saves the generated video(s) to the specified output folder. """ device = default(device, get_device) diff --git a/imaginairy/schema.py b/imaginairy/schema.py index b5ccbf39..f31d2996 100644 --- a/imaginairy/schema.py +++ b/imaginairy/schema.py @@ -40,7 +40,29 @@ class InvalidUrlError(ValueError): class LazyLoadingImage: - """Image file encoded as base64 string.""" + """ + A class representing an image that can be lazily loaded from various sources. + + This class supports loading an image from a filepath, URL, a PIL Image object, + or a base64 encoded string. The image is only loaded into memory when it's + accessed, not at the time of object creation. If multiple sources are provided, + an error is raised. The class also provides functionality to convert the image + to a base64 string and to access it as a PIL Image object. + + Attributes: + _lazy_filepath (str): Path to the image file, if provided. + _lazy_url (str): URL of the image, if provided. + _img (Image.Image): PIL Image object, if provided. + + Methods: + _load_img: Lazily loads the image from the specified source. + as_base64: Returns the image encoded as a base64 string. + as_pillow: Returns the image as a PIL Image object. + save_image_as_base64: Static method to convert a PIL Image to a base64 string. + load_image_from_base64: Static method to load an image from a base64 string. + __get_pydantic_core_schema__: Class method for Pydantic schema generation. + + """ def __init__( self, @@ -205,6 +227,35 @@ def __repr__(self): class ControlInput(BaseModel): + """ + A Pydantic model representing the input control parameters for an operation, + typically involving image processing. + + This model includes parameters such as the operation mode, the image to be processed, + an alternative raw image, and a strength parameter. It validates these parameters to + ensure they meet specific criteria, such as the mode being one of the predefined valid modes + and ensuring that both 'image' and 'image_raw' are not provided simultaneously. + + Attributes: + mode (str): The operation mode, which must be one of the predefined valid modes. + image (LazyLoadingImage, optional): An instance of LazyLoadingImage to be processed. + Defaults to None. + image_raw (LazyLoadingImage, optional): An alternative raw image instance of + LazyLoadingImage. Defaults to None. + strength (float): A float value representing the strength of the operation, must be + between 0 and 1000 (inclusive). Defaults to 1. + + Methods: + image_raw_validate: Validates that either 'image' or 'image_raw' is provided, + but not both. + mode_validate: Validates that the 'mode' attribute is one of the predefined valid + modes in the configuration. + + Raises: + ValueError: Raised if both 'image' and 'image_raw' are specified, or if the + 'mode' is not a valid mode. + """ + mode: str image: LazyLoadingImage | None = None image_raw: LazyLoadingImage | None = None @@ -238,6 +289,23 @@ def mode_validate(cls, v): class WeightedPrompt(BaseModel): + """ + Represents a prompt with an associated weight. + + This class is used to define a text prompt with a corresponding numerical weight, + indicating the significance or influence of the prompt in a given context, such as + in image generation or text processing tasks. + + Attributes: + text (str): The textual content of the prompt. + weight (float): A numerical weight associated with the prompt. Defaults to 1. + The weight must be greater than or equal to 0. + + Methods: + __repr__: Returns a string representation of the WeightedPrompt instance, + formatted as 'weight*(text)'. + """ + text: str weight: float = Field(1, ge=0) @@ -256,6 +324,39 @@ class MaskMode(str, Enum): class ImaginePrompt(BaseModel, protected_namespaces=()): + """ + The ImaginePrompt class is used for configuring and generating image prompts. + + Attributes: + prompt (str | WeightedPrompt | list[WeightedPrompt] | list[str] | None, optional): Primary prompt for the image generation. + negative_prompt (str | WeightedPrompt | list[WeightedPrompt] | list[str] | None, optional): Prompt specifying what to avoid in the image. + prompt_strength (float, optional): Strength of the influence of the prompt on the output. + init_image (LazyLoadingImage, optional): Initial image to base the generation on. + init_image_strength (float, optional): Strength of the influence of the initial image. + control_inputs (List[ControlInput], optional): Additional control inputs for image generation. + mask_prompt (str, optional): Mask prompt for selective area generation. + mask_image (LazyLoadingImage, optional): Image used for masking. + mask_mode (MaskMode | str): Mode of masking operation. + mask_modify_original (bool): Flag to modify the original image with mask. + outpaint (str, optional): Outpainting string for extending image boundaries. + model_weights (str): Weights configuration for the generation model. + solver_type (str): Type of solver used for image generation. + seed (int, optional): Seed for random number generator. + steps (int, optional): Number of steps for the generation process. + size (int | str | tuple[int, int], optional): Size of the generated image. + upscale (bool): Flag to enable upscaling of the generated image. + fix_faces (bool): Flag to apply face fixing in the generation. + fix_faces_fidelity (float, optional): Fidelity of face fixing. + conditioning (str, optional): Additional conditioning string. + tile_mode (str): Mode of tiling for the image. + allow_compose_phase (bool): Flag to allow composition phase in generation. + is_intermediate (bool): Flag for intermediate image processing. + collect_progress_latents (bool): Flag to collect progress latents. + caption_text (str): Caption text for the image. + composition_strength (float, optional): Strength of the composition effect. + inpaint_method (InpaintMethod): Method used for inpainting. + """ + model_config = ConfigDict(extra="forbid", validate_assignment=True) prompt: List[WeightedPrompt] = Field(default=None, validate_default=True) # type: ignore diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..096be06e --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,56 @@ +site_name: ImaginAIry +theme: + name: material + features: + - content.tabs.link + - content.code.copy + palette: + primary: cyan + +markdown_extensions: + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + - mkdocs-click + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + - pymdownx.superfences + - pymdownx.tabbed: + slugify: !!python/object/apply:pymdownx.slugs.slugify + kwds: + case: lower + alternate_style: true + - attr_list + - md_in_html + +plugins: + - search + - mkdocstrings: + default_handler: python + handlers: + python: + rendering: + show_source: true + +nav: + - Home: index.md + - Docs: + - CLI: + - Create Image: docs/CLI/imagine.md + - Create Video: docs/CLI/videogen.md + - Edit Image: docs/CLI/edit.md + - Upscale Image: docs/CLI/upscale.md + - Colorize Image: docs/CLI/colorize.md + - Describe Image: docs/CLI/describe.md + - Python: + - imagine(): docs/Python/imagine.md + - imagine_image_files(): docs/Python/imagine-image-files.md + - generate_video(): docs/Python/generate-video.md + - colorize_img(): docs/Python/colorize-img.md + - ImaginePrompt: docs/Python/ImaginePrompt.md + - ControlInput: docs/Python/ControlInput.md + - LazyLoadingImage: docs/Python/LazyLoadingImage.md + - WeightedPrompt: docs/Python/WeightedPrompt.md + diff --git a/requirements-dev.in b/requirements-dev.in index 663ee3d0..eeb96ca4 100644 --- a/requirements-dev.in +++ b/requirements-dev.in @@ -1,5 +1,8 @@ coverage httpx +mkdocs-material +mkdocs-click +mkdocstrings[python] mypy ruff pytest diff --git a/requirements-dev.txt b/requirements-dev.txt index 182f449b..e49eebaf 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -12,6 +12,8 @@ anyio==4.2.0 # via # httpx # starlette +babel==2.14.0 + # via mkdocs-material certifi==2023.11.17 # via # httpcore @@ -24,11 +26,18 @@ click==8.1.7 # click-help-colors # click-shell # imaginAIry (setup.py) + # mkdocs + # mkdocs-click + # mkdocstrings # uvicorn click-help-colors==0.9.4 # via imaginAIry (setup.py) click-shell==2.1 # via imaginAIry (setup.py) +colorama==0.4.6 + # via + # griffe + # mkdocs-material contourpy==1.2.0 # via matplotlib coverage==7.4.0 @@ -67,6 +76,10 @@ ftfy==6.1.3 # via # imaginAIry (setup.py) # open-clip-torch +ghp-import==2.1.0 + # via mkdocs +griffe==0.38.1 + # via mkdocstrings-python h11==0.14.0 # via # httpcore @@ -96,19 +109,55 @@ iniconfig==2.0.0 jaxtyping==0.2.25 # via imaginAIry (setup.py) jinja2==3.1.2 - # via torch + # via + # mkdocs + # mkdocs-material + # mkdocstrings + # torch kiwisolver==1.4.5 # via matplotlib kornia==0.7.1 # via imaginAIry (setup.py) llvmlite==0.41.1 # via numba +markdown==3.5.1 + # via + # mkdocs + # mkdocs-autorefs + # mkdocs-click + # mkdocs-material + # mkdocstrings + # pymdown-extensions markupsafe==2.1.3 - # via jinja2 + # via + # jinja2 + # mkdocs + # mkdocstrings matplotlib==3.7.4 # via # -c tests/constraints.txt # filterpy +mergedeep==1.3.4 + # via mkdocs +mkdocs==1.5.3 + # via + # mkdocs-autorefs + # mkdocs-material + # mkdocstrings +mkdocs-autorefs==0.5.0 + # via mkdocstrings +mkdocs-click==0.8.1 + # via -r requirements-dev.in +mkdocs-material==9.5.3 + # via -r requirements-dev.in +mkdocs-material-extensions==1.3.1 + # via mkdocs-material +mkdocstrings[python]==0.24.0 + # via + # -r requirements-dev.in + # mkdocstrings-python +mkdocstrings-python==1.7.5 + # via mkdocstrings mpmath==1.3.0 # via sympy mypy==1.8.0 @@ -149,9 +198,14 @@ packaging==23.2 # huggingface-hub # kornia # matplotlib + # mkdocs # pytest # pytest-sugar # transformers +paginate==0.5.6 + # via mkdocs-material +pathspec==0.12.1 + # via mkdocs pillow==10.2.0 # via # diffusers @@ -160,6 +214,10 @@ pillow==10.2.0 # imaginAIry (setup.py) # matplotlib # torchvision +platformdirs==4.1.0 + # via + # mkdocs + # mkdocstrings pluggy==1.3.0 # via pytest protobuf==4.25.1 @@ -174,6 +232,12 @@ pydantic==2.5.3 # imaginAIry (setup.py) pydantic-core==2.14.6 # via pydantic +pygments==2.17.2 + # via mkdocs-material +pymdown-extensions==10.7 + # via + # mkdocs-material + # mkdocstrings pyparsing==3.1.1 # via matplotlib pytest==7.4.4 @@ -189,17 +253,25 @@ pytest-randomly==3.15.0 pytest-sugar==0.9.7 # via -r requirements-dev.in python-dateutil==2.8.2 - # via matplotlib + # via + # ghp-import + # matplotlib pyyaml==6.0.1 # via # huggingface-hub + # mkdocs # omegaconf + # pymdown-extensions + # pyyaml-env-tag # responses # timm # transformers +pyyaml-env-tag==0.1 + # via mkdocs regex==2023.12.25 # via # diffusers + # mkdocs-material # open-clip-torch # transformers requests==2.31.0 @@ -207,6 +279,7 @@ requests==2.31.0 # diffusers # huggingface-hub # imaginAIry (setup.py) + # mkdocs-material # responses # torchvision # transformers @@ -305,6 +378,8 @@ urllib3==2.1.0 # types-requests uvicorn==0.25.0 # via imaginAIry (setup.py) +watchdog==3.0.0 + # via mkdocs wcwidth==0.2.12 # via ftfy wheel==0.42.0