diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7bfcd7a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +*.pyc \ No newline at end of file diff --git a/README.md b/README.md index 154ee33..4aeb398 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,42 @@ # ComfyUI-MagicAnimate -Easily use Magic Animate within ComfyUI! \ No newline at end of file +Easily use Magic Animate within ComfyUI! + +[![](https://dcbadge.vercel.app/api/server/MfVCahkc2y)](https://discord.gg/MfVCahkc2y) + + +- [Installation](#1-installation) +- [Node types](#node-types) +- [Example workflows](#example-workflows) + - [Animate any person's image with a DeepPose video input](#animate-any-person's-image-with-a-DeepPose-video-input) + + +Need help? Join our Discord! + +## 1. Installation +``` +cd ComfyUI/custom_nodes/ +git clone https://github.com/thecooltechguy/ComfyUI-MagicAnimate +cd ComfyUI-MagicAnimate/ +python -m pip install -r requirements.txt +python prestartup_script.py # This will download all the necessary model checkpoints +``` + +## Node types +- **MagicAnimateModelLoader** + - Loads the MagicAnimate model +- **MagicAnimate** + - Uses the MagicAnimate model to animate an input image using an input DeepPose video, and outputs the generated video + +## Example workflows + +### Animate any person's image with a DeepPose video input +[https://comfyworkflows.com/workflows/2e137168-91f7-414d-b3c6-23feaf704fdb](https://comfyworkflows.com/workflows/2e137168-91f7-414d-b3c6-23feaf704fdb) + +![workflow graph](./workflow1_graph.png) +![sample output](./workflow1.gif) + + \ No newline at end of file diff --git a/__pycache__/__init__.cpython-310.pyc b/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 0d885d6..0000000 Binary files a/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/__pycache__/nodes.cpython-310.pyc b/__pycache__/nodes.cpython-310.pyc deleted file mode 100644 index ff5afa1..0000000 Binary files a/__pycache__/nodes.cpython-310.pyc and /dev/null differ diff --git a/libs/magicanimate/pipelines/__pycache__/pipeline_animation.cpython-310.pyc b/libs/magicanimate/pipelines/__pycache__/pipeline_animation.cpython-310.pyc deleted file mode 100644 index 1385595..0000000 Binary files a/libs/magicanimate/pipelines/__pycache__/pipeline_animation.cpython-310.pyc and /dev/null differ diff --git a/nodes.py b/nodes.py index e22b647..0dab639 100644 --- a/nodes.py +++ b/nodes.py @@ -19,7 +19,6 @@ from magicanimate.utils.util import save_videos_grid from magicanimate.utils.dist_tools import distributed_init from accelerate.utils import set_seed from collections import OrderedDict -# from magicanimate.utils.videoreader import VideoReader class MagicAnimateModelLoader: def __init__(self): @@ -27,8 +26,6 @@ class MagicAnimateModelLoader: @classmethod def INPUT_TYPES(s): - # checkpoints = folder_paths.get_filename_list("checkpoints") - # vaes = folder_paths.get_filename_list("vae") magic_animate_checkpoints = folder_paths.get_filename_list("magic_animate") devices = [] @@ -38,16 +35,6 @@ class MagicAnimateModelLoader: return { "required": { - # "model" : (checkpoints, { - # "default" : checkpoints[0], - # }), - # "vae" : (vaes, { - # "default" : vaes[0] - # }) - # "model": ("MODEL",), - # "clip" : ("CLIP",), - # "vae" : ("VAE",), - # "controlnet" : ("CONTROL_NET",), "controlnet" : (magic_animate_checkpoints ,{ "default" : magic_animate_checkpoints[0] }), @@ -89,13 +76,6 @@ class MagicAnimateModelLoader: motion_module = os.path.join(magic_animate_models_dir, motion_module) config.motion_module = motion_module - # print(magic_animate_models_dir) - # print(config.pretrained_appearance_encoder_path) - # print(config.pretrained_model_path) - # print(config.pretrained_vae_path) - # print(config.pretrained_controlnet_path) - # print(config.motion_module) - ### >>> create animation pipeline >>> ### tokenizer = CLIPTokenizer.from_pretrained(config.pretrained_model_path, subfolder="tokenizer") text_encoder = CLIPTextModel.from_pretrained(config.pretrained_model_path, subfolder="text_encoder") @@ -249,6 +229,7 @@ class MagicAnimate: prompt = "" n_prompt = "" control = pose_video.detach().cpu().numpy() # (num_frames, H, W, C) + # print("control shape:", control.shape) if control.shape[1] != size or control.shape[2] != size: # resize each frame in control to be (size, size) @@ -290,41 +271,14 @@ class MagicAnimate: return (sample,) -class MagicAnimateModelDebug: - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "model": ("MAGIC_ANIMATE_MODEL",), - }, - } - - # RETURN_TYPES = ("MAGIC_ANIMATE_MODEL",) - - FUNCTION = "load_model" - - CATEGORY = "ComfyUI Magic Animate" - - OUTPUT_NODE = True - - RETURN_TYPES = () - - def load_model(self, model): - print(model) - return () - - - # A dictionary that contains all nodes you want to export with their names NODE_CLASS_MAPPINGS = { "MagicAnimateModelLoader" : MagicAnimateModelLoader, "MagicAnimate" : MagicAnimate, - "MagicAnimateModelDebug" : MagicAnimateModelDebug, } # A dictionary that contains the friendly/humanly readable titles for the nodes NODE_DISPLAY_NAME_MAPPINGS = { "MagicAnimateModelLoader" : "Load Magic Animate Model", "MagicAnimate" : "Magic Animate", - "MagicAnimateModelDebug" : "Debug Magic Animate Model", } \ No newline at end of file diff --git a/workflow1.gif b/workflow1.gif new file mode 100644 index 0000000..259db91 Binary files /dev/null and b/workflow1.gif differ diff --git a/workflow1_graph.png b/workflow1_graph.png new file mode 100644 index 0000000..5024eab Binary files /dev/null and b/workflow1_graph.png differ