Compare commits

..
5 Commits
10 changed files with 110 additions and 18 deletions
+4 -1
View File
@@ -228,11 +228,14 @@ This custom node helps to conveniently enhance images through Detector, Detailer
### Batch/List Util ### 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 - 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 List` - Convert multiple images into a single image list
* `Make Image Batch` - Convert multiple images into a single image batch * `Make Image Batch` - Convert multiple images into a single image batch
- The input of images can be scaled up as needed - 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) ### Logics (experimental)
+11 -3
View File
@@ -161,6 +161,7 @@ NODE_CLASS_MAPPINGS = {
"ImpactSegsAndMask": SegsBitwiseAndMask, "ImpactSegsAndMask": SegsBitwiseAndMask,
"ImpactSegsAndMaskForEach": SegsBitwiseAndMaskForEach, "ImpactSegsAndMaskForEach": SegsBitwiseAndMaskForEach,
"EmptySegs": EmptySEGS, "EmptySegs": EmptySEGS,
"ImpactFlattenMask": FlattenMask,
"MediaPipeFaceMeshToSEGS": MediaPipeFaceMeshToSEGS, "MediaPipeFaceMeshToSEGS": MediaPipeFaceMeshToSEGS,
"MaskToSEGS": MaskToSEGS, "MaskToSEGS": MaskToSEGS,
@@ -249,6 +250,8 @@ NODE_CLASS_MAPPINGS = {
"ImpactImageBatchToImageList": ImageBatchToImageList, "ImpactImageBatchToImageList": ImageBatchToImageList,
"ImpactMakeImageList": MakeImageList, "ImpactMakeImageList": MakeImageList,
"ImpactMakeImageBatch": MakeImageBatch, "ImpactMakeImageBatch": MakeImageBatch,
"ImpactMakeMaskList": MakeMaskList,
"ImpactMakeMaskBatch": MakeMaskBatch,
"RegionalSampler": RegionalSampler, "RegionalSampler": RegionalSampler,
"RegionalSamplerAdvanced": RegionalSamplerAdvanced, "RegionalSamplerAdvanced": RegionalSamplerAdvanced,
@@ -332,6 +335,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"BitwiseAndMask": "Pixelwise(MASK & MASK)", "BitwiseAndMask": "Pixelwise(MASK & MASK)",
"SubtractMask": "Pixelwise(MASK - MASK)", "SubtractMask": "Pixelwise(MASK - MASK)",
"AddMask": "Pixelwise(MASK + MASK)", "AddMask": "Pixelwise(MASK + MASK)",
"ImpactFlattenMask": "Flatten Mask Batch",
"DetailerForEach": "Detailer (SEGS)", "DetailerForEach": "Detailer (SEGS)",
"DetailerForEachPipe": "Detailer (SEGS/pipe)", "DetailerForEachPipe": "Detailer (SEGS/pipe)",
"DetailerForEachDebug": "DetailerDebug (SEGS)", "DetailerForEachDebug": "DetailerDebug (SEGS)",
@@ -400,12 +404,16 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"ImpactInversedSwitch": "Inversed Switch (Any)", "ImpactInversedSwitch": "Inversed Switch (Any)",
"ImpactExecutionOrderController": "Execution Order Controller", "ImpactExecutionOrderController": "Execution Order Controller",
"MasksToMaskList": "Masks to Mask List", "MasksToMaskList": "Mask Batch to Mask List",
"MaskListToMaskBatch": "Mask List to Masks", "MaskListToMaskBatch": "Mask List to Mask Batch",
"ImpactImageBatchToImageList": "Image batch to Image List", "ImpactImageBatchToImageList": "Image Batch to Image List",
"ImageListToImageBatch": "Image List to Image Batch", "ImageListToImageBatch": "Image List to Image Batch",
"ImpactMakeImageList": "Make Image List", "ImpactMakeImageList": "Make Image List",
"ImpactMakeImageBatch": "Make Image Batch", "ImpactMakeImageBatch": "Make Image Batch",
"ImpactMakeMaskList": "Make Mask List",
"ImpactMakeMaskBatch": "Make Mask Batch",
"ImpactStringSelector": "String Selector", "ImpactStringSelector": "String Selector",
"StringListToString": "String List to String", "StringListToString": "String List to String",
"WildcardPromptFromString": "Wildcard Prompt from String", "WildcardPromptFromString": "Wildcard Prompt from String",
+7 -1
View File
@@ -237,7 +237,7 @@ app.registerExtension({
if(nodeData.name == "ImpactControlBridge") { if(nodeData.name == "ImpactControlBridge") {
const onConnectionsChange = nodeType.prototype.onConnectionsChange; const onConnectionsChange = nodeType.prototype.onConnectionsChange;
nodeType.prototype.onConnectionsChange = function (type, index, connected, link_info) { nodeType.prototype.onConnectionsChange = function (type, index, connected, link_info) {
if(!link_info || this.inputs[0].type != '*') if(index != 0 || !link_info || this.inputs[0].type != '*')
return; return;
// assign type // assign type
@@ -393,6 +393,7 @@ app.registerExtension({
} }
if (nodeData.name === 'ImpactMakeImageList' || nodeData.name === 'ImpactMakeImageBatch' || if (nodeData.name === 'ImpactMakeImageList' || nodeData.name === 'ImpactMakeImageBatch' ||
nodeData.name === 'ImpactMakeMaskList' || nodeData.name === 'ImpactMakeMaskBatch' ||
nodeData.name === 'CombineRegionalPrompts' || nodeData.name === 'CombineRegionalPrompts' ||
nodeData.name === 'ImpactCombineConditionings' || nodeData.name === 'ImpactConcatConditionings' || nodeData.name === 'ImpactCombineConditionings' || nodeData.name === 'ImpactConcatConditionings' ||
nodeData.name === 'ImpactSEGSConcat' || nodeData.name === 'ImpactSEGSConcat' ||
@@ -405,6 +406,11 @@ app.registerExtension({
input_name = "image"; input_name = "image";
break; break;
case 'ImpactMakeMaskList':
case 'ImpactMakeMaskBatch':
input_name = "mask";
break;
case 'ImpactSEGSConcat': case 'ImpactSEGSConcat':
input_name = "segs"; input_name = "segs";
break; break;
+11 -7
View File
@@ -6,11 +6,15 @@ let refresh_btn2 = document.querySelector('button[title="Refresh widgets in node
let orig = refresh_btn.onclick; let orig = refresh_btn.onclick;
refresh_btn.onclick = function() { if(refresh_btn) {
orig(); refresh_btn.onclick = function() {
api.fetchApi('/impact/wildcards/refresh'); orig();
}; api.fetchApi('/impact/wildcards/refresh');
};
}
refresh_btn2.addEventListener('click', function() { if(refresh_btn2) {
api.fetchApi('/impact/wildcards/refresh'); refresh_btn2?.addEventListener('click', function() {
}); api.fetchApi('/impact/wildcards/refresh');
});
}
+2 -2
View File
@@ -20,7 +20,7 @@ class PreviewBridge:
"image": ("STRING", {"default": ""}), "image": ("STRING", {"default": ""}),
}, },
"optional": { "optional": {
"block": ("BOOLEAN", {"default": True, "label_on": "if_empty_mask", "label_off": "never", "tooltip": "is_empty_mask: If the mask is empty, the execution is stopped.\nnever: The execution is never stopped."}) "block": ("BOOLEAN", {"default": False, "label_on": "if_empty_mask", "label_off": "never", "tooltip": "is_empty_mask: If the mask is empty, the execution is stopped.\nnever: The execution is never stopped."})
}, },
"hidden": {"unique_id": "UNIQUE_ID", "extra_pnginfo": "EXTRA_PNGINFO"}, "hidden": {"unique_id": "UNIQUE_ID", "extra_pnginfo": "EXTRA_PNGINFO"},
} }
@@ -196,7 +196,7 @@ class PreviewBridgeLatent:
}, },
"optional": { "optional": {
"vae_opt": ("VAE", ), "vae_opt": ("VAE", ),
"block": ("BOOLEAN", {"default": True, "label_on": "if_empty_mask", "label_off": "never", "tooltip": "is_empty_mask: If the mask is empty, the execution is stopped.\nnever: The execution is never stopped. Instead, it returns a white mask."}) "block": ("BOOLEAN", {"default": False, "label_on": "if_empty_mask", "label_off": "never", "tooltip": "is_empty_mask: If the mask is empty, the execution is stopped.\nnever: The execution is never stopped. Instead, it returns a white mask."})
}, },
"hidden": {"unique_id": "UNIQUE_ID", "prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}, "hidden": {"unique_id": "UNIQUE_ID", "prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
} }
+1 -1
View File
@@ -1,7 +1,7 @@
import configparser import configparser
import os import os
version_code = [7, 4, 2] version_code = [7, 5]
version = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '') version = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
dependency_version = 22 dependency_version = 22
+19
View File
@@ -1696,6 +1696,25 @@ class ToBinaryMask:
return (mask,) 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: class BitwiseAndMask:
@classmethod @classmethod
def INPUT_TYPES(s): def INPUT_TYPES(s):
+45
View File
@@ -392,6 +392,26 @@ class ImageBatchToImageList:
return (images, ) 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: class MakeImageList:
@classmethod @classmethod
def INPUT_TYPES(s): def INPUT_TYPES(s):
@@ -437,6 +457,31 @@ class MakeImageBatch:
return (image1,) 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: class ReencodeLatent:
@classmethod @classmethod
def INPUT_TYPES(s): def INPUT_TYPES(s):
+9 -2
View File
@@ -5,8 +5,7 @@ import numpy as np
import folder_paths import folder_paths
import nodes import nodes
from . import config from . import config
from PIL import Image, ImageFilter from PIL import Image
from scipy.ndimage import zoom
import comfy import comfy
@@ -579,6 +578,14 @@ def apply_mask_alpha_to_pil(decoded_pil, mask):
return decoded_rgba 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): def try_install_custom_node(custom_node_url, msg):
try: try:
import cm_global import cm_global
+1 -1
View File
@@ -1,7 +1,7 @@
[project] [project]
name = "comfyui-impact-pack" 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." 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.2" version = "7.5"
license = { file = "LICENSE.txt" } license = { file = "LICENSE.txt" }
dependencies = ["segment-anything", "scikit-image", "piexif", "transformers", "opencv-python-headless", "GitPython", "scipy>=1.11.4"] dependencies = ["segment-anything", "scikit-image", "piexif", "transformers", "opencv-python-headless", "GitPython", "scipy>=1.11.4"]