Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
940ad41b15 | ||
|
|
e848a9dfb7 | ||
|
|
76653016dc | ||
|
|
9ed160123d | ||
|
|
ffbd4ae116 | ||
|
|
5757c533e6 | ||
|
|
e99e9aaec2 | ||
|
|
690b0a0f61 |
+1
-1
@@ -237,7 +237,7 @@ app.registerExtension({
|
||||
if(nodeData.name == "ImpactControlBridge") {
|
||||
const onConnectionsChange = nodeType.prototype.onConnectionsChange;
|
||||
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;
|
||||
|
||||
// assign type
|
||||
|
||||
+11
-7
@@ -6,11 +6,15 @@ let refresh_btn2 = document.querySelector('button[title="Refresh widgets in node
|
||||
|
||||
let orig = refresh_btn.onclick;
|
||||
|
||||
refresh_btn.onclick = function() {
|
||||
orig();
|
||||
api.fetchApi('/impact/wildcards/refresh');
|
||||
};
|
||||
if(refresh_btn) {
|
||||
refresh_btn.onclick = function() {
|
||||
orig();
|
||||
api.fetchApi('/impact/wildcards/refresh');
|
||||
};
|
||||
}
|
||||
|
||||
refresh_btn2.addEventListener('click', function() {
|
||||
api.fetchApi('/impact/wildcards/refresh');
|
||||
});
|
||||
if(refresh_btn2) {
|
||||
refresh_btn2?.addEventListener('click', function() {
|
||||
api.fetchApi('/impact/wildcards/refresh');
|
||||
});
|
||||
}
|
||||
@@ -19,6 +19,9 @@ class PreviewBridge:
|
||||
"images": ("IMAGE",),
|
||||
"image": ("STRING", {"default": ""}),
|
||||
},
|
||||
"optional": {
|
||||
"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"},
|
||||
}
|
||||
|
||||
@@ -30,6 +33,8 @@ class PreviewBridge:
|
||||
|
||||
CATEGORY = "ImpactPack/Util"
|
||||
|
||||
DESCRIPTION = "This is a feature that allows you to edit and send a Mask over a image.\nIf the block is set to 'is_empty_mask', the execution is stopped when the mask is empty."
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.output_dir = folder_paths.get_temp_directory()
|
||||
@@ -70,7 +75,7 @@ class PreviewBridge:
|
||||
|
||||
return image, mask.unsqueeze(0), ui_item
|
||||
|
||||
def doit(self, images, image, unique_id, prompt=None, extra_pnginfo=None):
|
||||
def doit(self, images, image, unique_id, block=False, prompt=None, extra_pnginfo=None):
|
||||
need_refresh = False
|
||||
|
||||
if unique_id not in core.preview_bridge_cache:
|
||||
@@ -96,9 +101,20 @@ class PreviewBridge:
|
||||
|
||||
image = image2
|
||||
|
||||
is_empty_mask = torch.all(mask == 0)
|
||||
|
||||
if block and is_empty_mask and core.is_execution_model_version_supported:
|
||||
from comfy_execution.graph import ExecutionBlocker
|
||||
result = ExecutionBlocker(None), ExecutionBlocker(None)
|
||||
elif block and is_empty_mask:
|
||||
print(f"[Impact Pack] PreviewBridge: ComfyUI is outdated - blocking feature is disabled.")
|
||||
result = pixels, mask
|
||||
else:
|
||||
result = pixels, mask
|
||||
|
||||
return {
|
||||
"ui": {"images": image},
|
||||
"result": (pixels, mask, ),
|
||||
"result": result,
|
||||
}
|
||||
|
||||
|
||||
@@ -179,7 +195,8 @@ class PreviewBridgeLatent:
|
||||
"TAEF1", "TAESDXL", "TAESD15", "TAESD3"],),
|
||||
},
|
||||
"optional": {
|
||||
"vae_opt": ("VAE", )
|
||||
"vae_opt": ("VAE", ),
|
||||
"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"},
|
||||
}
|
||||
@@ -192,6 +209,8 @@ class PreviewBridgeLatent:
|
||||
|
||||
CATEGORY = "ImpactPack/Util"
|
||||
|
||||
DESCRIPTION = "This is a feature that allows you to edit and send a Mask over a latent image.\nIf the block is set to 'is_empty_mask', the execution is stopped when the mask is empty."
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.output_dir = folder_paths.get_temp_directory()
|
||||
@@ -233,7 +252,7 @@ class PreviewBridgeLatent:
|
||||
|
||||
return image, mask, ui_item
|
||||
|
||||
def doit(self, latent, image, preview_method, vae_opt=None, unique_id=None, prompt=None, extra_pnginfo=None):
|
||||
def doit(self, latent, image, preview_method, vae_opt=None, block=False, unique_id=None, prompt=None, extra_pnginfo=None):
|
||||
latent_channels = latent['samples'].shape[1]
|
||||
preview_method_channels = 16 if 'SD3' in preview_method or 'SC-Prior' in preview_method or 'FLUX.1' in preview_method or 'TAEF1' == preview_method else 4
|
||||
|
||||
@@ -262,10 +281,14 @@ class PreviewBridgeLatent:
|
||||
del res_latent['noise_mask']
|
||||
else:
|
||||
res_latent = latent
|
||||
|
||||
is_empty_mask = True
|
||||
else:
|
||||
res_latent = latent.copy()
|
||||
res_latent['noise_mask'] = mask
|
||||
|
||||
is_empty_mask = torch.all(mask == 1)
|
||||
|
||||
res_image = [path_item]
|
||||
else:
|
||||
decoded_image = decode_latent(latent, preview_method, vae_opt)
|
||||
@@ -287,11 +310,15 @@ class PreviewBridgeLatent:
|
||||
'subfolder': 'PreviewBridge',
|
||||
'type': 'temp',
|
||||
}]
|
||||
|
||||
is_empty_mask = torch.all(mask == 1)
|
||||
else:
|
||||
mask = torch.ones(latent['samples'].shape[2:], dtype=torch.float32, device="cpu").unsqueeze(0)
|
||||
res = nodes.PreviewImage().save_images(decoded_image, filename_prefix="PreviewBridge/PBL-", prompt=prompt, extra_pnginfo=extra_pnginfo)
|
||||
res_image = res['ui']['images']
|
||||
|
||||
is_empty_mask = True
|
||||
|
||||
path = os.path.join(folder_paths.get_temp_directory(), 'PreviewBridge', res_image[0]['filename'])
|
||||
core.set_previewbridge_image(unique_id, path, res_image[0])
|
||||
core.preview_bridge_image_id_map[image] = (path, res_image[0])
|
||||
@@ -300,7 +327,16 @@ class PreviewBridgeLatent:
|
||||
|
||||
res_latent = latent
|
||||
|
||||
if block and is_empty_mask and core.is_execution_model_version_supported:
|
||||
from comfy_execution.graph import ExecutionBlocker
|
||||
result = ExecutionBlocker(None), ExecutionBlocker(None)
|
||||
elif block and is_empty_mask:
|
||||
print(f"[Impact Pack] PreviewBridgeLatent: ComfyUI is outdated - blocking feature is disabled.")
|
||||
result = res_latent, mask
|
||||
else:
|
||||
result = res_latent, mask
|
||||
|
||||
return {
|
||||
"ui": {"images": res_image},
|
||||
"result": (res_latent, mask, ),
|
||||
"result": result,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import configparser
|
||||
import os
|
||||
|
||||
version_code = [7, 3, 1]
|
||||
version_code = [7, 4, 5]
|
||||
version = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
||||
|
||||
dependency_version = 22
|
||||
|
||||
@@ -237,7 +237,7 @@ def enhance_detail(image, model, clip, vae, guide_size, guide_size_for_bbox, max
|
||||
noise_mask = utils.tensor_gaussian_blur_mask(noise_mask, noise_mask_feather)
|
||||
noise_mask = noise_mask.squeeze(3)
|
||||
|
||||
if noise_mask_feather > 0:
|
||||
if noise_mask_feather > 0 and 'denoise_mask_function' not in model.model_options:
|
||||
model = nodes_differential_diffusion.DifferentialDiffusion().apply(model)[0]
|
||||
|
||||
if wildcard_opt is not None and wildcard_opt != "":
|
||||
@@ -383,7 +383,7 @@ def enhance_detail_for_animatediff(image_frames, model, clip, vae, guide_size, g
|
||||
noise_mask = utils.tensor_gaussian_blur_mask(noise_mask, noise_mask_feather)
|
||||
noise_mask = noise_mask.squeeze(3)
|
||||
|
||||
if noise_mask_feather > 0:
|
||||
if noise_mask_feather > 0 and 'denoise_mask_function' not in model.model_options:
|
||||
model = nodes_differential_diffusion.DifferentialDiffusion().apply(model)[0]
|
||||
|
||||
if wildcard_opt is not None and wildcard_opt != "":
|
||||
|
||||
@@ -78,6 +78,8 @@ class PreviewDetailerHookProvider:
|
||||
|
||||
CATEGORY = "ImpactPack/Util"
|
||||
|
||||
NOT_IDEMPOTENT = True
|
||||
|
||||
def doit(self, quality, unique_id):
|
||||
hook = hooks.PreviewDetailerHook(unique_id, quality)
|
||||
return (hook, hook)
|
||||
return hook, hook
|
||||
|
||||
@@ -62,10 +62,10 @@ class CLIPSegDetectorProvider:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"text": ("STRING", {"multiline": False}),
|
||||
"blur": ("FLOAT", {"min": 0, "max": 15, "step": 0.1, "default": 7}),
|
||||
"threshold": ("FLOAT", {"min": 0, "max": 1, "step": 0.05, "default": 0.4}),
|
||||
"dilation_factor": ("INT", {"min": 0, "max": 10, "step": 1, "default": 4}),
|
||||
"text": ("STRING", {"multiline": False, "tooltip": "Enter the targets to be detected, separated by commas"}),
|
||||
"blur": ("FLOAT", {"min": 0, "max": 15, "step": 0.1, "default": 7, "tooltip": "Blurs the detected mask"}),
|
||||
"threshold": ("FLOAT", {"min": 0, "max": 1, "step": 0.05, "default": 0.4, "tooltip": "Detects only areas that are certain above the threshold."}),
|
||||
"dilation_factor": ("INT", {"min": 0, "max": 10, "step": 1, "default": 4, "tooltip": "Dilates the detected mask."}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,8 @@ class CLIPSegDetectorProvider:
|
||||
|
||||
CATEGORY = "ImpactPack/Util"
|
||||
|
||||
DESCRIPTION = "Provides a detection function using CLIPSeg, which generates masks based on text prompts.\nTo use this node, the CLIPSeg custom node must be installed."
|
||||
|
||||
def doit(self, text, blur, threshold, dilation_factor):
|
||||
if "CLIPSeg" in nodes.NODE_CLASS_MAPPINGS:
|
||||
return (core.BBoxDetectorBasedOnCLIPSeg(text, blur, threshold, dilation_factor), )
|
||||
@@ -87,8 +89,10 @@ class SAMLoader:
|
||||
models = [x for x in folder_paths.get_filename_list("sams") if 'hq' not in x]
|
||||
return {
|
||||
"required": {
|
||||
"model_name": (models + ['ESAM'], ),
|
||||
"device_mode": (["AUTO", "Prefer GPU", "CPU"],),
|
||||
"model_name": (models + ['ESAM'], {"tooltip": "The detection accuracy varies depending on the SAM model. ESAM can only be used if ComfyUI-YoloWorld-EfficientSAM is installed."}),
|
||||
"device_mode": (["AUTO", "Prefer GPU", "CPU"], {"tooltip": "AUTO: Only applicable when a GPU is available. It temporarily loads the SAM_MODEL into VRAM only when the detection function is used.\n"
|
||||
"Prefer GPU: Tries to keep the SAM_MODEL on the GPU whenever possible. This can be used when there is sufficient VRAM available.\n"
|
||||
"CPU: Always loads only on the CPU."}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +101,8 @@ class SAMLoader:
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
|
||||
DESCRIPTION = "Load the SAM (Segment Anything) model. This can be used in places that utilize SAM detection functionality, such as SAMDetector or SimpleDetector.\nThe SAM detection functionality in Impact Pack must use the SAM_MODEL loaded through this node."
|
||||
|
||||
def load_model(self, model_name, device_mode="auto"):
|
||||
if model_name == 'ESAM':
|
||||
if 'ESAM_ModelLoader_Zho' not in nodes.NODE_CLASS_MAPPINGS:
|
||||
@@ -1640,6 +1646,8 @@ class BitwiseAndMaskForEach:
|
||||
|
||||
CATEGORY = "ImpactPack/Operation"
|
||||
|
||||
DESCRIPTION = "Retains only the overlapping areas between the masks included in base_segs and the mask regions of mask_segs. SEGS with no overlapping mask areas are filtered out."
|
||||
|
||||
def doit(self, base_segs, mask_segs):
|
||||
mask = core.segs_to_combined_mask(mask_segs)
|
||||
mask = make_3d_mask(mask)
|
||||
@@ -1661,6 +1669,8 @@ class SubtractMaskForEach:
|
||||
|
||||
CATEGORY = "ImpactPack/Operation"
|
||||
|
||||
DESCRIPTION = "Removes only the overlapping areas between the masks included in base_segs and the mask regions of mask_segs. SEGS with no overlapping mask areas are filtered out."
|
||||
|
||||
def doit(self, base_segs, mask_segs):
|
||||
mask = core.segs_to_combined_mask(mask_segs)
|
||||
mask = make_3d_mask(mask)
|
||||
|
||||
@@ -98,7 +98,7 @@ def img2img_segs(image, model, clip, vae, seed, steps, cfg, sampler_name, schedu
|
||||
noise_mask = tensor_gaussian_blur_mask(noise_mask, noise_mask_feather)
|
||||
noise_mask = noise_mask.squeeze(3)
|
||||
|
||||
if noise_mask_feather > 0:
|
||||
if noise_mask_feather > 0 and 'denoise_mask_function' not in model.model_options:
|
||||
model = nodes_differential_diffusion.DifferentialDiffusion().apply(model)[0]
|
||||
|
||||
if control_net_wrapper is not None:
|
||||
|
||||
+1
-1
@@ -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.3.1"
|
||||
version = "7.4.5"
|
||||
license = { file = "LICENSE.txt" }
|
||||
dependencies = ["segment-anything", "scikit-image", "piexif", "transformers", "opencv-python-headless", "GitPython", "scipy>=1.11.4"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user