Files
CavinHuang-comfyui-nodes-docs/docs/Load Image Batch.md
2024-05-26 20:35:16 +08:00

7.4 KiB

Documentation

WAS_Load_Image_Batch 节点旨在高效地加载和管理图像文件批次。它提供以不同模式加载图像的功能,如单张图像、增量图像或随机选择。该节点确保图像正确定向,并且在需要时可以处理 RGBA 到 RGB 的转换。它还能够根据指定去除文件名中的文件扩展名。

Input types

Required

  • path
    • 'path' 参数指定了图像文件所在的目录路径。这对于节点定位和访问所需处理的图像文件至关重要。
    • Comfy dtype: STRING
    • Python dtype: str

Optional

  • pattern
    • 'pattern' 参数用于根据特定模式过滤图像文件。它对于在指定目录内选择符合给定标准的图像子集很重要。
    • Comfy dtype: STRING
    • Python dtype: str
  • index
    • 'index' 参数是一个整数,表示要加载的批次中图像的具体位置。当模式设置为 'single_image' 时,它在确定要检索的确切图像时起着重要作用。
    • Comfy dtype: INT
    • Python dtype: int
  • mode
    • 'mode' 参数确定加载图像的方法。它可以是 'single_image' 用于加载特定图像,'incremental_image' 用于顺序访问,或 'random' 用于随机选择。
    • Comfy dtype: COMBO['single_image', 'incremental_image', 'random']
    • Python dtype: str
  • label
    • 'label' 参数是一个字符串,用于标识和分类图像批次。它有助于在节点操作中组织和跟踪不同的图像集。
    • Comfy dtype: STRING
    • Python dtype: str
  • allow_RGBA_output
    • 'allow_RGBA_output' 参数决定是否允许输出图像具有 RGBA 通道。如果设置为 'false',则节点将图像转换为 RGB。
    • Comfy dtype: COMBO['false', 'true']
    • Python dtype: str
  • filename_text_extension
    • 'filename_text_extension' 参数指示是否在文件名文本输出中包含文件扩展名。在不需要文件扩展名的文件名中,它很有用。
    • Comfy dtype: COMBO['true', 'false']
    • Python dtype: str

Output types

  • image
    • 'image' 输出提供了指定批次中加载的图像。它是节点功能内图像处理任务的主要输出。
    • Comfy dtype: IMAGE
    • Python dtype: PIL.Image.Image
  • filename_text
    • 'filename_text' 输出返回加载的图像文件的名称,可以用于参考或在节点之外进行进一步处理。
    • Comfy dtype: STRING
    • Python dtype: str

Usage tips

  • Infra type: CPU

Source code

class WAS_Load_Image_Batch:

    def __init__(self):
        self.HDB = WASDatabase(WAS_HISTORY_DATABASE)

    @classmethod
    def INPUT_TYPES(cls):
        return {'required': {'mode': (['single_image', 'incremental_image', 'random'],), 'index': ('INT', {'default': 0, 'min': 0, 'max': 150000, 'step': 1}), 'label': ('STRING', {'default': 'Batch 001', 'multiline': False}), 'path': ('STRING', {'default': '', 'multiline': False}), 'pattern': ('STRING', {'default': '*', 'multiline': False}), 'allow_RGBA_output': (['false', 'true'],)}, 'optional': {'filename_text_extension': (['true', 'false'],)}}
    RETURN_TYPES = ('IMAGE', TEXT_TYPE)
    RETURN_NAMES = ('image', 'filename_text')
    FUNCTION = 'load_batch_images'
    CATEGORY = 'WAS Suite/IO'

    def load_batch_images(self, path, pattern='*', index=0, mode='single_image', label='Batch 001', allow_RGBA_output='false', filename_text_extension='true'):
        allow_RGBA_output = allow_RGBA_output == 'true'
        if not os.path.exists(path):
            return (None,)
        fl = self.BatchImageLoader(path, label, pattern)
        new_paths = fl.image_paths
        if mode == 'single_image':
            (image, filename) = fl.get_image_by_id(index)
            if image == None:
                cstr(f'No valid image was found for the inded `{index}`').error.print()
                return (None, None)
        elif mode == 'incremental_image':
            (image, filename) = fl.get_next_image()
            if image == None:
                cstr(f'No valid image was found for the next ID. Did you remove images from the source directory?').error.print()
                return (None, None)
        else:
            newindex = int(random.random() * len(fl.image_paths))
            (image, filename) = fl.get_image_by_id(newindex)
            if image == None:
                cstr(f'No valid image was found for the next ID. Did you remove images from the source directory?').error.print()
                return (None, None)
        update_history_images(new_paths)
        if not allow_RGBA_output:
            image = image.convert('RGB')
        if filename_text_extension == 'false':
            filename = os.path.splitext(filename)[0]
        return (pil2tensor(image), filename)

    class BatchImageLoader:

        def __init__(self, directory_path, label, pattern):
            self.WDB = WDB
            self.image_paths = []
            self.load_images(directory_path, pattern)
            self.image_paths.sort()
            stored_directory_path = self.WDB.get('Batch Paths', label)
            stored_pattern = self.WDB.get('Batch Patterns', label)
            if stored_directory_path != directory_path or stored_pattern != pattern:
                self.index = 0
                self.WDB.insert('Batch Counters', label, 0)
                self.WDB.insert('Batch Paths', label, directory_path)
                self.WDB.insert('Batch Patterns', label, pattern)
            else:
                self.index = self.WDB.get('Batch Counters', label)
            self.label = label

        def load_images(self, directory_path, pattern):
            for file_name in glob.glob(os.path.join(glob.escape(directory_path), pattern), recursive=True):
                if file_name.lower().endswith(ALLOWED_EXT):
                    abs_file_path = os.path.abspath(file_name)
                    self.image_paths.append(abs_file_path)

        def get_image_by_id(self, image_id):
            if image_id < 0 or image_id >= len(self.image_paths):
                cstr(f'Invalid image index `{image_id}`').error.print()
                return
            i = Image.open(self.image_paths[image_id])
            i = ImageOps.exif_transpose(i)
            return (i, os.path.basename(self.image_paths[image_id]))

        def get_next_image(self):
            if self.index >= len(self.image_paths):
                self.index = 0
            image_path = self.image_paths[self.index]
            self.index += 1
            if self.index == len(self.image_paths):
                self.index = 0
            cstr(f'{cstr.color.YELLOW}{self.label}{cstr.color.END} Index: {self.index}').msg.print()
            self.WDB.insert('Batch Counters', self.label, self.index)
            i = Image.open(image_path)
            i = ImageOps.exif_transpose(i)
            return (i, os.path.basename(image_path))

        def get_current_image(self):
            if self.index >= len(self.image_paths):
                self.index = 0
            image_path = self.image_paths[self.index]
            return os.path.basename(image_path)

    @classmethod
    def IS_CHANGED(cls, **kwargs):
        if kwargs['mode'] != 'single_image':
            return float('NaN')
        else:
            fl = WAS_Load_Image_Batch.BatchImageLoader(kwargs['path'], kwargs['label'], kwargs['pattern'])
            filename = fl.get_current_image()
            image = os.path.join(kwargs['path'], filename)
            sha = get_sha256(image)
            return sha