From 8d06232bf4b8738e0736edcbd5b265bb97b57d0b Mon Sep 17 00:00:00 2001 From: "Dr.Lt.Data" Date: Tue, 26 Sep 2023 22:34:46 +0900 Subject: [PATCH] feat: 'Load Images From Dir (Inspire)' --- README.md | 4 +++ __init__.py | 3 +- image_util.py | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 image_util.py diff --git a/README.md b/README.md index ef6cd7a..28b1913 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,9 @@ This repository offers various extension nodes for ComfyUI. Nodes here have diff * `Global Seed (Inspire)`: This is a node that controls the global seed without a separate connection line. It only controls when the widget's name is 'seed' or 'noise_seed'. Additionally, if 'control_before_generate' is checked, it controls the seed before executing the prompt. * Seeds that have been converted into inputs are excluded from the target. If you want to control the seed separately, convert it into an input and control it separately. +* Image Util + * `Load Images From Dir (Inspire)`: This is almost same as `LoadImagesFromDirectory` of [ComfyUI-Advanced-Controlnet](https://github.com/Kosinkadink/ComfyUI-Advanced-ControlNet). This is just a modified version. Just note that this node forcibly normalizes the size of the loaded image to match the size of the first image, even if they are not the same size, to create a batch image. + ## Credits ComfyUI/[ComfyUI](https://github.com/comfyanonymous/ComfyUI) - A powerful and modular stable diffusion GUI. @@ -54,3 +57,4 @@ LucianoCirino[efficiency-nodes-comfyui](https://github.com/LucianoCirino/efficie Fannovel16/[comfyui_controlnet_aux](https://github.com/Fannovel16/comfyui_controlnet_aux) - The wrapper for the controlnet preprocessor in the Inspire Pack depends on these nodes. +Kosinkadink/[ComfyUI-Advanced-Controlnet](https://github.com/Kosinkadink/ComfyUI-Advanced-ControlNet) - `Load Images From Dir (Inspire)` code is came from here. \ No newline at end of file diff --git a/__init__.py b/__init__.py index 6aa0a19..2bd2181 100644 --- a/__init__.py +++ b/__init__.py @@ -7,7 +7,7 @@ import importlib -print(f"### Loading: ComfyUI-Inspire-Pack (V0.17)") +print(f"### Loading: ComfyUI-Inspire-Pack (V0.18)") node_list = [ "lora_block_weight", @@ -15,6 +15,7 @@ node_list = [ "a1111_compat", "prompt_support", "inspire_server", + "image_util", ] NODE_CLASS_MAPPINGS = {} diff --git a/image_util.py b/image_util.py new file mode 100644 index 0000000..df9adf9 --- /dev/null +++ b/image_util.py @@ -0,0 +1,81 @@ +import os +from PIL import Image +from PIL import ImageOps +import numpy as np +import torch +import comfy + +class LoadImagesFromDir: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "directory": ("STRING", {"default": ""}), + }, + "optional": { + "image_load_cap": ("INT", {"default": 0, "min": 0, "step": 1}), + "start_index": ("INT", {"default": 0, "min": 0, "step": 1}), + } + } + + RETURN_TYPES = ("IMAGE", "MASK", "INT") + FUNCTION = "load_images" + + CATEGORY = "Inspire/Batch" + + def load_images(self, directory: str, image_load_cap: int = 0, start_index: int = 0): + if not os.path.isdir(directory): + raise FileNotFoundError(f"Directory '{directory} cannot be found.'") + dir_files = os.listdir(directory) + if len(dir_files) == 0: + raise FileNotFoundError(f"No files in directory '{directory}'.") + + dir_files = sorted(dir_files) + dir_files = [os.path.join(directory, x) for x in dir_files] + + # start at start_index + dir_files = dir_files[start_index:] + + images = [] + masks = [] + + limit_images = False + if image_load_cap > 0: + limit_images = True + image_count = 0 + + for image_path in dir_files: + if os.path.isdir(image_path): + continue + if limit_images and image_count >= image_load_cap: + break + i = Image.open(image_path) + i = ImageOps.exif_transpose(i) + image = i.convert("RGB") + image = np.array(image).astype(np.float32) / 255.0 + image = torch.from_numpy(image)[None,] + if 'A' in i.getbands(): + mask = np.array(i.getchannel('A')).astype(np.float32) / 255.0 + mask = 1. - torch.from_numpy(mask) + else: + mask = torch.zeros((64, 64), dtype=torch.float32, device="cpu") + images.append(image) + masks.append(mask) + image_count += 1 + + if len(images) == 1: + return (images[0], 1) + elif len(images) > 1: + image1 = images[0] + for image2 in images[1:]: + if image1.shape[1:] != image2.shape[1:]: + image2 = comfy.utils.common_upscale(image2.movedim(-1, 1), image1.shape[2], image1.shape[1], "bilinear", "center").movedim(1, -1) + image1 = torch.cat((image1, image2), dim=0) + return (image1, len(images)) + +NODE_CLASS_MAPPINGS = { + "LoadImagesFromDir //Inspire": LoadImagesFromDir, +} +NODE_DISPLAY_NAME_MAPPINGS = { + "LoadImagesFromDir //Inspire": "Load Images From Dir (Inspire)", +}