Files
CavinHuang-comfyui-nodes-docs/docs/LoadImagesFromDir __Inspire.md
2024-07-04 08:39:03 +08:00

5.4 KiB

Documentation

LoadImagesFromDir __Inspire节点旨在从指定目录中批量加载图像,为图像处理或机器学习任务做准备。它高效地处理图像加载、可选的尺寸调整和格式标准化,以确保与下游处理兼容。

Input types

Required

  • directory
    • 指定要加载图像的目录路径。这个参数对于确定节点要处理的图像来源至关重要。
    • Comfy dtype: STRING
    • Python dtype: str

Optional

  • image_load_cap
    • 限制从目录中加载的图像数量,允许控制资源使用和处理时间。
    • Comfy dtype: INT
    • Python dtype: int
  • start_index
    • 确定加载图像的起始索引,使得可以基于顺序从目录中部分加载图像。
    • Comfy dtype: INT
    • Python dtype: int
  • load_always
    • 一个标志,用于指示是否应该在其他条件下也始终加载图像,确保加载行为的灵活性。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool

Output types

  • image
    • 加载的图像,经过处理和格式化,可用于进一步的图像应用。
    • Comfy dtype: IMAGE
    • Python dtype: List[torch.Tensor]
  • mask
    • 与加载图像相关的可选遮罩,对于需要背景分离或聚焦于特定图像区域的任务很有用。
    • Comfy dtype: MASK
    • Python dtype: List[torch.Tensor]
  • int
    • 加载的图像总数,提供了一个计数,可用于进一步的处理步骤或信息目的。
    • Comfy dtype: INT
    • Python dtype: int

Usage tips

  • Infra type: GPU
  • Common nodes: unknown

Source code

class LoadImagesFromDirBatch:
    @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}),
                "load_always": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
            }
        }

    RETURN_TYPES = ("IMAGE", "MASK", "INT")
    FUNCTION = "load_images"

    CATEGORY = "image"

    @classmethod
    def IS_CHANGED(cls, **kwargs):
        if 'load_always' in kwargs and kwargs['load_always']:
            return float("NaN")
        else:
            return hash(frozenset(kwargs))

    def load_images(self, directory: str, image_load_cap: int = 0, start_index: int = 0, load_always=False):
        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}'.")

        # Filter files by extension
        valid_extensions = ['.jpg', '.jpeg', '.png', '.webp']
        dir_files = [f for f in dir_files if any(f.lower().endswith(ext) for ext in valid_extensions)]

        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

        has_non_empty_mask = False

        for image_path in dir_files:
            if os.path.isdir(image_path) and os.path.ex:
                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)
                has_non_empty_mask = True
            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], masks[0], 1)

        elif len(images) > 1:
            image1 = images[0]
            mask1 = None

            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)

            for mask2 in masks[1:]:
                if has_non_empty_mask:
                    if image1.shape[1:3] != mask2.shape:
                        mask2 = torch.nn.functional.interpolate(mask2.unsqueeze(0).unsqueeze(0), size=(image1.shape[2], image1.shape[1]), mode='bilinear', align_corners=False)
                        mask2 = mask2.squeeze(0)
                    else:
                        mask2 = mask2.unsqueeze(0)
                else:
                    mask2 = mask2.unsqueeze(0)

                if mask1 is None:
                    mask1 = mask2
                else:
                    mask1 = torch.cat((mask1, mask2), dim=0)

            return (image1, mask1, len(images))