Compare commits

..
7 Commits
Author SHA1 Message Date
Dr.Lt.Data 7330577a0f version marker 2025-01-10 00:49:38 +09:00
Symbiomatrix b1d760291f Dummy shortcircuit. (#880) 2025-01-10 00:49:06 +09:00
Dr.Lt.Data 12e838a320 improved: refresh wildcard
Now refresh feature is moved to menu item.
`Edit > Impact: Refresh Wildcard`
2025-01-06 22:59:33 +09:00
Dr.Lt.Data 8e8621df49 update .gitignore 2024-12-30 02:32:46 +09:00
Dr.Lt.Data cdb7b4d3b0 fix: compatibility patch for VAEEncodeTiled's overlap
https://github.com/ltdrdata/ComfyUI-Impact-Pack/issues/863#issuecomment-2560861500
2024-12-25 16:14:51 +09:00
Dr.Lt.Data 21eecb0c03 fix: install script - folder_paths error 2024-12-22 18:40:09 +09:00
Dr.Lt.Data 9402ecf4f9 refactor: use ControlNetApplyAdvanced instead of legacy ControlNetApply 2024-12-21 18:21:58 +09:00
9 changed files with 95 additions and 52 deletions
+2
View File
@@ -7,3 +7,5 @@ subpack
impact_subpack
*.txt
*.yaml
!requirements.txt
!LICENSE.txt
-1
View File
@@ -69,7 +69,6 @@ def process_wrap(cmd_str, cwd=None, handler=None, env=None):
try:
import platform
import folder_paths
from torchvision.datasets.utils import download_url
import impact.config
+25
View File
@@ -222,6 +222,31 @@ api.addEventListener("executed", progressExecuteHandler);
app.registerExtension({
name: "Comfy.Impack",
commands: [
{
id: 'refresh-impact-wildcard',
label: 'Impact: Refresh Wildcard',
function: async () => {
await api.fetchApi('/impact/wildcards/refresh');
await load_wildcards();
app.extensionManager.toast.add({
severity: 'info',
summary: 'Refreshed!',
detail: 'Impact Wildcard List is refreshed!!',
life: 3000
});
}
}
],
menuCommands: [
{
path: ['Edit'],
commands: ['refresh-impact-wildcard']
}
],
loadedGraphNode(node, app) {
if (node.comfyClass == "MaskPainter") {
input_dirty[node.id + ""] = true;
-20
View File
@@ -1,20 +0,0 @@
import { ComfyApp, app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
let refresh_btn = document.getElementById('comfy-refresh-button');
let refresh_btn2 = document.querySelector('button[title="Refresh widgets in nodes to find new models or files"]');
let orig = refresh_btn.onclick;
if(refresh_btn) {
refresh_btn.onclick = function() {
orig();
api.fetchApi('/impact/wildcards/refresh');
};
}
if(refresh_btn2) {
refresh_btn2?.addEventListener('click', function() {
api.fetchApi('/impact/wildcards/refresh');
});
}
+1 -1
View File
@@ -1,7 +1,7 @@
import configparser
import os
version_code = [8, 1, 3]
version_code = [8, 3]
version = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
dependency_version = 24
+18 -5
View File
@@ -1675,8 +1675,14 @@ class PixelKSampleUpscaler:
preprocessor = nodes.NODE_CLASS_MAPPINGS['TilePreprocessor']()
# might add capacity to set pyrUp_iters later, not needed for now though
preprocessed = preprocessor.execute(images, pyrUp_iters=3, resolution=min(image_w, image_h))[0]
apply_cnet = getattr(nodes.ControlNetApply(), nodes.ControlNetApply.FUNCTION)
positive = apply_cnet(positive, self.tile_cnet, preprocessed, strength=self.tile_cnet_strength)[0]
positive, negative = nodes.ControlNetApplyAdvanced().apply_controlnet(positive=positive,
negative=negative,
control_net=self.tile_cnet,
image=preprocessed,
strength=self.tile_cnet_strength,
start_percent=0,
end_percent=1.0,
vae=self.vae)
refined_latent = impact_sampling.impact_sample(model, seed, steps, cfg, sampler_name, scheduler,
positive, negative, upscaled_latent, denoise, scheduler_func=self.scheduler_func)
@@ -1947,7 +1953,7 @@ class PixelTiledKSampleUpscaler:
def __init__(self, scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative,
denoise,
tile_width, tile_height, tiling_strategy,
upscale_model_opt=None, hook_opt=None, tile_cnet_opt=None, tile_size=512, tile_cnet_strength=1.0):
upscale_model_opt=None, hook_opt=None, tile_cnet_opt=None, tile_size=512, tile_cnet_strength=1.0, overlap=64):
self.params = scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise
self.vae = vae
self.tile_params = tile_width, tile_height, tiling_strategy
@@ -1957,6 +1963,7 @@ class PixelTiledKSampleUpscaler:
self.tile_size = tile_size
self.is_tiled = True
self.tile_cnet_strength = tile_cnet_strength
self.overlap = overlap
def tiled_ksample(self, latent, images):
if "BNK_TiledKSampler" in nodes.NODE_CLASS_MAPPINGS:
@@ -1979,8 +1986,14 @@ class PixelTiledKSampleUpscaler:
preprocessor = nodes.NODE_CLASS_MAPPINGS['TilePreprocessor']()
# might add capacity to set pyrUp_iters later, not needed for now though
preprocessed = preprocessor.execute(images, pyrUp_iters=3, resolution=min(image_w, image_h))[0]
apply_cnet = getattr(nodes.ControlNetApply(), nodes.ControlNetApply.FUNCTION)
positive = apply_cnet(positive, self.tile_cnet, preprocessed, strength=self.tile_cnet_strength)[0]
positive, negative = nodes.ControlNetApplyAdvanced().apply_controlnet(positive=positive,
negative=negative,
control_net=self.tile_cnet,
image=preprocessed,
strength=self.tile_cnet_strength,
start_percent=0, end_percent=1.0,
vae=self.vae)
return TiledKSampler().sample(model, seed, tile_width, tile_height, tiling_strategy, steps, cfg, sampler_name,
scheduler, positive, negative, latent, denoise)[0]
+34 -21
View File
@@ -28,6 +28,7 @@ import base64
import impact.wildcards as wildcards
from . import hooks
from . import utils
import inspect
try:
@@ -269,7 +270,7 @@ class DetailerForEach:
else:
ordered_segs = segs[1]
if noise_mask_feather > 0 and 'denoise_mask_function' not in model.model_options:
if not (isinstance(model, str) and model == "DUMMY") and noise_mask_feather > 0 and 'denoise_mask_function' not in model.model_options:
model = nodes_differential_diffusion.DifferentialDiffusion().apply(model)[0]
for i, seg in enumerate(ordered_segs):
@@ -297,13 +298,16 @@ class DetailerForEach:
seg_seed = seed + i if seg_seed is None else seg_seed
cropped_positive = [
[condition, {
k: core.crop_condition_mask(v, image, seg.crop_region) if k == "mask" else v
for k, v in details.items()
}]
for condition, details in positive
]
if not isinstance(positive, str):
cropped_positive = [
[condition, {
k: core.crop_condition_mask(v, image, seg.crop_region) if k == "mask" else v
for k, v in details.items()
}]
for condition, details in positive
]
else:
cropped_positive = positive
if not isinstance(negative, str):
cropped_negative = [
@@ -324,16 +328,20 @@ class DetailerForEach:
break
orig_cropped_image = cropped_image.clone()
enhanced_image, cnet_pils = core.enhance_detail(cropped_image, model, clip, vae, guide_size, guide_size_for_bbox, max_size,
seg.bbox, seg_seed, steps, cfg, sampler_name, scheduler,
cropped_positive, cropped_negative, denoise, cropped_mask, force_inpaint,
wildcard_opt=wildcard_item, wildcard_opt_concat_mode=wildcard_concat_mode,
detailer_hook=detailer_hook,
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
refiner_negative=refiner_negative, control_net_wrapper=seg.control_net_wrapper,
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather,
scheduler_func=scheduler_func_opt)
if not (isinstance(model, str) and model == "DUMMY"):
enhanced_image, cnet_pils = core.enhance_detail(cropped_image, model, clip, vae, guide_size, guide_size_for_bbox, max_size,
seg.bbox, seg_seed, steps, cfg, sampler_name, scheduler,
cropped_positive, cropped_negative, denoise, cropped_mask, force_inpaint,
wildcard_opt=wildcard_item, wildcard_opt_concat_mode=wildcard_concat_mode,
detailer_hook=detailer_hook,
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
refiner_negative=refiner_negative, control_net_wrapper=seg.control_net_wrapper,
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather,
scheduler_func=scheduler_func_opt)
else:
enhanced_image = cropped_image
cnet_pils = None
if cnet_pils is not None:
cnet_pil_list.extend(cnet_pils)
@@ -986,6 +994,7 @@ class PixelTiledKSampleUpscalerProvider:
"pk_hook_opt": ("PK_HOOK", ),
"tile_cnet_opt": ("CONTROL_NET", ),
"tile_cnet_strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
"overlap": ("INT", {"default": 64, "min": 0, "max": 4096, "step": 32}),
}
}
@@ -995,11 +1004,11 @@ class PixelTiledKSampleUpscalerProvider:
CATEGORY = "ImpactPack/Upscale"
def doit(self, scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, tile_width, tile_height, tiling_strategy, upscale_model_opt=None,
pk_hook_opt=None, tile_cnet_opt=None, tile_cnet_strength=1.0):
pk_hook_opt=None, tile_cnet_opt=None, tile_cnet_strength=1.0, overlap=64):
if "BNK_TiledKSampler" in nodes.NODE_CLASS_MAPPINGS:
upscaler = core.PixelTiledKSampleUpscaler(scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise,
tile_width, tile_height, tiling_strategy, upscale_model_opt, pk_hook_opt, tile_cnet_opt,
tile_size=max(tile_width, tile_height), tile_cnet_strength=tile_cnet_strength)
tile_size=max(tile_width, tile_height), tile_cnet_strength=tile_cnet_strength, overlap=overlap)
return (upscaler, )
else:
utils.try_install_custom_node('https://github.com/BlenderNeko/ComfyUI_TiledKSampler',
@@ -1312,7 +1321,11 @@ class IterativeImageUpscale:
core.update_node_status(unique_id, "VAEEncode (first)", 0)
if upscaler.is_tiled:
latent = nodes.VAEEncodeTiled().encode(vae, pixels, upscaler.tile_size)[0]
encoder = nodes.VAEEncodeTiled()
if 'overlap' in inspect.signature(encoder.encode).parameters:
latent = encoder.encode(vae, pixels, upscaler.tile_size, overlap=upscaler.overlap)[0]
else:
latent = encoder.encode(vae, pixels, upscaler.tile_size)[0]
else:
latent = nodes.VAEEncode().encode(vae, pixels)[0]
+14 -3
View File
@@ -526,6 +526,9 @@ class ReencodeLatent:
"output_vae": ("VAE", ),
"tile_size": ("INT", {"default": 512, "min": 320, "max": 4096, "step": 64}),
},
"optional": {
"overlap": ("INT", {"default": 64, "min": 0, "max": 4096, "step": 32, "tooltip": "This setting applies when 'tile_mode' is enabled."}),
}
}
CATEGORY = "ImpactPack/Util"
@@ -533,14 +536,22 @@ class ReencodeLatent:
RETURN_TYPES = ("LATENT", )
FUNCTION = "doit"
def doit(self, samples, tile_mode, input_vae, output_vae, tile_size=512):
def doit(self, samples, tile_mode, input_vae, output_vae, tile_size=512, overlap=64):
if tile_mode in ["Both", "Decode(input) only"]:
pixels = nodes.VAEDecodeTiled().decode(input_vae, samples, tile_size)[0]
decoder = nodes.VAEDecodeTiled()
if 'overlap' in inspect.signature(decoder.decode).parameters:
pixels = decoder.decode(input_vae, samples, tile_size, overlap=overlap)[0]
else:
pixels = decoder.decode(input_vae, samples, tile_size, overlap=overlap)[0]
else:
pixels = nodes.VAEDecode().decode(input_vae, samples)[0]
if tile_mode in ["Both", "Encode(output) only"]:
return nodes.VAEEncodeTiled().encode(output_vae, pixels, tile_size)
encoder = nodes.VAEEncodeTiled()
if 'overlap' in inspect.signature(encoder.encode).parameters:
return encoder.encode(output_vae, pixels, tile_size, overlap=overlap)
else:
return encoder.encode(output_vae, pixels, tile_size)
else:
return nodes.VAEEncode().encode(output_vae, pixels)
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui-impact-pack"
description = "This node pack offers various detector nodes and detailer nodes that allow you to configure a workflow that automatically enhances facial details. And provide iterative upscaler."
version = "8.1.3"
version = "8.3"
license = { file = "LICENSE.txt" }
dependencies = ["segment-anything", "scikit-image", "piexif", "transformers", "opencv-python-headless", "GitPython", "scipy>=1.11.4"]