Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
092310bc8f | ||
|
|
5c530eb32e | ||
|
|
e35bc23fd1 | ||
|
|
869ac6fd1f | ||
|
|
cb168d64ab | ||
|
|
a89e9e01a6 | ||
|
|
e70b4df9b5 | ||
|
|
af1ef7e441 | ||
|
|
d8738eee2f | ||
|
|
c397c68ca3 | ||
|
|
0e0722ec08 | ||
|
|
70d0540895 |
@@ -1,35 +0,0 @@
|
|||||||
import { ComfyApp, app } from "../../scripts/app.js";
|
|
||||||
|
|
||||||
let conflict_check = undefined;
|
|
||||||
|
|
||||||
app.registerExtension({
|
|
||||||
name: "Comfy.impact.comboBoolMigration",
|
|
||||||
|
|
||||||
nodeCreated(node, app) {
|
|
||||||
for(let i in node.widgets) {
|
|
||||||
let widget = node.widgets[i];
|
|
||||||
|
|
||||||
if(conflict_check == undefined) {
|
|
||||||
conflict_check = !!app.extensions.find((ext) => ext.name === "Comfy.comboBoolMigration");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(conflict_check)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(widget.type == "toggle") {
|
|
||||||
let value = widget.value;
|
|
||||||
|
|
||||||
var v = Object.getOwnPropertyDescriptor(widget, 'value');
|
|
||||||
if(!v) {
|
|
||||||
Object.defineProperty(widget, "value", {
|
|
||||||
set: (value) => {
|
|
||||||
delete widget.value;
|
|
||||||
widget.value = value == true || value == widget.options.on;
|
|
||||||
},
|
|
||||||
get: () => { return value; }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
+16
-6
@@ -93,7 +93,7 @@ const input_dirty = {};
|
|||||||
const output_tracking = {};
|
const output_tracking = {};
|
||||||
|
|
||||||
function progressExecuteHandler(event) {
|
function progressExecuteHandler(event) {
|
||||||
if(event.detail.output.aux){
|
if(event.detail?.output?.aux){
|
||||||
const id = event.detail.node;
|
const id = event.detail.node;
|
||||||
if(input_tracking.hasOwnProperty(id)) {
|
if(input_tracking.hasOwnProperty(id)) {
|
||||||
if(input_tracking.hasOwnProperty(id) && input_tracking[id][0] != event.detail.output.aux[0]) {
|
if(input_tracking.hasOwnProperty(id) && input_tracking[id][0] != event.detail.output.aux[0]) {
|
||||||
@@ -273,7 +273,7 @@ app.registerExtension({
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const node = app.graph.getNodeById(link_info.origin_id);
|
const node = app.graph.getNodeById(link_info.origin_id);
|
||||||
slot_type = node.outputs[link_info.origin_slot].type;
|
slot_type = node.outputs[link_info.origin_slot]?.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.inputs[0].type = slot_type;
|
this.inputs[0].type = slot_type;
|
||||||
@@ -365,7 +365,11 @@ app.registerExtension({
|
|||||||
// connect input
|
// connect input
|
||||||
if(this.inputs[0].type == '*'){
|
if(this.inputs[0].type == '*'){
|
||||||
const node = app.graph.getNodeById(link_info.origin_id);
|
const node = app.graph.getNodeById(link_info.origin_id);
|
||||||
let origin_type = node.outputs[link_info.origin_slot].type;
|
let origin_type = node.outputs[link_info.origin_slot]?.type;
|
||||||
|
|
||||||
|
if(origin_type==undefined) {
|
||||||
|
return; // fallback
|
||||||
|
}
|
||||||
|
|
||||||
if(origin_type == '*') {
|
if(origin_type == '*') {
|
||||||
this.disconnectInput(link_info.target_slot);
|
this.disconnectInput(link_info.target_slot);
|
||||||
@@ -755,14 +759,20 @@ app.registerExtension({
|
|||||||
// mode combo
|
// mode combo
|
||||||
Object.defineProperty(mode_widget, "value", {
|
Object.defineProperty(mode_widget, "value", {
|
||||||
set: (value) => {
|
set: (value) => {
|
||||||
node._mode_value = value == true || value == "Populate";
|
if(value == true)
|
||||||
populated_text_widget.inputEl.disabled = value == true || value == "Populate";
|
node._mode_value = "populate";
|
||||||
|
else if(value == false)
|
||||||
|
node._mode_value = "fixed";
|
||||||
|
else
|
||||||
|
node._mode_value = value; // combo value
|
||||||
|
|
||||||
|
populated_text_widget.inputEl.disabled = node._mode_value == 'populate';
|
||||||
},
|
},
|
||||||
get: () => {
|
get: () => {
|
||||||
if(node._mode_value != undefined)
|
if(node._mode_value != undefined)
|
||||||
return node._mode_value;
|
return node._mode_value;
|
||||||
else
|
else
|
||||||
return true;
|
return 'populate';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,7 @@ class SEGSDetailerForAnimateDiff:
|
|||||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS,),
|
"sampler_name": (comfy.samplers.KSampler.SAMPLERS,),
|
||||||
"scheduler": (core.SCHEDULERS,),
|
"scheduler": (core.SCHEDULERS,),
|
||||||
"denoise": ("FLOAT", {"default": 0.5, "min": 0.0001, "max": 1.0, "step": 0.01}),
|
"denoise": ("FLOAT", {"default": 0.5, "min": 0.0001, "max": 1.0, "step": 0.01}),
|
||||||
"basic_pipe": ("BASIC_PIPE",),
|
"basic_pipe": ("BASIC_PIPE", {"tooltip": "If the `ImpactDummyInput` is connected to the model in the basic_pipe, the inference stage is skipped."}),
|
||||||
"refiner_ratio": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0}),
|
"refiner_ratio": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0}),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
@@ -45,6 +45,8 @@ class SEGSDetailerForAnimateDiff:
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Detailer"
|
CATEGORY = "ImpactPack/Detailer"
|
||||||
|
|
||||||
|
DESCRIPTION = "This node enhances details by inpainting each region within the detected area bundle (SEGS) after enlarging them based on the guide size.\nThis node is applied specifically to SEGS rather than the entire image. To apply it to the entire image, use the 'SEGS Paste' node.\nAs a specialized detailer node for improving video details, such as in AnimateDiff, this node can handle cases where the masks contained in SEGS serve as batch masks spanning multiple frames."
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def do_detail(image_frames, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
def do_detail(image_frames, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
||||||
denoise, basic_pipe, refiner_ratio=None, refiner_basic_pipe_opt=None, noise_mask_feather=0, scheduler_func_opt=None):
|
denoise, basic_pipe, refiner_ratio=None, refiner_basic_pipe_opt=None, noise_mask_feather=0, scheduler_func_opt=None):
|
||||||
@@ -60,7 +62,7 @@ class SEGSDetailerForAnimateDiff:
|
|||||||
new_segs = []
|
new_segs = []
|
||||||
cnet_image_list = []
|
cnet_image_list = []
|
||||||
|
|
||||||
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]
|
model = nodes_differential_diffusion.DifferentialDiffusion().apply(model)[0]
|
||||||
|
|
||||||
for seg in segs[1]:
|
for seg in segs[1]:
|
||||||
@@ -94,13 +96,18 @@ class SEGSDetailerForAnimateDiff:
|
|||||||
for condition, details in negative
|
for condition, details in negative
|
||||||
]
|
]
|
||||||
|
|
||||||
enhanced_image_tensor, cnet_images = core.enhance_detail_for_animatediff(cropped_image_frames, model, clip, vae, guide_size, guide_size_for, max_size,
|
if not (isinstance(model, str) and model == "DUMMY"):
|
||||||
seg.bbox, seed, steps, cfg, sampler_name, scheduler,
|
enhanced_image_tensor, cnet_images = core.enhance_detail_for_animatediff(cropped_image_frames, model, clip, vae, guide_size, guide_size_for, max_size,
|
||||||
cropped_positive, cropped_negative, denoise, seg.cropped_mask,
|
seg.bbox, seed, steps, cfg, sampler_name, scheduler,
|
||||||
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
cropped_positive, cropped_negative, denoise, seg.cropped_mask,
|
||||||
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
|
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
||||||
refiner_negative=refiner_negative, control_net_wrapper=seg.control_net_wrapper,
|
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
|
||||||
noise_mask_feather=noise_mask_feather, scheduler_func=scheduler_func_opt)
|
refiner_negative=refiner_negative, control_net_wrapper=seg.control_net_wrapper,
|
||||||
|
noise_mask_feather=noise_mask_feather, scheduler_func=scheduler_func_opt)
|
||||||
|
else:
|
||||||
|
enhanced_image_tensor = cropped_image_frames
|
||||||
|
cnet_images = None
|
||||||
|
|
||||||
if cnet_images is not None:
|
if cnet_images is not None:
|
||||||
cnet_image_list.extend(cnet_images)
|
cnet_image_list.extend(cnet_images)
|
||||||
|
|
||||||
@@ -143,7 +150,7 @@ class DetailerForEachPipeForAnimateDiff:
|
|||||||
"scheduler": (core.SCHEDULERS,),
|
"scheduler": (core.SCHEDULERS,),
|
||||||
"denoise": ("FLOAT", {"default": 0.5, "min": 0.0001, "max": 1.0, "step": 0.01}),
|
"denoise": ("FLOAT", {"default": 0.5, "min": 0.0001, "max": 1.0, "step": 0.01}),
|
||||||
"feather": ("INT", {"default": 5, "min": 0, "max": 100, "step": 1}),
|
"feather": ("INT", {"default": 5, "min": 0, "max": 100, "step": 1}),
|
||||||
"basic_pipe": ("BASIC_PIPE", ),
|
"basic_pipe": ("BASIC_PIPE", {"tooltip": "If the `ImpactDummyInput` is connected to the model in the basic_pipe, the inference stage is skipped."}),
|
||||||
"refiner_ratio": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0}),
|
"refiner_ratio": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0}),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
@@ -161,6 +168,8 @@ class DetailerForEachPipeForAnimateDiff:
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Detailer"
|
CATEGORY = "ImpactPack/Detailer"
|
||||||
|
|
||||||
|
DESCRIPTION = "This node enhances details by inpainting each region within the detected area bundle (SEGS) after enlarging them based on the guide size.\nThis node is a specialized detailer node for enhancing video details, such as in AnimateDiff. It can handle cases where the masks contained in SEGS serve as batch masks spanning multiple frames."
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def doit(image_frames, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
def doit(image_frames, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
||||||
denoise, feather, basic_pipe, refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None,
|
denoise, feather, basic_pipe, refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import configparser
|
import configparser
|
||||||
import os
|
import os
|
||||||
|
|
||||||
version_code = [8, 3]
|
version_code = [8, 8]
|
||||||
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 = 24
|
dependency_version = 24
|
||||||
|
|||||||
+15
-8
@@ -244,7 +244,8 @@ def enhance_detail(image, model, clip, vae, guide_size, guide_size_for_bbox, max
|
|||||||
detailer_hook=None,
|
detailer_hook=None,
|
||||||
refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None,
|
refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None,
|
||||||
refiner_negative=None, control_net_wrapper=None, cycle=1,
|
refiner_negative=None, control_net_wrapper=None, cycle=1,
|
||||||
inpaint_model=False, noise_mask_feather=0, scheduler_func=None):
|
inpaint_model=False, noise_mask_feather=0, scheduler_func=None,
|
||||||
|
vae_tiled_encode=False, vae_tiled_decode=False):
|
||||||
|
|
||||||
if noise_mask is not None:
|
if noise_mask is not None:
|
||||||
noise_mask = utils.tensor_gaussian_blur_mask(noise_mask, noise_mask_feather)
|
noise_mask = utils.tensor_gaussian_blur_mask(noise_mask, noise_mask_feather)
|
||||||
@@ -334,7 +335,7 @@ def enhance_detail(image, model, clip, vae, guide_size, guide_size_for_bbox, max
|
|||||||
print(f"[Impact Pack] ComfyUI is an outdated version.")
|
print(f"[Impact Pack] ComfyUI is an outdated version.")
|
||||||
positive, negative, latent_image = imc_encode(positive, negative, upscaled_image, vae, noise_mask)
|
positive, negative, latent_image = imc_encode(positive, negative, upscaled_image, vae, noise_mask)
|
||||||
else:
|
else:
|
||||||
latent_image = to_latent_image(upscaled_image, vae)
|
latent_image = to_latent_image(upscaled_image, vae, vae_tiled_encode=vae_tiled_encode)
|
||||||
if noise_mask is not None:
|
if noise_mask is not None:
|
||||||
latent_image['noise_mask'] = noise_mask
|
latent_image['noise_mask'] = noise_mask
|
||||||
|
|
||||||
@@ -369,12 +370,18 @@ def enhance_detail(image, model, clip, vae, guide_size, guide_size_for_bbox, max
|
|||||||
refined_latent = detailer_hook.pre_decode(refined_latent)
|
refined_latent = detailer_hook.pre_decode(refined_latent)
|
||||||
|
|
||||||
# non-latent downscale - latent downscale cause bad quality
|
# non-latent downscale - latent downscale cause bad quality
|
||||||
try:
|
start = time.time()
|
||||||
# try to decode image normally
|
if vae_tiled_decode:
|
||||||
refined_image = vae.decode(refined_latent['samples'])
|
(refined_image,) = nodes.VAEDecodeTiled().decode(vae, refined_latent, 512) # using default settings
|
||||||
except Exception as e:
|
print(f"[Impact Pack] vae decoded (tiled) in {time.time() - start:.1f}s")
|
||||||
#usually an out-of-memory exception from the decode, so try a tiled approach
|
else:
|
||||||
refined_image = vae.decode_tiled(refined_latent["samples"], tile_x=64, tile_y=64, )
|
try:
|
||||||
|
refined_image = vae.decode(refined_latent['samples'])
|
||||||
|
except Exception as e:
|
||||||
|
# usually an out-of-memory exception from the decode, so try a tiled approach
|
||||||
|
print(f"[Impact Pack] failed after {time.time() - start:.1f}s, doing vae.decode_tiled 64...")
|
||||||
|
refined_image = vae.decode_tiled(refined_latent["samples"], tile_x=64, tile_y=64, )
|
||||||
|
print(f"[Impact Pack] vae decoded in {time.time() - start:.1f}s")
|
||||||
|
|
||||||
if detailer_hook is not None:
|
if detailer_hook is not None:
|
||||||
refined_image = detailer_hook.post_decode(refined_image)
|
refined_image = detailer_hook.post_decode(refined_image)
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ class DetailerForEach:
|
|||||||
return {"required": {
|
return {"required": {
|
||||||
"image": ("IMAGE", ),
|
"image": ("IMAGE", ),
|
||||||
"segs": ("SEGS", ),
|
"segs": ("SEGS", ),
|
||||||
"model": ("MODEL",),
|
"model": ("MODEL", {"tooltip": "If the `ImpactDummyInput` is connected to the model, the inference stage is skipped."}),
|
||||||
"clip": ("CLIP",),
|
"clip": ("CLIP",),
|
||||||
"vae": ("VAE",),
|
"vae": ("VAE",),
|
||||||
"guide_size": ("FLOAT", {"default": 512, "min": 64, "max": nodes.MAX_RESOLUTION, "step": 8}),
|
"guide_size": ("FLOAT", {"default": 512, "min": 64, "max": nodes.MAX_RESOLUTION, "step": 8}),
|
||||||
@@ -218,6 +218,8 @@ class DetailerForEach:
|
|||||||
"inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
"inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
"noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}),
|
"noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}),
|
||||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||||
|
"tiled_encode": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
|
"tiled_decode": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,6 +228,8 @@ class DetailerForEach:
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Detailer"
|
CATEGORY = "ImpactPack/Detailer"
|
||||||
|
|
||||||
|
DESCRIPTION = "It enhances details by inpainting each region within the detected area bundle (SEGS) after enlarging them based on the guide size."
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_core_module():
|
def get_core_module():
|
||||||
return core
|
return core
|
||||||
@@ -234,7 +238,7 @@ class DetailerForEach:
|
|||||||
def do_detail(image, segs, model, clip, vae, guide_size, guide_size_for_bbox, max_size, seed, steps, cfg, sampler_name, scheduler,
|
def do_detail(image, segs, model, clip, vae, guide_size, guide_size_for_bbox, max_size, seed, steps, cfg, sampler_name, scheduler,
|
||||||
positive, negative, denoise, feather, noise_mask, force_inpaint, wildcard_opt=None, detailer_hook=None,
|
positive, negative, denoise, feather, noise_mask, force_inpaint, wildcard_opt=None, detailer_hook=None,
|
||||||
refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None, refiner_negative=None,
|
refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None, refiner_negative=None,
|
||||||
cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None):
|
cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None, tiled_encode=False, tiled_decode=False):
|
||||||
|
|
||||||
if len(image) > 1:
|
if len(image) > 1:
|
||||||
raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.')
|
raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.')
|
||||||
@@ -338,7 +342,8 @@ class DetailerForEach:
|
|||||||
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
|
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
|
||||||
refiner_negative=refiner_negative, control_net_wrapper=seg.control_net_wrapper,
|
refiner_negative=refiner_negative, control_net_wrapper=seg.control_net_wrapper,
|
||||||
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather,
|
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather,
|
||||||
scheduler_func=scheduler_func_opt)
|
scheduler_func=scheduler_func_opt, vae_tiled_encode=tiled_encode,
|
||||||
|
vae_tiled_decode=tiled_decode)
|
||||||
else:
|
else:
|
||||||
enhanced_image = cropped_image
|
enhanced_image = cropped_image
|
||||||
cnet_pils = None
|
cnet_pils = None
|
||||||
@@ -384,13 +389,15 @@ class DetailerForEach:
|
|||||||
|
|
||||||
def doit(self, image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name,
|
def doit(self, image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name,
|
||||||
scheduler, positive, negative, denoise, feather, noise_mask, force_inpaint, wildcard, cycle=1,
|
scheduler, positive, negative, denoise, feather, noise_mask, force_inpaint, wildcard, cycle=1,
|
||||||
detailer_hook=None, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None):
|
detailer_hook=None, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None,
|
||||||
|
tiled_encode=False, tiled_decode=False):
|
||||||
|
|
||||||
enhanced_img, *_ = \
|
enhanced_img, *_ = \
|
||||||
DetailerForEach.do_detail(image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps,
|
DetailerForEach.do_detail(image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps,
|
||||||
cfg, sampler_name, scheduler, positive, negative, denoise, feather, noise_mask,
|
cfg, sampler_name, scheduler, positive, negative, denoise, feather, noise_mask,
|
||||||
force_inpaint, wildcard, detailer_hook,
|
force_inpaint, wildcard, detailer_hook,
|
||||||
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt)
|
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather,
|
||||||
|
scheduler_func_opt=scheduler_func_opt, tiled_encode=tiled_encode, tiled_decode=tiled_decode)
|
||||||
|
|
||||||
return (enhanced_img, )
|
return (enhanced_img, )
|
||||||
|
|
||||||
@@ -413,7 +420,7 @@ class DetailerForEachPipe:
|
|||||||
"feather": ("INT", {"default": 5, "min": 0, "max": 100, "step": 1}),
|
"feather": ("INT", {"default": 5, "min": 0, "max": 100, "step": 1}),
|
||||||
"noise_mask": ("BOOLEAN", {"default": True, "label_on": "enabled", "label_off": "disabled"}),
|
"noise_mask": ("BOOLEAN", {"default": True, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
"force_inpaint": ("BOOLEAN", {"default": True, "label_on": "enabled", "label_off": "disabled"}),
|
"force_inpaint": ("BOOLEAN", {"default": True, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
"basic_pipe": ("BASIC_PIPE", ),
|
"basic_pipe": ("BASIC_PIPE", {"tooltip": "If the `ImpactDummyInput` is connected to the model in the basic_pipe, the inference stage is skipped."}),
|
||||||
"wildcard": ("STRING", {"multiline": True, "dynamicPrompts": False}),
|
"wildcard": ("STRING", {"multiline": True, "dynamicPrompts": False}),
|
||||||
"refiner_ratio": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0}),
|
"refiner_ratio": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0}),
|
||||||
|
|
||||||
@@ -425,6 +432,8 @@ class DetailerForEachPipe:
|
|||||||
"inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
"inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
"noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}),
|
"noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}),
|
||||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||||
|
"tiled_encode": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
|
"tiled_decode": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,10 +444,13 @@ class DetailerForEachPipe:
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Detailer"
|
CATEGORY = "ImpactPack/Detailer"
|
||||||
|
|
||||||
|
DESCRIPTION = DetailerForEach.DESCRIPTION
|
||||||
|
|
||||||
def doit(self, image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
def doit(self, image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
||||||
denoise, feather, noise_mask, force_inpaint, basic_pipe, wildcard,
|
denoise, feather, noise_mask, force_inpaint, basic_pipe, wildcard,
|
||||||
refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None,
|
refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None,
|
||||||
cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None):
|
cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None,
|
||||||
|
tiled_encode=False, tiled_decode=False):
|
||||||
|
|
||||||
if len(image) > 1:
|
if len(image) > 1:
|
||||||
raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.')
|
raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.')
|
||||||
@@ -456,7 +468,8 @@ class DetailerForEachPipe:
|
|||||||
force_inpaint, wildcard, detailer_hook,
|
force_inpaint, wildcard, detailer_hook,
|
||||||
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
||||||
refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative,
|
refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative,
|
||||||
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt)
|
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt,
|
||||||
|
tiled_encode=tiled_encode, tiled_decode=tiled_decode)
|
||||||
|
|
||||||
# set fallback image
|
# set fallback image
|
||||||
if len(cnet_pil_list) == 0:
|
if len(cnet_pil_list) == 0:
|
||||||
@@ -470,7 +483,7 @@ class FaceDetailer:
|
|||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": {
|
return {"required": {
|
||||||
"image": ("IMAGE", ),
|
"image": ("IMAGE", ),
|
||||||
"model": ("MODEL",),
|
"model": ("MODEL", {"tooltip": "If the `ImpactDummyInput` is connected to the model, the inference stage is skipped."}),
|
||||||
"clip": ("CLIP",),
|
"clip": ("CLIP",),
|
||||||
"vae": ("VAE",),
|
"vae": ("VAE",),
|
||||||
"guide_size": ("FLOAT", {"default": 512, "min": 64, "max": nodes.MAX_RESOLUTION, "step": 8}),
|
"guide_size": ("FLOAT", {"default": 512, "min": 64, "max": nodes.MAX_RESOLUTION, "step": 8}),
|
||||||
@@ -513,6 +526,8 @@ class FaceDetailer:
|
|||||||
"inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
"inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
"noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}),
|
"noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}),
|
||||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||||
|
"tiled_encode": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
|
"tiled_decode": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
}}
|
}}
|
||||||
|
|
||||||
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", "MASK", "DETAILER_PIPE", "IMAGE")
|
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", "MASK", "DETAILER_PIPE", "IMAGE")
|
||||||
@@ -522,6 +537,8 @@ class FaceDetailer:
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Simple"
|
CATEGORY = "ImpactPack/Simple"
|
||||||
|
|
||||||
|
DESCRIPTION = "This node enhances details by automatically detecting specific objects in the input image using detection models (bbox, segm, sam) and regenerating the image by enlarging the detected area based on the guide size.\nAlthough this node is specialized to simplify the commonly used facial detail enhancement workflow, it can also be used for various automatic inpainting purposes depending on the detection model."
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def enhance_face(image, model, clip, vae, guide_size, guide_size_for_bbox, max_size, seed, steps, cfg, sampler_name, scheduler,
|
def enhance_face(image, model, clip, vae, guide_size, guide_size_for_bbox, max_size, seed, steps, cfg, sampler_name, scheduler,
|
||||||
positive, negative, denoise, feather, noise_mask, force_inpaint,
|
positive, negative, denoise, feather, noise_mask, force_inpaint,
|
||||||
@@ -530,7 +547,7 @@ class FaceDetailer:
|
|||||||
sam_mask_hint_use_negative, drop_size,
|
sam_mask_hint_use_negative, drop_size,
|
||||||
bbox_detector, segm_detector=None, sam_model_opt=None, wildcard_opt=None, detailer_hook=None,
|
bbox_detector, segm_detector=None, sam_model_opt=None, wildcard_opt=None, detailer_hook=None,
|
||||||
refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None, refiner_negative=None, cycle=1,
|
refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None, refiner_negative=None, cycle=1,
|
||||||
inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None):
|
inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None, tiled_encode=False, tiled_decode=False):
|
||||||
|
|
||||||
# make default prompt as 'face' if empty prompt for CLIPSeg
|
# make default prompt as 'face' if empty prompt for CLIPSeg
|
||||||
bbox_detector.setAux('face')
|
bbox_detector.setAux('face')
|
||||||
@@ -562,7 +579,8 @@ class FaceDetailer:
|
|||||||
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
||||||
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
|
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
|
||||||
refiner_negative=refiner_negative,
|
refiner_negative=refiner_negative,
|
||||||
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt)
|
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather,
|
||||||
|
scheduler_func_opt=scheduler_func_opt, tiled_encode=tiled_encode, tiled_decode=tiled_decode)
|
||||||
else:
|
else:
|
||||||
enhanced_img = image
|
enhanced_img = image
|
||||||
cropped_enhanced = []
|
cropped_enhanced = []
|
||||||
@@ -588,7 +606,8 @@ class FaceDetailer:
|
|||||||
bbox_threshold, bbox_dilation, bbox_crop_factor,
|
bbox_threshold, bbox_dilation, bbox_crop_factor,
|
||||||
sam_detection_hint, sam_dilation, sam_threshold, sam_bbox_expansion, sam_mask_hint_threshold,
|
sam_detection_hint, sam_dilation, sam_threshold, sam_bbox_expansion, sam_mask_hint_threshold,
|
||||||
sam_mask_hint_use_negative, drop_size, bbox_detector, wildcard, cycle=1,
|
sam_mask_hint_use_negative, drop_size, bbox_detector, wildcard, cycle=1,
|
||||||
sam_model_opt=None, segm_detector_opt=None, detailer_hook=None, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None):
|
sam_model_opt=None, segm_detector_opt=None, detailer_hook=None, inpaint_model=False, noise_mask_feather=0,
|
||||||
|
scheduler_func_opt=None, tiled_encode=False, tiled_decode=False):
|
||||||
|
|
||||||
result_img = None
|
result_img = None
|
||||||
result_mask = None
|
result_mask = None
|
||||||
@@ -606,7 +625,8 @@ class FaceDetailer:
|
|||||||
bbox_threshold, bbox_dilation, bbox_crop_factor,
|
bbox_threshold, bbox_dilation, bbox_crop_factor,
|
||||||
sam_detection_hint, sam_dilation, sam_threshold, sam_bbox_expansion, sam_mask_hint_threshold,
|
sam_detection_hint, sam_dilation, sam_threshold, sam_bbox_expansion, sam_mask_hint_threshold,
|
||||||
sam_mask_hint_use_negative, drop_size, bbox_detector, segm_detector_opt, sam_model_opt, wildcard, detailer_hook,
|
sam_mask_hint_use_negative, drop_size, bbox_detector, segm_detector_opt, sam_model_opt, wildcard, detailer_hook,
|
||||||
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt)
|
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt,
|
||||||
|
tiled_encode=tiled_encode, tiled_decode=tiled_decode)
|
||||||
|
|
||||||
result_img = torch.cat((result_img, enhanced_img), dim=0) if result_img is not None else enhanced_img
|
result_img = torch.cat((result_img, enhanced_img), dim=0) if result_img is not None else enhanced_img
|
||||||
result_mask = torch.cat((result_mask, mask), dim=0) if result_mask is not None else mask
|
result_mask = torch.cat((result_mask, mask), dim=0) if result_mask is not None else mask
|
||||||
@@ -1347,7 +1367,7 @@ class FaceDetailerPipe:
|
|||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": {
|
return {"required": {
|
||||||
"image": ("IMAGE", ),
|
"image": ("IMAGE", ),
|
||||||
"detailer_pipe": ("DETAILER_PIPE",),
|
"detailer_pipe": ("DETAILER_PIPE", {"tooltip": "If the `ImpactDummyInput` is connected to the model in the detailer_pipe, the inference stage is skipped."}),
|
||||||
"guide_size": ("FLOAT", {"default": 512, "min": 64, "max": nodes.MAX_RESOLUTION, "step": 8}),
|
"guide_size": ("FLOAT", {"default": 512, "min": 64, "max": nodes.MAX_RESOLUTION, "step": 8}),
|
||||||
"guide_size_for": ("BOOLEAN", {"default": True, "label_on": "bbox", "label_off": "crop_region"}),
|
"guide_size_for": ("BOOLEAN", {"default": True, "label_on": "bbox", "label_off": "crop_region"}),
|
||||||
"max_size": ("FLOAT", {"default": 1024, "min": 64, "max": nodes.MAX_RESOLUTION, "step": 8}),
|
"max_size": ("FLOAT", {"default": 1024, "min": 64, "max": nodes.MAX_RESOLUTION, "step": 8}),
|
||||||
@@ -1381,6 +1401,8 @@ class FaceDetailerPipe:
|
|||||||
"inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
"inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
"noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}),
|
"noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}),
|
||||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||||
|
"tiled_encode": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
|
"tiled_decode": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1391,11 +1413,14 @@ class FaceDetailerPipe:
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Simple"
|
CATEGORY = "ImpactPack/Simple"
|
||||||
|
|
||||||
|
DESCRIPTION = FaceDetailer.DESCRIPTION
|
||||||
|
|
||||||
def doit(self, image, detailer_pipe, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
def doit(self, image, detailer_pipe, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
||||||
denoise, feather, noise_mask, force_inpaint, bbox_threshold, bbox_dilation, bbox_crop_factor,
|
denoise, feather, noise_mask, force_inpaint, bbox_threshold, bbox_dilation, bbox_crop_factor,
|
||||||
sam_detection_hint, sam_dilation, sam_threshold, sam_bbox_expansion,
|
sam_detection_hint, sam_dilation, sam_threshold, sam_bbox_expansion,
|
||||||
sam_mask_hint_threshold, sam_mask_hint_use_negative, drop_size, refiner_ratio=None,
|
sam_mask_hint_threshold, sam_mask_hint_use_negative, drop_size, refiner_ratio=None,
|
||||||
cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None):
|
cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None,
|
||||||
|
tiled_encode=False, tiled_decode=False):
|
||||||
|
|
||||||
result_img = None
|
result_img = None
|
||||||
result_mask = None
|
result_mask = None
|
||||||
@@ -1418,7 +1443,8 @@ class FaceDetailerPipe:
|
|||||||
sam_mask_hint_use_negative, drop_size, bbox_detector, segm_detector, sam_model_opt, wildcard, detailer_hook,
|
sam_mask_hint_use_negative, drop_size, bbox_detector, segm_detector, sam_model_opt, wildcard, detailer_hook,
|
||||||
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
||||||
refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative,
|
refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative,
|
||||||
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt)
|
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt,
|
||||||
|
tiled_encode=tiled_encode, tiled_decode=tiled_decode)
|
||||||
|
|
||||||
result_img = torch.cat((result_img, enhanced_img), dim=0) if result_img is not None else enhanced_img
|
result_img = torch.cat((result_img, enhanced_img), dim=0) if result_img is not None else enhanced_img
|
||||||
result_mask = torch.cat((result_mask, mask), dim=0) if result_mask is not None else mask
|
result_mask = torch.cat((result_mask, mask), dim=0) if result_mask is not None else mask
|
||||||
@@ -1484,6 +1510,8 @@ class MaskDetailerPipe:
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Detailer"
|
CATEGORY = "ImpactPack/Detailer"
|
||||||
|
|
||||||
|
DESCRIPTION = ""
|
||||||
|
|
||||||
def doit(self, image, mask, basic_pipe, guide_size, guide_size_for, max_size, mask_mode,
|
def doit(self, image, mask, basic_pipe, guide_size, guide_size_for, max_size, mask_mode,
|
||||||
seed, steps, cfg, sampler_name, scheduler, denoise,
|
seed, steps, cfg, sampler_name, scheduler, denoise,
|
||||||
feather, crop_factor, drop_size, refiner_ratio, batch_size, cycle=1,
|
feather, crop_factor, drop_size, refiner_ratio, batch_size, cycle=1,
|
||||||
@@ -1552,7 +1580,7 @@ class DetailerForEachTest(DetailerForEach):
|
|||||||
|
|
||||||
def doit(self, image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name,
|
def doit(self, image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name,
|
||||||
scheduler, positive, negative, denoise, feather, noise_mask, force_inpaint, wildcard, detailer_hook=None,
|
scheduler, positive, negative, denoise, feather, noise_mask, force_inpaint, wildcard, detailer_hook=None,
|
||||||
cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None):
|
cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None, tiled_encode=False, tiled_decode=False):
|
||||||
|
|
||||||
if len(image) > 1:
|
if len(image) > 1:
|
||||||
raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.')
|
raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.')
|
||||||
@@ -1561,7 +1589,8 @@ class DetailerForEachTest(DetailerForEach):
|
|||||||
DetailerForEach.do_detail(image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps,
|
DetailerForEach.do_detail(image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps,
|
||||||
cfg, sampler_name, scheduler, positive, negative, denoise, feather, noise_mask,
|
cfg, sampler_name, scheduler, positive, negative, denoise, feather, noise_mask,
|
||||||
force_inpaint, wildcard, detailer_hook,
|
force_inpaint, wildcard, detailer_hook,
|
||||||
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt)
|
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather,
|
||||||
|
scheduler_func_opt=scheduler_func_opt, tiled_encode=tiled_encode, tiled_decode=tiled_decode)
|
||||||
|
|
||||||
# set fallback image
|
# set fallback image
|
||||||
if len(cropped) == 0:
|
if len(cropped) == 0:
|
||||||
@@ -1588,9 +1617,12 @@ class DetailerForEachTestPipe(DetailerForEachPipe):
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Detailer"
|
CATEGORY = "ImpactPack/Detailer"
|
||||||
|
|
||||||
|
DESCRIPTION = DetailerForEach.DESCRIPTION
|
||||||
|
|
||||||
def doit(self, image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
def doit(self, image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
||||||
denoise, feather, noise_mask, force_inpaint, basic_pipe, wildcard, cycle=1,
|
denoise, feather, noise_mask, force_inpaint, basic_pipe, wildcard, cycle=1,
|
||||||
refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None):
|
refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None, inpaint_model=False, noise_mask_feather=0,
|
||||||
|
scheduler_func_opt=None, tiled_encode=False, tiled_decode=False):
|
||||||
|
|
||||||
if len(image) > 1:
|
if len(image) > 1:
|
||||||
raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.')
|
raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.')
|
||||||
@@ -1609,7 +1641,8 @@ class DetailerForEachTestPipe(DetailerForEachPipe):
|
|||||||
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
||||||
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
|
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
|
||||||
refiner_negative=refiner_negative,
|
refiner_negative=refiner_negative,
|
||||||
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt)
|
cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather,
|
||||||
|
scheduler_func_opt=scheduler_func_opt, tiled_encode=tiled_encode, tiled_decode=tiled_decode)
|
||||||
|
|
||||||
# set fallback image
|
# set fallback image
|
||||||
if len(cropped) == 0:
|
if len(cropped) == 0:
|
||||||
@@ -2322,7 +2355,11 @@ class ImpactWildcardProcessor:
|
|||||||
return {"required": {
|
return {"required": {
|
||||||
"wildcard_text": ("STRING", {"multiline": True, "dynamicPrompts": False, "tooltip": "Enter a prompt using wildcard syntax."}),
|
"wildcard_text": ("STRING", {"multiline": True, "dynamicPrompts": False, "tooltip": "Enter a prompt using wildcard syntax."}),
|
||||||
"populated_text": ("STRING", {"multiline": True, "dynamicPrompts": False, "tooltip": "The actual value passed during the execution of 'ImpactWildcardProcessor' is what is shown here. The behavior varies slightly depending on the mode. Wildcard syntax can also be used in 'populated_text'."}),
|
"populated_text": ("STRING", {"multiline": True, "dynamicPrompts": False, "tooltip": "The actual value passed during the execution of 'ImpactWildcardProcessor' is what is shown here. The behavior varies slightly depending on the mode. Wildcard syntax can also be used in 'populated_text'."}),
|
||||||
"mode": ("BOOLEAN", {"default": True, "label_on": "Populate", "label_off": "Fixed", "tooltip": "Populate: Before running the workflow, it overwrites the existing value of 'populated_text' with the prompt processed from 'wildcard_text'. In this mode, 'populated_text' cannot be edited.\nFixed: Ignores wildcard_text and keeps 'populated_text' as is. You can edit 'populated_text' in this mode."}),
|
"mode": (["populate", "fixed", "reproduce"], {"default": "populate", "tooltip":
|
||||||
|
"populate: Before running the workflow, it overwrites the existing value of 'populated_text' with the prompt processed from 'wildcard_text'. In this mode, 'populated_text' cannot be edited.\n"
|
||||||
|
"fixed: Ignores wildcard_text and keeps 'populated_text' as is. You can edit 'populated_text' in this mode.\n"
|
||||||
|
"reproduce: This mode operates as 'fixed' mode only once for reproduction, and then it switches to 'populate' mode."
|
||||||
|
}),
|
||||||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff, "tooltip": "Determines the random seed to be used for wildcard processing."}),
|
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff, "tooltip": "Determines the random seed to be used for wildcard processing."}),
|
||||||
"Select to add Wildcard": (["Select the Wildcard to add to the text"],),
|
"Select to add Wildcard": (["Select the Wildcard to add to the text"],),
|
||||||
},
|
},
|
||||||
@@ -2331,9 +2368,10 @@ class ImpactWildcardProcessor:
|
|||||||
CATEGORY = "ImpactPack/Prompt"
|
CATEGORY = "ImpactPack/Prompt"
|
||||||
|
|
||||||
DESCRIPTION = ("The 'ImpactWildcardProcessor' processes text prompts written in wildcard syntax and outputs the processed text prompt.\n\n"
|
DESCRIPTION = ("The 'ImpactWildcardProcessor' processes text prompts written in wildcard syntax and outputs the processed text prompt.\n\n"
|
||||||
"TIP: Before the workflow is executed, the processing result of 'wildcard_text' is displayed in 'populated_text', and the populated text is saved along with the workflow. If you want to use a seed converted as input, write the prompt directly in 'populated_text' instead of 'wildcard_text', and set the mode to 'Fixed'.")
|
"TIP: Before the workflow is executed, the processing result of 'wildcard_text' is displayed in 'populated_text', and the populated text is saved along with the workflow. If you want to use a seed converted as input, write the prompt directly in 'populated_text' instead of 'wildcard_text', and set the mode to 'fixed'.")
|
||||||
|
|
||||||
RETURN_TYPES = ("STRING", )
|
RETURN_TYPES = ("STRING", )
|
||||||
|
RETURN_NAMES = ("processed text",)
|
||||||
FUNCTION = "doit"
|
FUNCTION = "doit"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -2353,8 +2391,10 @@ class ImpactWildcardEncode:
|
|||||||
"clip": ("CLIP",),
|
"clip": ("CLIP",),
|
||||||
"wildcard_text": ("STRING", {"multiline": True, "dynamicPrompts": False, "tooltip": "Enter a prompt using wildcard syntax."}),
|
"wildcard_text": ("STRING", {"multiline": True, "dynamicPrompts": False, "tooltip": "Enter a prompt using wildcard syntax."}),
|
||||||
"populated_text": ("STRING", {"multiline": True, "dynamicPrompts": False, "tooltip": "The actual value passed during the execution of 'ImpactWildcardEncode' is what is shown here. The behavior varies slightly depending on the mode. Wildcard syntax can also be used in 'populated_text'."}),
|
"populated_text": ("STRING", {"multiline": True, "dynamicPrompts": False, "tooltip": "The actual value passed during the execution of 'ImpactWildcardEncode' is what is shown here. The behavior varies slightly depending on the mode. Wildcard syntax can also be used in 'populated_text'."}),
|
||||||
"mode": ("BOOLEAN", {"default": True, "label_on": "Populate", "label_off": "Fixed", "tooltip": "Populate: Before running the workflow, it overwrites the existing value of 'populated_text' with the prompt processed from 'wildcard_text'. In this mode, 'populated_text' cannot be edited.\n"
|
"mode": (["populate", "fixed", "reproduce"], {"tooltip":
|
||||||
"Fixed: Ignores wildcard_text and keeps 'populated_text' as is. You can edit 'populated_text' in this mode."}),
|
"populate: Before running the workflow, it overwrites the existing value of 'populated_text' with the prompt processed from 'wildcard_text'. In this mode, 'populated_text' cannot be edited.\n"
|
||||||
|
"fixed: Ignores wildcard_text and keeps 'populated_text' as is. You can edit 'populated_text' in this mode\n."
|
||||||
|
"reproduce: This mode operates as 'fixed' mode only once for reproduction, and then it switches to 'populate' mode."}),
|
||||||
"Select to add LoRA": (["Select the LoRA to add to the text"] + folder_paths.get_filename_list("loras"), ),
|
"Select to add LoRA": (["Select the LoRA to add to the text"] + folder_paths.get_filename_list("loras"), ),
|
||||||
"Select to add Wildcard": (["Select the Wildcard to add to the text"], ),
|
"Select to add Wildcard": (["Select the Wildcard to add to the text"], ),
|
||||||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff, "tooltip": "Determines the random seed to be used for wildcard processing."}),
|
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff, "tooltip": "Determines the random seed to be used for wildcard processing."}),
|
||||||
@@ -2364,7 +2404,7 @@ class ImpactWildcardEncode:
|
|||||||
CATEGORY = "ImpactPack/Prompt"
|
CATEGORY = "ImpactPack/Prompt"
|
||||||
|
|
||||||
DESCRIPTION = ("The 'ImpactWildcardEncode' node processes text prompts written in wildcard syntax and outputs them as conditioning. It also supports LoRA syntax, with the applied LoRA reflected in the model's output.\n\n"
|
DESCRIPTION = ("The 'ImpactWildcardEncode' node processes text prompts written in wildcard syntax and outputs them as conditioning. It also supports LoRA syntax, with the applied LoRA reflected in the model's output.\n\n"
|
||||||
"TIP1: Before the workflow is executed, the processing result of 'wildcard_text' is displayed in 'populated_text', and the populated text is saved along with the workflow. If you want to use a seed converted as input, write the prompt directly in 'populated_text' instead of 'wildcard_text', and set the mode to 'Fixed'.\n"
|
"TIP1: Before the workflow is executed, the processing result of 'wildcard_text' is displayed in 'populated_text', and the populated text is saved along with the workflow. If you want to use a seed converted as input, write the prompt directly in 'populated_text' instead of 'wildcard_text', and set the mode to 'fixed'.\n"
|
||||||
"TIP2: If the 'Inspire Pack' is installed, LBW(LoRA Block Weight) syntax can also be applied.")
|
"TIP2: If the 'Inspire Pack' is installed, LBW(LoRA Block Weight) syntax can also be applied.")
|
||||||
|
|
||||||
RETURN_TYPES = ("MODEL", "CLIP", "CONDITIONING", "STRING")
|
RETURN_TYPES = ("MODEL", "CLIP", "CONDITIONING", "STRING")
|
||||||
|
|||||||
@@ -46,65 +46,27 @@ def get_noise_sampler(x, cpu, total_sigmas, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
def ksampler(sampler_name, total_sigmas, extra_options={}, inpaint_options={}):
|
def ksampler(sampler_name, total_sigmas, extra_options={}, inpaint_options={}):
|
||||||
if sampler_name == "dpmpp_sde":
|
if sampler_name in ["dpmpp_sde", "dpmpp_sde_gpu", "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", "dpmpp_3m_sde_gpu"]:
|
||||||
def sample_dpmpp_sde(model, x, sigmas, **kwargs):
|
if sampler_name == "dpmpp_sde":
|
||||||
noise_sampler = get_noise_sampler(x, True, total_sigmas, **kwargs)
|
orig_sampler_function = k_diffusion_sampling.sample_dpmpp_sde
|
||||||
if noise_sampler is not None:
|
elif sampler_name == "dpmpp_sde_gpu":
|
||||||
kwargs['noise_sampler'] = noise_sampler
|
orig_sampler_function = k_diffusion_sampling.sample_dpmpp_sde_gpu
|
||||||
|
elif sampler_name == "dpmpp_2m_sde":
|
||||||
|
orig_sampler_function = k_diffusion_sampling.sample_dpmpp_2m_sde
|
||||||
|
elif sampler_name == "dpmpp_2m_sde_gpu":
|
||||||
|
orig_sampler_function = k_diffusion_sampling.sample_dpmpp_2m_sde_gpu
|
||||||
|
elif sampler_name == "dpmpp_3m_sde":
|
||||||
|
orig_sampler_function = k_diffusion_sampling.sample_dpmpp_3m_sde
|
||||||
|
elif sampler_name == "dpmpp_3m_sde_gpu":
|
||||||
|
orig_sampler_function = k_diffusion_sampling.sample_dpmpp_3m_sde_gpu
|
||||||
|
|
||||||
return k_diffusion_sampling.sample_dpmpp_sde(model, x, sigmas, **kwargs)
|
def sampler_function_wrapper(model, x, sigmas, **kwargs):
|
||||||
|
if 'noise_sampler' not in kwargs:
|
||||||
|
kwargs['noise_sampler'] = get_noise_sampler(x, 'gpu' not in sampler_name, total_sigmas, **kwargs)
|
||||||
|
|
||||||
sampler_function = sample_dpmpp_sde
|
return orig_sampler_function(model, x, sigmas, **kwargs)
|
||||||
|
|
||||||
elif sampler_name == "dpmpp_sde_gpu":
|
sampler_function = sampler_function_wrapper
|
||||||
def sample_dpmpp_sde(model, x, sigmas, **kwargs):
|
|
||||||
noise_sampler = get_noise_sampler(x, False, total_sigmas, **kwargs)
|
|
||||||
if noise_sampler is not None:
|
|
||||||
kwargs['noise_sampler'] = noise_sampler
|
|
||||||
|
|
||||||
return k_diffusion_sampling.sample_dpmpp_sde_gpu(model, x, sigmas, **kwargs)
|
|
||||||
|
|
||||||
sampler_function = sample_dpmpp_sde
|
|
||||||
|
|
||||||
elif sampler_name == "dpmpp_2m_sde":
|
|
||||||
def sample_dpmpp_sde(model, x, sigmas, **kwargs):
|
|
||||||
noise_sampler = get_noise_sampler(x, True, total_sigmas, **kwargs)
|
|
||||||
if noise_sampler is not None:
|
|
||||||
kwargs['noise_sampler'] = noise_sampler
|
|
||||||
|
|
||||||
return k_diffusion_sampling.sample_dpmpp_2m_sde(model, x, sigmas, **kwargs)
|
|
||||||
|
|
||||||
sampler_function = sample_dpmpp_sde
|
|
||||||
|
|
||||||
elif sampler_name == "dpmpp_2m_sde_gpu":
|
|
||||||
def sample_dpmpp_sde(model, x, sigmas, **kwargs):
|
|
||||||
noise_sampler = get_noise_sampler(x, False, total_sigmas, **kwargs)
|
|
||||||
if noise_sampler is not None:
|
|
||||||
kwargs['noise_sampler'] = noise_sampler
|
|
||||||
|
|
||||||
return k_diffusion_sampling.sample_dpmpp_2m_sde_gpu(model, x, sigmas, **kwargs)
|
|
||||||
|
|
||||||
sampler_function = sample_dpmpp_sde
|
|
||||||
|
|
||||||
elif sampler_name == "dpmpp_3m_sde":
|
|
||||||
def sample_dpmpp_sde(model, x, sigmas, **kwargs):
|
|
||||||
noise_sampler = get_noise_sampler(x, True, total_sigmas, **kwargs)
|
|
||||||
if noise_sampler is not None:
|
|
||||||
kwargs['noise_sampler'] = noise_sampler
|
|
||||||
|
|
||||||
return k_diffusion_sampling.sample_dpmpp_3m_sde(model, x, sigmas, **kwargs)
|
|
||||||
|
|
||||||
sampler_function = sample_dpmpp_sde
|
|
||||||
|
|
||||||
elif sampler_name == "dpmpp_3m_sde_gpu":
|
|
||||||
def sample_dpmpp_sde(model, x, sigmas, **kwargs):
|
|
||||||
noise_sampler = get_noise_sampler(x, False, total_sigmas, **kwargs)
|
|
||||||
if noise_sampler is not None:
|
|
||||||
kwargs['noise_sampler'] = noise_sampler
|
|
||||||
|
|
||||||
return k_diffusion_sampling.sample_dpmpp_3m_sde_gpu(model, x, sigmas, **kwargs)
|
|
||||||
|
|
||||||
sampler_function = sample_dpmpp_sde
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return comfy.samplers.sampler_object(sampler_name)
|
return comfy.samplers.sampler_object(sampler_name)
|
||||||
|
|||||||
@@ -78,9 +78,13 @@ async def sam_prepare(request):
|
|||||||
if data['sam_model_name'] == 'auto':
|
if data['sam_model_name'] == 'auto':
|
||||||
model_name = impact.config.get_config()['sam_editor_model']
|
model_name = impact.config.get_config()['sam_editor_model']
|
||||||
|
|
||||||
model_name = os.path.join(impact_pack.model_path, "sams", model_name)
|
model_path = folder_paths.get_full_path("sams", model_name)
|
||||||
|
|
||||||
logging.info(f"[Impact Pack] Loading SAM model '{impact_pack.model_path}'")
|
if model_path is None:
|
||||||
|
logging.error(f"[Impact Pack] The '{model_name}' model file cannot be found in any sams model path.")
|
||||||
|
return web.Response(status=400)
|
||||||
|
|
||||||
|
logging.info(f"[Impact Pack] Loading SAM model '{model_path}'")
|
||||||
|
|
||||||
filename, image_dir = folder_paths.annotated_filepath(data["filename"])
|
filename, image_dir = folder_paths.annotated_filepath(data["filename"])
|
||||||
|
|
||||||
@@ -93,7 +97,7 @@ async def sam_prepare(request):
|
|||||||
if image_dir is None:
|
if image_dir is None:
|
||||||
return web.Response(status=400)
|
return web.Response(status=400)
|
||||||
|
|
||||||
thread = threading.Thread(target=async_prepare_sam, args=(image_dir, model_name, filename,))
|
thread = threading.Thread(target=async_prepare_sam, args=(image_dir, model_path, filename,))
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
logging.info("[Impact Pack] SAM model loaded. ")
|
logging.info("[Impact Pack] SAM model loaded. ")
|
||||||
@@ -478,7 +482,17 @@ def onprompt_populate_wildcards(json_data):
|
|||||||
for k, v in prompt.items():
|
for k, v in prompt.items():
|
||||||
if 'class_type' in v and (v['class_type'] == 'ImpactWildcardEncode' or v['class_type'] == 'ImpactWildcardProcessor'):
|
if 'class_type' in v and (v['class_type'] == 'ImpactWildcardEncode' or v['class_type'] == 'ImpactWildcardProcessor'):
|
||||||
inputs = v['inputs']
|
inputs = v['inputs']
|
||||||
if inputs['mode'] and isinstance(inputs['populated_text'], str):
|
|
||||||
|
# legacy adapter
|
||||||
|
if isinstance(inputs['mode'], bool):
|
||||||
|
if inputs['mode']:
|
||||||
|
new_mode = 'populate'
|
||||||
|
else:
|
||||||
|
new_mode = 'fixed'
|
||||||
|
|
||||||
|
inputs['mode'] = new_mode
|
||||||
|
|
||||||
|
if inputs['mode'] == 'populate' and isinstance(inputs['populated_text'], str):
|
||||||
if isinstance(inputs['seed'], list):
|
if isinstance(inputs['seed'], list):
|
||||||
try:
|
try:
|
||||||
input_node = prompt[inputs['seed'][0]]
|
input_node = prompt[inputs['seed'][0]]
|
||||||
@@ -499,17 +513,22 @@ def onprompt_populate_wildcards(json_data):
|
|||||||
input_seed = int(inputs['seed'])
|
input_seed = int(inputs['seed'])
|
||||||
|
|
||||||
inputs['populated_text'] = wildcards.process(inputs['wildcard_text'], input_seed)
|
inputs['populated_text'] = wildcards.process(inputs['wildcard_text'], input_seed)
|
||||||
inputs['mode'] = False
|
inputs['mode'] = 'reproduce'
|
||||||
|
|
||||||
PromptServer.instance.send_sync("impact-node-feedback", {"node_id": k, "widget_name": "populated_text", "type": "STRING", "value": inputs['populated_text']})
|
PromptServer.instance.send_sync("impact-node-feedback", {"node_id": k, "widget_name": "populated_text", "type": "STRING", "value": inputs['populated_text']})
|
||||||
updated_widget_values[k] = inputs['populated_text']
|
updated_widget_values[k] = inputs['populated_text']
|
||||||
|
|
||||||
|
if inputs['mode'] == 'reproduce':
|
||||||
|
PromptServer.instance.send_sync("impact-node-feedback", {"node_id": k, "widget_name": "mode", "type": "STRING", "value": 'populate'})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if 'extra_data' in json_data and 'extra_pnginfo' in json_data['extra_data']:
|
if 'extra_data' in json_data and 'extra_pnginfo' in json_data['extra_data']:
|
||||||
for node in json_data['extra_data']['extra_pnginfo']['workflow']['nodes']:
|
for node in json_data['extra_data']['extra_pnginfo']['workflow']['nodes']:
|
||||||
key = str(node['id'])
|
key = str(node['id'])
|
||||||
if key in updated_widget_values:
|
if key in updated_widget_values:
|
||||||
node['widgets_values'][1] = updated_widget_values[key]
|
node['widgets_values'][1] = updated_widget_values[key]
|
||||||
node['widgets_values'][2] = False
|
node['widgets_values'][2] = 'reproduce'
|
||||||
|
|
||||||
|
|
||||||
def onprompt_for_remote(json_data):
|
def onprompt_for_remote(json_data):
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class SEGSDetailer:
|
|||||||
"denoise": ("FLOAT", {"default": 0.5, "min": 0.0001, "max": 1.0, "step": 0.01}),
|
"denoise": ("FLOAT", {"default": 0.5, "min": 0.0001, "max": 1.0, "step": 0.01}),
|
||||||
"noise_mask": ("BOOLEAN", {"default": True, "label_on": "enabled", "label_off": "disabled"}),
|
"noise_mask": ("BOOLEAN", {"default": True, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
"force_inpaint": ("BOOLEAN", {"default": True, "label_on": "enabled", "label_off": "disabled"}),
|
"force_inpaint": ("BOOLEAN", {"default": True, "label_on": "enabled", "label_off": "disabled"}),
|
||||||
"basic_pipe": ("BASIC_PIPE",),
|
"basic_pipe": ("BASIC_PIPE", {"tooltip": "If the `ImpactDummyInput` is connected to the model in the basic_pipe, the inference stage is skipped."}),
|
||||||
"refiner_ratio": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0}),
|
"refiner_ratio": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0}),
|
||||||
"batch_size": ("INT", {"default": 1, "min": 1, "max": 100}),
|
"batch_size": ("INT", {"default": 1, "min": 1, "max": 100}),
|
||||||
|
|
||||||
@@ -60,6 +60,8 @@ class SEGSDetailer:
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Detailer"
|
CATEGORY = "ImpactPack/Detailer"
|
||||||
|
|
||||||
|
DESCRIPTION = "This node enhances details by inpainting each region within the detected area bundle (SEGS) after enlarging them based on the guide size.\nThis node is applied specifically to SEGS rather than the entire image. To apply it to the entire image, use the 'SEGS Paste' node."
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def do_detail(image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
def do_detail(image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
|
||||||
denoise, noise_mask, force_inpaint, basic_pipe, refiner_ratio=None, batch_size=1, cycle=1,
|
denoise, noise_mask, force_inpaint, basic_pipe, refiner_ratio=None, batch_size=1, cycle=1,
|
||||||
@@ -76,7 +78,7 @@ class SEGSDetailer:
|
|||||||
new_segs = []
|
new_segs = []
|
||||||
cnet_pil_list = []
|
cnet_pil_list = []
|
||||||
|
|
||||||
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]
|
model = nodes_differential_diffusion.DifferentialDiffusion().apply(model)[0]
|
||||||
|
|
||||||
for i in range(batch_size):
|
for i in range(batch_size):
|
||||||
@@ -113,13 +115,17 @@ class SEGSDetailer:
|
|||||||
for condition, details in negative
|
for condition, details in negative
|
||||||
]
|
]
|
||||||
|
|
||||||
enhanced_image, cnet_pils = core.enhance_detail(cropped_image, model, clip, vae, guide_size, guide_size_for, max_size,
|
if not (isinstance(model, str) and model == "DUMMY"):
|
||||||
seg.bbox, seed, steps, cfg, sampler_name, scheduler,
|
enhanced_image, cnet_pils = core.enhance_detail(cropped_image, model, clip, vae, guide_size, guide_size_for, max_size,
|
||||||
cropped_positive, cropped_negative, denoise, cropped_mask, force_inpaint,
|
seg.bbox, seed, steps, cfg, sampler_name, scheduler,
|
||||||
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
cropped_positive, cropped_negative, denoise, cropped_mask, force_inpaint,
|
||||||
refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative,
|
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
|
||||||
control_net_wrapper=seg.control_net_wrapper, cycle=cycle,
|
refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative,
|
||||||
inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func=scheduler_func_opt)
|
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:
|
if cnet_pils is not None:
|
||||||
cnet_pil_list.extend(cnet_pils)
|
cnet_pil_list.extend(cnet_pils)
|
||||||
@@ -170,6 +176,8 @@ class SEGSPaste:
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Detailer"
|
CATEGORY = "ImpactPack/Detailer"
|
||||||
|
|
||||||
|
DESCRIPTION = "This node provides a function to paste the enhanced SEGS, improved through the SEGS detailer, back onto the original image."
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def doit(image, segs, feather, alpha=255, ref_image_opt=None):
|
def doit(image, segs, feather, alpha=255, ref_image_opt=None):
|
||||||
|
|
||||||
@@ -1482,6 +1490,8 @@ class SEGSPicker:
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Util"
|
CATEGORY = "ImpactPack/Util"
|
||||||
|
|
||||||
|
DESCRIPTION = "This node provides a function to select only the chosen SEGS from the input SEGS."
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def doit(picks, segs, fallback_image_opt=None, unique_id=None):
|
def doit(picks, segs, fallback_image_opt=None, unique_id=None):
|
||||||
if fallback_image_opt is not None:
|
if fallback_image_opt is not None:
|
||||||
@@ -1538,6 +1548,8 @@ class DefaultImageForSEGS:
|
|||||||
|
|
||||||
CATEGORY = "ImpactPack/Util"
|
CATEGORY = "ImpactPack/Util"
|
||||||
|
|
||||||
|
DESCRIPTION = "If the SEGS have not passed through the detailer, they contain only detection area information without an image. This node sets a default image for the SEGS."
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def doit(segs, image, override):
|
def doit(segs, image, override):
|
||||||
results = []
|
results = []
|
||||||
|
|||||||
+10
-3
@@ -7,6 +7,7 @@ import nodes
|
|||||||
from . import config
|
from . import config
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import comfy
|
import comfy
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
class TensorBatchBuilder:
|
class TensorBatchBuilder:
|
||||||
@@ -501,15 +502,21 @@ def crop_image(image, crop_region):
|
|||||||
return crop_tensor4(image, crop_region)
|
return crop_tensor4(image, crop_region)
|
||||||
|
|
||||||
|
|
||||||
def to_latent_image(pixels, vae):
|
def to_latent_image(pixels, vae, vae_tiled_encode=False):
|
||||||
x = pixels.shape[1]
|
x = pixels.shape[1]
|
||||||
y = pixels.shape[2]
|
y = pixels.shape[2]
|
||||||
if pixels.shape[1] != x or pixels.shape[2] != y:
|
if pixels.shape[1] != x or pixels.shape[2] != y:
|
||||||
pixels = pixels[:, :x, :y, :]
|
pixels = pixels[:, :x, :y, :]
|
||||||
|
|
||||||
vae_encode = nodes.VAEEncode()
|
start = time.time()
|
||||||
|
if vae_tiled_encode:
|
||||||
|
encoded = nodes.VAEEncodeTiled().encode(vae, pixels, 512, overlap=64)[0] # using default settings
|
||||||
|
print(f"[Impact Pack] vae encoded (tiled) in {time.time() - start:.1f}s")
|
||||||
|
else:
|
||||||
|
encoded = nodes.VAEEncode().encode(vae, pixels)[0]
|
||||||
|
print(f"[Impact Pack] vae encoded in {time.time() - start:.1f}s")
|
||||||
|
|
||||||
return vae_encode.encode(vae, pixels)[0]
|
return encoded
|
||||||
|
|
||||||
|
|
||||||
def empty_pil_tensor(w=64, h=64):
|
def empty_pil_tensor(w=64, h=64):
|
||||||
|
|||||||
@@ -237,7 +237,23 @@ def process(text, seed=None):
|
|||||||
keyword = match.lower()
|
keyword = match.lower()
|
||||||
keyword = wildcard_normalize(keyword)
|
keyword = wildcard_normalize(keyword)
|
||||||
if keyword in local_wildcard_dict:
|
if keyword in local_wildcard_dict:
|
||||||
replacement = random_gen.choice(local_wildcard_dict[keyword])
|
# look for adjusted probability
|
||||||
|
adjusted_probabilities = []
|
||||||
|
total_prob = 0
|
||||||
|
options=local_wildcard_dict[keyword]
|
||||||
|
for option in options:
|
||||||
|
parts = option.split('::', 1)
|
||||||
|
if len(parts) == 2 and is_numeric_string(parts[0].strip()):
|
||||||
|
config_value = float(parts[0].strip())
|
||||||
|
else:
|
||||||
|
config_value = 1 # Default value if no configuration is provided
|
||||||
|
|
||||||
|
adjusted_probabilities.append(config_value)
|
||||||
|
total_prob += config_value
|
||||||
|
|
||||||
|
normalized_probabilities = [prob / total_prob for prob in adjusted_probabilities]
|
||||||
|
selected_item = random_gen.choice(options, p=normalized_probabilities, replace=False)
|
||||||
|
replacement = re.sub(r'^\s*[0-9.]+::', '', selected_item, 1)
|
||||||
replacements_found = True
|
replacements_found = True
|
||||||
string = string.replace(f"__{match}__", replacement, 1)
|
string = string.replace(f"__{match}__", replacement, 1)
|
||||||
elif '*' in keyword:
|
elif '*' in keyword:
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "comfyui-impact-pack"
|
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."
|
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.3"
|
version = "8.8"
|
||||||
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"]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user