From 44adbbe282be0d639a48a8f55cdb43ba3e7c22dc Mon Sep 17 00:00:00 2001 From: "Dr.Lt.Data" Date: Sat, 7 Sep 2024 00:48:25 +0900 Subject: [PATCH] feat: ImpactMakeMaskList, ImpactMakeMaskBatch, MasksToMaskList, MaskListToMaskBatch, ImpactFlattenMask --- README.md | 5 +++- __init__.py | 14 ++++++++--- js/impact-pack.js | 6 +++++ modules/impact/config.py | 2 +- modules/impact/impact_pack.py | 19 +++++++++++++++ modules/impact/util_nodes.py | 45 +++++++++++++++++++++++++++++++++++ modules/impact/utils.py | 11 +++++++-- pyproject.toml | 2 +- 8 files changed, 96 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c372fc6..251a4f2 100644 --- a/README.md +++ b/README.md @@ -228,11 +228,14 @@ This custom node helps to conveniently enhance images through Detector, Detailer ### Batch/List Util - * `Image batch To Image List` - Convert Image batch to Image List + * `Image Batch to Image List` - Convert Image batch to Image List - You can use images generated in a multi batch to handle them + * `Image List to Image Batch` - Convert Image List to Image Batch * `Make Image List` - Convert multiple images into a single image list * `Make Image Batch` - Convert multiple images into a single image batch - The input of images can be scaled up as needed + * `Masks to Mask List`, `Mask List to Masks`, `Make Mask List`, `Make Mask Batch` - It has the same functionality as the nodes above, but uses mask as input instead of image. + * `Flatten Mask Batch` - Flattens a Mask Batch into a single Mask. Normal operation is not guaranteed for non-binary masks. ### Logics (experimental) diff --git a/__init__.py b/__init__.py index 689b6c4..c3eb14b 100644 --- a/__init__.py +++ b/__init__.py @@ -161,6 +161,7 @@ NODE_CLASS_MAPPINGS = { "ImpactSegsAndMask": SegsBitwiseAndMask, "ImpactSegsAndMaskForEach": SegsBitwiseAndMaskForEach, "EmptySegs": EmptySEGS, + "ImpactFlattenMask": FlattenMask, "MediaPipeFaceMeshToSEGS": MediaPipeFaceMeshToSEGS, "MaskToSEGS": MaskToSEGS, @@ -249,6 +250,8 @@ NODE_CLASS_MAPPINGS = { "ImpactImageBatchToImageList": ImageBatchToImageList, "ImpactMakeImageList": MakeImageList, "ImpactMakeImageBatch": MakeImageBatch, + "ImpactMakeMaskList": MakeMaskList, + "ImpactMakeMaskBatch": MakeMaskBatch, "RegionalSampler": RegionalSampler, "RegionalSamplerAdvanced": RegionalSamplerAdvanced, @@ -332,6 +335,7 @@ NODE_DISPLAY_NAME_MAPPINGS = { "BitwiseAndMask": "Pixelwise(MASK & MASK)", "SubtractMask": "Pixelwise(MASK - MASK)", "AddMask": "Pixelwise(MASK + MASK)", + "ImpactFlattenMask": "Flatten Mask Batch", "DetailerForEach": "Detailer (SEGS)", "DetailerForEachPipe": "Detailer (SEGS/pipe)", "DetailerForEachDebug": "DetailerDebug (SEGS)", @@ -400,12 +404,16 @@ NODE_DISPLAY_NAME_MAPPINGS = { "ImpactInversedSwitch": "Inversed Switch (Any)", "ImpactExecutionOrderController": "Execution Order Controller", - "MasksToMaskList": "Masks to Mask List", - "MaskListToMaskBatch": "Mask List to Masks", - "ImpactImageBatchToImageList": "Image batch to Image List", + "MasksToMaskList": "Mask Batch to Mask List", + "MaskListToMaskBatch": "Mask List to Mask Batch", + "ImpactImageBatchToImageList": "Image Batch to Image List", "ImageListToImageBatch": "Image List to Image Batch", + "ImpactMakeImageList": "Make Image List", "ImpactMakeImageBatch": "Make Image Batch", + "ImpactMakeMaskList": "Make Mask List", + "ImpactMakeMaskBatch": "Make Mask Batch", + "ImpactStringSelector": "String Selector", "StringListToString": "String List to String", "WildcardPromptFromString": "Wildcard Prompt from String", diff --git a/js/impact-pack.js b/js/impact-pack.js index 2c7bbe2..9b506d6 100644 --- a/js/impact-pack.js +++ b/js/impact-pack.js @@ -393,6 +393,7 @@ app.registerExtension({ } if (nodeData.name === 'ImpactMakeImageList' || nodeData.name === 'ImpactMakeImageBatch' || + nodeData.name === 'ImpactMakeMaskList' || nodeData.name === 'ImpactMakeMaskBatch' || nodeData.name === 'CombineRegionalPrompts' || nodeData.name === 'ImpactCombineConditionings' || nodeData.name === 'ImpactConcatConditionings' || nodeData.name === 'ImpactSEGSConcat' || @@ -405,6 +406,11 @@ app.registerExtension({ input_name = "image"; break; + case 'ImpactMakeMaskList': + case 'ImpactMakeMaskBatch': + input_name = "mask"; + break; + case 'ImpactSEGSConcat': input_name = "segs"; break; diff --git a/modules/impact/config.py b/modules/impact/config.py index 8f4ab57..a732099 100644 --- a/modules/impact/config.py +++ b/modules/impact/config.py @@ -1,7 +1,7 @@ import configparser import os -version_code = [7, 4, 5] +version_code = [7, 5] version = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '') dependency_version = 22 diff --git a/modules/impact/impact_pack.py b/modules/impact/impact_pack.py index 500585c..287f79a 100644 --- a/modules/impact/impact_pack.py +++ b/modules/impact/impact_pack.py @@ -1696,6 +1696,25 @@ class ToBinaryMask: return (mask,) +class FlattenMask: + @classmethod + def INPUT_TYPES(s): + return {"required": { + "masks": ("MASK",), + } + } + + RETURN_TYPES = ("MASK",) + FUNCTION = "doit" + + CATEGORY = "ImpactPack/Operation" + + def doit(self, masks): + masks = utils.make_3d_mask(masks) + masks = utils.flatten_mask(masks) + return (masks,) + + class BitwiseAndMask: @classmethod def INPUT_TYPES(s): diff --git a/modules/impact/util_nodes.py b/modules/impact/util_nodes.py index 0b93850..baee019 100644 --- a/modules/impact/util_nodes.py +++ b/modules/impact/util_nodes.py @@ -392,6 +392,26 @@ class ImageBatchToImageList: return (images, ) +class MakeMaskList: + @classmethod + def INPUT_TYPES(s): + return {"required": {"mask1": ("MASK",), }} + + RETURN_TYPES = ("MASK",) + OUTPUT_IS_LIST = (True,) + FUNCTION = "doit" + + CATEGORY = "ImpactPack/Util" + + def doit(self, **kwargs): + masks = [] + + for k, v in kwargs.items(): + masks.append(v) + + return (masks, ) + + class MakeImageList: @classmethod def INPUT_TYPES(s): @@ -437,6 +457,31 @@ class MakeImageBatch: return (image1,) +class MakeMaskBatch: + @classmethod + def INPUT_TYPES(s): + return {"required": {"mask1": ("MASK",), }} + + RETURN_TYPES = ("MASK",) + FUNCTION = "doit" + + CATEGORY = "ImpactPack/Util" + + def doit(self, **kwargs): + mask1 = kwargs['mask1'] + del kwargs['mask1'] + masks = [utils.make_3d_mask(value) for value in kwargs.values()] + + if len(masks) == 0: + return (mask1,) + else: + for mask2 in masks: + if mask1.shape[1:] != mask2.shape[1:]: + mask2 = comfy.utils.common_upscale(mask2.movedim(-1, 1), mask1.shape[2], mask1.shape[1], "lanczos", "center").movedim(1, -1) + mask1 = torch.cat((mask1, mask2), dim=0) + return (mask1,) + + class ReencodeLatent: @classmethod def INPUT_TYPES(s): diff --git a/modules/impact/utils.py b/modules/impact/utils.py index bf4c40b..bd583cb 100644 --- a/modules/impact/utils.py +++ b/modules/impact/utils.py @@ -5,8 +5,7 @@ import numpy as np import folder_paths import nodes from . import config -from PIL import Image, ImageFilter -from scipy.ndimage import zoom +from PIL import Image import comfy @@ -579,6 +578,14 @@ def apply_mask_alpha_to_pil(decoded_pil, mask): return decoded_rgba +def flatten_mask(all_masks): + merged_mask = (all_masks[0] * 255).to(torch.uint8) + for mask in all_masks[1:]: + merged_mask |= (mask * 255).to(torch.uint8) + + return merged_mask + + def try_install_custom_node(custom_node_url, msg): try: import cm_global diff --git a/pyproject.toml b/pyproject.toml index 867d68d..87e60f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui-impact-pack" description = "This extension offers various detector nodes and detailer nodes that allow you to configure a workflow that automatically enhances facial details. And provide iterative upscaler." -version = "7.4.5" +version = "7.5" license = { file = "LICENSE.txt" } dependencies = ["segment-anything", "scikit-image", "piexif", "transformers", "opencv-python-headless", "GitPython", "scipy>=1.11.4"]