feat: SDXL refiner support for Detailer

feat: controlnet for SEGS
fix: tile size bug
This commit is contained in:
Dr.Lt.Data
2023-09-02 01:49:07 +09:00
parent f58449d73b
commit b60522aee2
9 changed files with 2410 additions and 130 deletions
+5
View File
@@ -34,6 +34,9 @@ This custom node helps to conveniently enhance images through Detector, Detailer
* As a result, it outputs the `combined_mask`, which is a unified mask, and `batch_masks`, which are multiple masks grouped together in batch form.
* While `batch_masks` may not be completely separated, it provides functionality to perform some level of segmentation.
* Simple Detector (SEGS) - Operating primarily with `BBOX_DETECTOR`, and with the additional provision of `SAM_MODEL` or `SEGM_DETECTOR`, this node internally generates improved SEGS through mask operations on both *bbox* and *silhouette*. It serves as a convenient tool to simplify a somewhat intricate workflow.
* ControlNetApply (SEGS) - To apply ControlNet in SEGS, you need to use the Preprocessor Provider node from the Inspire Pack to utilize this node.
* Bitwise(SEGS & SEGS) - Performs a 'bitwise and' operation between two SEGS.
* Bitwise(SEGS - SEGS) - Subtracts one SEGS from another.
* Bitwise(SEGS & MASK) - Performs a bitwise AND operation between SEGS and MASK.
@@ -57,6 +60,8 @@ This custom node helps to conveniently enhance images through Detector, Detailer
* FaceDetailer - Easily detects faces and improves them.
* FaceDetailer (pipe) - Easily detects faces and improves them (for multipass).
* `FaceDetailer (SDXL/pipe), BasicPipe -> DetailerPipe (SDXL), Edit DetailerPipe (SDXL)` - These are pipe functions used in Detailer for utilizing the refiner model of SDXL.
* SEGSDetailer - Performs detailed work on SEGS without pasting it back onto the original image.
* SEGSPaste - Pastes the results of SEGS onto the original image.
* If `ref_image_opt` is present, the images contained within SEGS are ignored. Instead, the image within `ref_image_opt` corresponding to the crop area of SEGS is taken and pasted. The size of the image in `ref_image_opt` should be the same as the original image size.
+10
View File
@@ -121,15 +121,19 @@ NODE_CLASS_MAPPINGS = {
"FaceDetailerPipe": FaceDetailerPipe,
"ToDetailerPipe": ToDetailerPipe,
"ToDetailerPipeSDXL": ToDetailerPipeSDXL,
"FromDetailerPipe": FromDetailerPipe,
"FromDetailerPipe_v2": FromDetailerPipe_v2,
"FromDetailerPipeSDXL": FromDetailerPipe_SDXL,
"ToBasicPipe": ToBasicPipe,
"FromBasicPipe": FromBasicPipe,
"FromBasicPipe_v2": FromBasicPipe_v2,
"BasicPipeToDetailerPipe": BasicPipeToDetailerPipe,
"BasicPipeToDetailerPipeSDXL": BasicPipeToDetailerPipeSDXL,
"DetailerPipeToBasicPipe": DetailerPipeToBasicPipe,
"EditBasicPipe": EditBasicPipe,
"EditDetailerPipe": EditDetailerPipe,
"EditDetailerPipeSDXL": EditDetailerPipeSDXL,
"LatentPixelScale": LatentPixelScale,
"PixelKSampleUpscalerProvider": PixelKSampleUpscalerProvider,
@@ -163,6 +167,7 @@ NODE_CLASS_MAPPINGS = {
"ONNXDetectorSEGS": ONNXDetectorForEach,
"ImpactSimpleDetectorSEGS": SimpleDetectorForEach,
"ImpactSimpleDetectorSEGSPipe": SimpleDetectorForEachPipe,
"ImpactControlNetApplySEGS": ControlNetApplySEGS,
"BboxDetectorCombined_v2": BboxDetectorCombined,
"SegmDetectorCombined_v2": SegmDetectorCombined,
@@ -240,6 +245,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"ONNXDetectorSEGS": "ONNX Detector (SEGS)",
"ImpactSimpleDetectorSEGS": "Simple Detector (SEGS)",
"ImpactSimpleDetectorSEGSPipe": "Simple Detector (SEGS/pipe)",
"ImpactControlNetApplySEGS": "ControlNetApply (SEGS)",
"BboxDetectorCombined_v2": "BBOX Detector (combined)",
"SegmDetectorCombined_v2": "SEGM Detector (combined)",
@@ -260,6 +266,10 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"SAMDetectorSegmented": "SAMDetector (segmented)",
"FaceDetailerPipe": "FaceDetailer (pipe)",
"FromDetailerPipeSDXL": "FaceDetailer (SDXL/pipe)",
"BasicPipeToDetailerPipeSDXL": "BasicPipe -> DetailerPipe (SDXL)",
"EditDetailerPipeSDXL": "Edit DetailerPipe (SDXL)",
"BasicPipeToDetailerPipe": "BasicPipe -> DetailerPipe",
"DetailerPipeToBasicPipe": "DetailerPipe -> BasicPipe",
"EditBasicPipe": "Edit BasicPipe",
+6 -1
View File
@@ -312,7 +312,9 @@ app.registerExtension({
switch(node.comfyClass) {
case "ToDetailerPipe":
case "ToDetailerPipeSDXL":
case "BasicPipeToDetailerPipe":
case "BasicPipeToDetailerPipeSDXL":
case "EditDetailerPipe":
case "FaceDetailer":
case "DetailerForEach":
@@ -354,7 +356,8 @@ app.registerExtension({
});
}
if(node.comfyClass == "ImpactWildcardEncode" || node.comfyClass == "ToDetailerPipe" || node.comfyClass == "EditDetailerPipe" || node.comfyClass == "BasicPipeToDetailerPipe") {
if(node.comfyClass == "ImpactWildcardEncode" || node.comfyClass == "ToDetailerPipe" || node.comfyClass == "ToDetailerPipeSDXL"
|| node.comfyClass == "EditDetailerPipe" || node.comfyClass == "BasicPipeToDetailerPipe" || node.comfyClass == "BasicPipeToDetailerPipeSDXL") {
node._value = "Select the LoRA to add to the text";
var tbox_id = 0;
@@ -367,8 +370,10 @@ app.registerExtension({
break;
case "ToDetailerPipe":
case "ToDetailerPipeSDXL":
case "EditDetailerPipe":
case "BasicPipeToDetailerPipe":
case "BasicPipeToDetailerPipeSDXL":
tbox_id = 0;
combo_id = 1;
break;
+1 -1
View File
@@ -2,7 +2,7 @@ import configparser
import os
version = "V3.25.3"
version = "V3.26"
dependency_version = 9
+187 -87
View File
@@ -14,7 +14,9 @@ import comfy
import impact.wildcards as wildcards
import math
SEG = namedtuple("SEG", ['cropped_image', 'cropped_mask', 'confidence', 'crop_region', 'bbox', 'label'],
SEG = namedtuple("SEG",
['cropped_image', 'cropped_mask', 'confidence', 'crop_region', 'bbox', 'label', 'control_net_wrapper'],
defaults=[None])
@@ -37,6 +39,44 @@ def erosion_mask(mask, grow_mask_by):
return mask_erosion[:, :, :w, :h].round()
def ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise,
refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None,
refiner_negative=None):
if refiner_ratio is None or refiner_model is None or refiner_clip is None or refiner_positive is None or refiner_negative is None:
refined_latent = \
nodes.KSampler().sample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image,
denoise)[0]
else:
advanced_steps = math.floor(steps / denoise)
start_at_step = advanced_steps - steps
end_at_step = start_at_step + math.floor(steps * (1.0 - refiner_ratio))
print(f"pre: {start_at_step} .. {end_at_step} / {advanced_steps}")
temp_latent = \
nodes.KSamplerAdvanced().sample(model, "enable", seed, advanced_steps, cfg, sampler_name, scheduler,
positive, negative, latent_image, start_at_step, end_at_step,
"enable")[0]
if 'noise_mask' in latent_image:
# noise_latent = \
# nodes.KSamplerAdvanced().sample(refiner_model, "enable", seed, advanced_steps, cfg, sampler_name,
# scheduler, refiner_positive, refiner_negative, latent_image, end_at_step,
# end_at_step, "enable")[0]
latent_compositor = nodes.NODE_CLASS_MAPPINGS['LatentCompositeMasked']()
temp_latent = \
latent_compositor.composite(latent_image, temp_latent, 0, 0, False, latent_image['noise_mask'])[0]
print(f"post: {end_at_step} .. {advanced_steps + 1} / {advanced_steps}")
refined_latent = \
nodes.KSamplerAdvanced().sample(refiner_model, "disable", seed, advanced_steps, cfg, sampler_name, scheduler,
refiner_positive, refiner_negative, temp_latent, end_at_step,
advanced_steps + 1,
"disable")[0]
return refined_latent
class REGIONAL_PROMPT:
def __init__(self, mask, sampler):
self.mask = mask
@@ -76,18 +116,18 @@ def gen_detection_hints_from_mask_area(x, y, mask, threshold, use_negative):
plabs = []
# minimum sampling step >= 3
y_step = max(3, int(mask.shape[0]/20))
x_step = max(3, int(mask.shape[1]/20))
y_step = max(3, int(mask.shape[0] / 20))
x_step = max(3, int(mask.shape[1] / 20))
for i in range(0, len(mask), y_step):
for j in range(0, len(mask[i]), x_step):
if mask[i][j] > threshold:
points.append((x+j, y+i))
points.append((x + j, y + i))
plabs.append(1)
elif use_negative and mask[i][j] == 0:
points.append((x+j, y+i))
points.append((x + j, y + i))
plabs.append(0)
return points, plabs
@@ -96,20 +136,24 @@ def gen_negative_hints(w, h, x1, y1, x2, y2):
nplabs = []
# minimum sampling step >= 3
y_step = max(3, int(w/20))
x_step = max(3, int(h/20))
for i in range(10, h-10, y_step):
for j in range(10, w-10, x_step):
if not (x1-10 <= j and j <= x2+10 and y1-10 <= i and i <= y2+10):
y_step = max(3, int(w / 20))
x_step = max(3, int(h / 20))
for i in range(10, h - 10, y_step):
for j in range(10, w - 10, x_step):
if not (x1 - 10 <= j and j <= x2 + 10 and y1 - 10 <= i and i <= y2 + 10):
npoints.append((j, i))
nplabs.append(0)
return npoints, nplabs
def enhance_detail(image, model, clip, vae, guide_size, guide_size_for_bbox, max_size, bbox, seed, steps, cfg, sampler_name,
scheduler, positive, negative, denoise, noise_mask, force_inpaint, wildcard_opt=None, detailer_hook=None):
def enhance_detail(image, model, clip, vae, guide_size, guide_size_for_bbox, max_size, bbox, seed, steps, cfg,
sampler_name,
scheduler, positive, negative, denoise, 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, control_net_wrapper=None):
if wildcard_opt is not None and wildcard_opt != "":
model, _, positive = wildcards.process_with_loras(wildcard_opt, model, clip)
@@ -179,7 +223,12 @@ def enhance_detail(image, model, clip, vae, guide_size, guide_size_for_bbox, max
if detailer_hook is not None:
latent_image = detailer_hook.post_encode(latent_image)
refined_latent = nodes.KSampler().sample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise)[0]
if control_net_wrapper is not None:
positive = control_net_wrapper.apply(positive, upscaled_image)
refined_latent = ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, negative,
latent_image, denoise,
refiner_ratio, refiner_model, refiner_clip, refiner_positive, refiner_negative)
# non-latent downscale - latent downscale cause bad quality
refined_image = vae.decode(refined_latent['samples'])
@@ -239,8 +288,7 @@ def sam_predict(predictor, points, plabs, bbox, threshold):
def make_sam_mask(sam_model, segs, image, detection_hint, dilation,
threshold, bbox_expansion, mask_hint_threshold, mask_hint_use_negative):
threshold, bbox_expansion, mask_hint_threshold, mask_hint_use_negative):
if sam_model.is_auto_mode:
device = comfy.model_management.get_torch_device()
sam_model.to(device=device)
@@ -360,8 +408,9 @@ def make_sam_mask(sam_model, segs, image, detection_hint, dilation,
return mask
def generate_detection_hints(image,seg,center,detection_hint,dilated_bbox,mask_hint_threshold, use_small_negative, mask_hint_use_negative):
def generate_detection_hints(image, seg, center, detection_hint, dilated_bbox, mask_hint_threshold, use_small_negative,
mask_hint_use_negative):
[x1, y1, x2, y2] = dilated_bbox
points = []
@@ -407,13 +456,13 @@ def generate_detection_hints(image,seg,center,detection_hint,dilated_bbox,mask_h
elif detection_hint == "mask-area":
points, plabs = gen_detection_hints_from_mask_area(seg.crop_region[0], seg.crop_region[1],
seg.cropped_mask,
mask_hint_threshold, use_small_negative)
seg.cropped_mask,
mask_hint_threshold, use_small_negative)
if mask_hint_use_negative == "Outter":
npoints, nplabs = gen_negative_hints(image.shape[0], image.shape[1],
seg.crop_region[0], seg.crop_region[1],
seg.crop_region[2], seg.crop_region[3])
seg.crop_region[0], seg.crop_region[1],
seg.crop_region[2], seg.crop_region[3])
points += npoints
plabs += nplabs
@@ -445,7 +494,7 @@ def merge_and_stack_masks(stacked_masks, group_size):
merged_masks = []
for i in range(0, num_masks, group_size):
subset_masks = stacked_masks[i:i+group_size]
subset_masks = stacked_masks[i:i + group_size]
merged_mask = torch.any(subset_masks, dim=0)
merged_masks.append(merged_mask)
@@ -464,7 +513,6 @@ def every_three_pick_last(stacked_masks):
def make_sam_mask_segmented(sam_model, segs, image, detection_hint, dilation,
threshold, bbox_expansion, mask_hint_threshold, mask_hint_use_negative):
if sam_model.is_auto_mode:
device = comfy.model_management.get_torch_device()
sam_model.to(device=device)
@@ -509,7 +557,9 @@ def make_sam_mask_segmented(sam_model, segs, image, detection_hint, dilation,
dilated_bbox = [x1, y1, x2, y2]
points, plabs = generate_detection_hints(image, segs[i],center, detection_hint, dilated_bbox, mask_hint_threshold, use_small_negative, mask_hint_use_negative)
points, plabs = generate_detection_hints(image, segs[i], center, detection_hint, dilated_bbox,
mask_hint_threshold, use_small_negative,
mask_hint_use_negative)
detected_masks = sam_predict(predictor, points, plabs, dilated_bbox, threshold)
@@ -539,7 +589,7 @@ def make_sam_mask_segmented(sam_model, segs, image, detection_hint, dilation,
def segs_bitwise_and_mask(segs, mask):
if mask is None:
print("[SegsBitwiseAndMask] Cannot operate: MASK is empty.")
return ([], )
return ([],)
items = []
@@ -563,7 +613,7 @@ def segs_bitwise_and_mask(segs, mask):
def apply_mask_to_each_seg(segs, masks):
if masks is None:
print("[SegsBitwiseAndMask] Cannot operate: MASK is empty.")
return (segs[0], [], )
return (segs[0], [],)
items = []
@@ -614,9 +664,9 @@ class ONNXDetector:
crop_x1, crop_y1, crop_x2, crop_y2, = crop_region
# prepare cropped mask
cropped_mask = np.zeros((crop_y2-crop_y1,crop_x2-crop_x1))
inner_mask = np.ones((y2-y1, x2-x1))
cropped_mask[y1-crop_y1:y2-crop_y1, x1-crop_x1:x2-crop_x1] = inner_mask
cropped_mask = np.zeros((crop_y2 - crop_y1, crop_x2 - crop_x1))
inner_mask = np.ones((y2 - y1, x2 - x1))
cropped_mask[y1 - crop_y1:y2 - crop_y1, x1 - crop_x1:x2 - crop_x1] = inner_mask
# make items
item = SEG(None, cropped_mask, scores[i], crop_region, item_bbox)
@@ -690,10 +740,10 @@ def mask_to_segs(mask, combined, crop_factor, bbox_fill, drop_size=1):
for contour in contours:
separated_mask = np.zeros_like(mask_i_uint8)
cv2.drawContours(separated_mask, [contour], 0, 255, -1)
separated_mask = np.array(separated_mask/255.0).astype(np.float32)
separated_mask = np.array(separated_mask / 255.0).astype(np.float32)
x, y, w, h = cv2.boundingRect(contour)
bbox = x, y, x+w, y+h
bbox = x, y, x + w, y + h
crop_region = make_crop_region(
mask_i.shape[1], mask_i.shape[0], bbox, crop_factor
)
@@ -701,8 +751,8 @@ def mask_to_segs(mask, combined, crop_factor, bbox_fill, drop_size=1):
if w > drop_size and h > drop_size:
cropped_mask = np.array(
separated_mask[
crop_region[1]: crop_region[3],
crop_region[0]: crop_region[2],
crop_region[1]: crop_region[3],
crop_region[0]: crop_region[2],
]
)
@@ -791,9 +841,11 @@ class KSamplerWrapper:
if hook is not None:
model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise = \
hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise)
hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image,
denoise)
return nodes.common_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=denoise)[0]
return nodes.common_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image,
denoise=denoise)[0]
class KSamplerAdvancedWrapper:
@@ -802,7 +854,8 @@ class KSamplerAdvancedWrapper:
def __init__(self, model, cfg, sampler_name, scheduler, positive, negative):
self.params = model, cfg, sampler_name, scheduler, positive, negative
def sample_advanced(self, add_noise, seed, steps, latent_image, start_at_step, end_at_step, return_with_leftover_noise, hook=None):
def sample_advanced(self, add_noise, seed, steps, latent_image, start_at_step, end_at_step,
return_with_leftover_noise, hook=None):
model, cfg, sampler_name, scheduler, positive, negative = self.params
if hook is not None:
@@ -822,7 +875,7 @@ class PixelKSampleHook:
def __init__(self):
pass
def set_steps(self, info):
self.cur_step, self.total_step = info
@@ -835,14 +888,15 @@ class PixelKSampleHook:
def post_encode(self, samples):
return samples
def pre_ksample(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise):
return model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise
def pre_ksample(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent,
denoise):
return model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise
class PixelKSampleHookCombine(PixelKSampleHook):
hook1 = None
hook2 = None
def __init__(self, hook1, hook2):
super().__init__()
self.hook1 = hook1
@@ -864,9 +918,11 @@ class PixelKSampleHookCombine(PixelKSampleHook):
def pre_ksample(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent,
denoise):
model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise = \
self.hook1.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise)
self.hook1.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative,
upscaled_latent, denoise)
return self.hook2.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise)
return self.hook2.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative,
upscaled_latent, denoise)
class SimpleCfgScheduleHook(PixelKSampleHook):
@@ -875,11 +931,12 @@ class SimpleCfgScheduleHook(PixelKSampleHook):
def __init__(self, target_cfg):
super().__init__()
self.target_cfg = target_cfg
def pre_ksample(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise):
progress = self.cur_step/self.total_step
def pre_ksample(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent,
denoise):
progress = self.cur_step / self.total_step
gap = self.target_cfg - cfg
current_cfg = cfg + gap*progress
current_cfg = cfg + gap * progress
return model, seed, steps, current_cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise
@@ -890,14 +947,16 @@ class SimpleDenoiseScheduleHook(PixelKSampleHook):
super().__init__()
self.target_denoise = target_denoise
def pre_ksample(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise):
def pre_ksample(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent,
denoise):
progress = self.cur_step / self.total_step
gap = self.target_denoise - denoise
current_denoise = denoise + gap * progress
return model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, current_denoise
def latent_upscale_on_pixel_space_shape(samples, scale_method, w, h, vae, use_tile=False, tile_size=512, save_temp_prefix=None, hook=None):
def latent_upscale_on_pixel_space_shape(samples, scale_method, w, h, vae, use_tile=False, tile_size=512,
save_temp_prefix=None, hook=None):
pixels = vae_decode(vae, samples, use_tile, hook, tile_size=tile_size)
if save_temp_prefix is not None:
@@ -911,7 +970,8 @@ def latent_upscale_on_pixel_space_shape(samples, scale_method, w, h, vae, use_ti
return vae_encode(vae, pixels, use_tile, hook, tile_size=tile_size)
def latent_upscale_on_pixel_space(samples, scale_method, scale_factor, vae, use_tile=False, tile_size=512, save_temp_prefix=None, hook=None):
def latent_upscale_on_pixel_space(samples, scale_method, scale_factor, vae, use_tile=False, tile_size=512,
save_temp_prefix=None, hook=None):
pixels = vae_decode(vae, samples, use_tile, hook, tile_size=tile_size)
if save_temp_prefix is not None:
@@ -927,7 +987,8 @@ def latent_upscale_on_pixel_space(samples, scale_method, scale_factor, vae, use_
return vae_encode(vae, pixels, use_tile, hook, tile_size=tile_size)
def latent_upscale_on_pixel_space_with_model_shape(samples, scale_method, upscale_model, new_w, new_h, vae, use_tile=False, tile_size=512, save_temp_prefix=None, hook=None):
def latent_upscale_on_pixel_space_with_model_shape(samples, scale_method, upscale_model, new_w, new_h, vae,
use_tile=False, tile_size=512, save_temp_prefix=None, hook=None):
pixels = vae_decode(vae, samples, use_tile, hook, tile_size=tile_size)
if save_temp_prefix is not None:
@@ -950,7 +1011,8 @@ def latent_upscale_on_pixel_space_with_model_shape(samples, scale_method, upscal
return vae_encode(vae, pixels, use_tile, hook, tile_size=tile_size)
def latent_upscale_on_pixel_space_with_model(samples, scale_method, upscale_model, scale_factor, vae, use_tile=False, tile_size=512, save_temp_prefix=None, hook=None):
def latent_upscale_on_pixel_space_with_model(samples, scale_method, upscale_model, scale_factor, vae, use_tile=False,
tile_size=512, save_temp_prefix=None, hook=None):
pixels = vae_decode(vae, samples, use_tile, hook, tile_size=tile_size)
if save_temp_prefix is not None:
@@ -988,7 +1050,8 @@ class TwoSamplersForMaskUpscaler:
tile_size = 512
def __init__(self, scale_method, sample_schedule, use_tiled_vae, base_sampler, mask_sampler, mask, vae,
full_sampler_opt=None, upscale_model_opt=None, hook_base_opt=None, hook_mask_opt=None, hook_full_opt=None,
full_sampler_opt=None, upscale_model_opt=None, hook_base_opt=None, hook_mask_opt=None,
hook_full_opt=None,
tile_size=512):
mask = mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1]))
@@ -1013,7 +1076,8 @@ class TwoSamplersForMaskUpscaler:
save_temp_prefix=save_temp_prefix,
hook=self.hook_base, tile_size=self.tile_size)
else:
upscaled_latent = latent_upscale_on_pixel_space_with_model(samples, scale_method, self.upscale_model, upscale_factor, vae,
upscaled_latent = latent_upscale_on_pixel_space_with_model(samples, scale_method, self.upscale_model,
upscale_factor, vae,
use_tile=self.use_tiled_vae,
save_temp_prefix=save_temp_prefix,
hook=self.hook_mask, tile_size=self.tile_size)
@@ -1037,12 +1101,15 @@ class TwoSamplersForMaskUpscaler:
if self.upscale_model is None:
upscaled_latent = latent_upscale_on_pixel_space_shape(samples, scale_method, w, h, vae,
use_tile=self.use_tiled_vae,
save_temp_prefix=save_temp_prefix, hook=self.hook_base,
save_temp_prefix=save_temp_prefix,
hook=self.hook_base,
tile_size=self.tile_size)
else:
upscaled_latent = latent_upscale_on_pixel_space_with_model_shape(samples, scale_method, self.upscale_model, w, h, vae,
upscaled_latent = latent_upscale_on_pixel_space_with_model_shape(samples, scale_method, self.upscale_model,
w, h, vae,
use_tile=self.use_tiled_vae,
save_temp_prefix=save_temp_prefix, hook=self.hook_mask,
save_temp_prefix=save_temp_prefix,
hook=self.hook_mask,
tile_size=self.tile_size)
return self.do_samples(step_info, base_sampler, mask_sampler, sample_schedule, mask, upscaled_latent)
@@ -1070,16 +1137,16 @@ class TwoSamplersForMaskUpscaler:
return cur_step == total_step
elif sample_schedule == "last2":
return cur_step >= total_step-1
return cur_step >= total_step - 1
elif sample_schedule == "interleave1+last1":
return cur_step % 2 == 0 or cur_step >= total_step-1
return cur_step % 2 == 0 or cur_step >= total_step - 1
elif sample_schedule == "interleave2+last1":
return cur_step % 2 == 0 or cur_step >= total_step-1
return cur_step % 2 == 0 or cur_step >= total_step - 1
elif sample_schedule == "interleave3+last1":
return cur_step % 2 == 0 or cur_step >= total_step-1
return cur_step % 2 == 0 or cur_step >= total_step - 1
def do_samples(self, step_info, base_sampler, mask_sampler, sample_schedule, mask, upscaled_latent):
if self.is_full_sample_time(step_info, sample_schedule):
@@ -1092,9 +1159,11 @@ class TwoSamplersForMaskUpscaler:
else:
print(f"step_info={step_info} / non-full time")
# upscale mask
upscaled_mask = F.interpolate(mask, size=(upscaled_latent['samples'].shape[2], upscaled_latent['samples'].shape[3]),
upscaled_mask = F.interpolate(mask, size=(
upscaled_latent['samples'].shape[2], upscaled_latent['samples'].shape[3]),
mode='bilinear', align_corners=True)
upscaled_mask = upscaled_mask[:, :, :upscaled_latent['samples'].shape[2], :upscaled_latent['samples'].shape[3]]
upscaled_mask = upscaled_mask[:, :, :upscaled_latent['samples'].shape[2],
:upscaled_latent['samples'].shape[3]]
# base sampler
upscaled_inv_mask = torch.where(upscaled_mask != 1.0, torch.tensor(1.0), torch.tensor(0.0))
@@ -1140,12 +1209,14 @@ class PixelKSampleUpscaler:
upscaled_latent = latent_upscale_on_pixel_space_with_model(samples, scale_method, self.upscale_model,
upscale_factor, vae,
use_tile=self.use_tiled_vae,
save_temp_prefix=save_temp_prefix, hook=self.hook,
save_temp_prefix=save_temp_prefix,
hook=self.hook,
tile_size=self.tile_size)
if self.hook is not None:
model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise = \
self.hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise)
self.hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative,
upscaled_latent, denoise)
refined_latent = nodes.KSampler().sample(model, seed, steps, cfg, sampler_name, scheduler,
positive, negative, upscaled_latent, denoise)[0]
@@ -1163,20 +1234,36 @@ class PixelKSampleUpscaler:
save_temp_prefix=save_temp_prefix, hook=self.hook,
tile_size=self.tile_size)
else:
upscaled_latent = latent_upscale_on_pixel_space_with_model_shape(samples, scale_method, self.upscale_model, w, h, vae,
upscaled_latent = latent_upscale_on_pixel_space_with_model_shape(samples, scale_method, self.upscale_model,
w, h, vae,
use_tile=self.use_tiled_vae,
save_temp_prefix=save_temp_prefix, hook=self.hook,
save_temp_prefix=save_temp_prefix,
hook=self.hook,
tile_size=self.tile_size)
if self.hook is not None:
model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise = \
self.hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise)
self.hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative,
upscaled_latent, denoise)
refined_latent = nodes.KSampler().sample(model, seed, steps, cfg, sampler_name, scheduler,
positive, negative, upscaled_latent, denoise)[0]
return refined_latent
class ControlNetWrapper:
def __init__(self, control_net, strength, preprocessor):
self.control_net = control_net
self.strength = strength
self.preprocessor = preprocessor
def apply(self, conditioning, image):
if self.preprocessor is not None:
image = self.preprocessor.apply(image)
return nodes.ControlNetApply().apply_controlnet(conditioning, self.control_net, image, self.strength)[0]
# REQUIREMENTS: BlenderNeko/ComfyUI Noise
try:
class InjectNoiseHook(PixelKSampleHook):
@@ -1192,14 +1279,14 @@ try:
size = samples['samples'].shape
seed = self.cur_step + self.seed
from custom_nodes.ComfyUI_Noise.nodes import NoisyLatentImage, InjectNoise
noise = NoisyLatentImage().create_noisy_latents(self.source, seed, size[3]*8, size[2]*8, size[0])[0]
noise = NoisyLatentImage().create_noisy_latents(self.source, seed, size[3] * 8, size[2] * 8, size[0])[0]
# inj noise
mask = None
if 'noise_mask' in samples:
mask = samples['noise_mask']
strength = self.start_strength + (self.end_strength-self.start_strength)*self.cur_step/self.total_step
strength = self.start_strength + (self.end_strength - self.start_strength) * self.cur_step / self.total_step
samples = InjectNoise().inject_noise(samples, strength, noise, mask)[0]
if mask is not None:
@@ -1209,7 +1296,6 @@ try:
except:
pass
# REQUIREMENTS: BlenderNeko/ComfyUI_TiledKSampler
try:
class TiledKSamplerWrapper:
@@ -1226,10 +1312,14 @@ try:
if hook is not None:
model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise = \
hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise)
hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image,
denoise)
return \
TiledKSampler().sample(model, seed, tile_width, tile_height, tiling_strategy, steps, cfg, sampler_name,
scheduler,
positive, negative, latent_image, denoise)[0]
return TiledKSampler().sample(model, seed, tile_width, tile_height, tiling_strategy, steps, cfg, sampler_name, scheduler,
positive, negative, latent_image, denoise)[0]
class PixelTiledKSampleUpscaler:
params = None
@@ -1239,7 +1329,8 @@ try:
is_tiled = True
tile_size = 512
def __init__(self, scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise,
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_size=512):
self.params = scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise
@@ -1254,8 +1345,10 @@ try:
scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise = self.params
tile_width, tile_height, tiling_strategy = self.tile_params
return TiledKSampler().sample(model, seed, tile_width, tile_height, tiling_strategy, steps, cfg, sampler_name, scheduler,
positive, negative, latent, denoise)[0]
return \
TiledKSampler().sample(model, seed, tile_width, tile_height, tiling_strategy, steps, cfg, sampler_name,
scheduler,
positive, negative, latent, denoise)[0]
def upscale(self, step_info, samples, upscale_factor, save_temp_prefix=None):
scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise = self.params
@@ -1265,11 +1358,15 @@ try:
if self.upscale_model is None:
upscaled_latent = latent_upscale_on_pixel_space(samples, scale_method, upscale_factor, vae,
use_tile=True, save_temp_prefix=save_temp_prefix, hook=self.hook,
use_tile=True, save_temp_prefix=save_temp_prefix,
hook=self.hook,
tile_size=self.tile_size)
else:
upscaled_latent = latent_upscale_on_pixel_space_with_model(samples, scale_method, self.upscale_model, upscale_factor, vae,
use_tile=True, save_temp_prefix=save_temp_prefix, hook=self.hook,
upscaled_latent = latent_upscale_on_pixel_space_with_model(samples, scale_method, self.upscale_model,
upscale_factor, vae,
use_tile=True,
save_temp_prefix=save_temp_prefix,
hook=self.hook,
tile_size=self.tile_size)
refined_latent = self.tiled_ksample(upscaled_latent)
@@ -1287,9 +1384,12 @@ try:
use_tile=True, save_temp_prefix=save_temp_prefix,
hook=self.hook, tile_size=self.tile_size)
else:
upscaled_latent = latent_upscale_on_pixel_space_with_model_shape(samples, scale_method, self.upscale_model, w, h, vae,
use_tile=True, save_temp_prefix=save_temp_prefix,
hook=self.hook, tile_size=self.tile_size)
upscaled_latent = latent_upscale_on_pixel_space_with_model_shape(samples, scale_method,
self.upscale_model, w, h, vae,
use_tile=True,
save_temp_prefix=save_temp_prefix,
hook=self.hook,
tile_size=self.tile_size)
refined_latent = self.tiled_ksample(upscaled_latent)
@@ -1297,7 +1397,6 @@ try:
except:
pass
# REQUIREMENTS: biegert/ComfyUI-CLIPSeg
try:
class BBoxDetectorBasedOnCLIPSeg:
@@ -1361,6 +1460,7 @@ from latent_preview import TAESD, TAESDPreviewerImpl, Latent2RGBPreviewer
try:
import comfy.latent_formats as latent_formats
def get_previewer(device, latent_format=latent_formats.SD15(), force=False, method=None):
previewer = None
@@ -1381,7 +1481,8 @@ try:
taesd = TAESD(None, taesd_decoder_path).to(device)
previewer = TAESDPreviewerImpl(taesd)
else:
print("Warning: TAESD previews enabled, but could not find models/vae_approx/{}".format(latent_format.taesd_decoder_name))
print("Warning: TAESD previews enabled, but could not find models/vae_approx/{}".format(
latent_format.taesd_decoder_name))
if previewer is None:
previewer = Latent2RGBPreviewer(latent_format.latent_rgb_factors)
@@ -1391,4 +1492,3 @@ except:
print(f"#########################################################################")
print(f"[ERROR] ComfyUI-Impact-Pack: Please update ComfyUI to the latest version.")
print(f"#########################################################################")
+1 -1
View File
@@ -230,7 +230,7 @@ class SimpleDetectorForEachPipe:
def doit(self, detailer_pipe, image, bbox_threshold, bbox_dilation, crop_factor, drop_size,
sub_threshold, sub_dilation, sub_bbox_expansion, sam_mask_hint_threshold):
model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook = detailer_pipe
model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook, refiner_model, refiner_clip, refiner_positive, refiner_negative = detailer_pipe
return SimpleDetectorForEach.detect(bbox_detector, image, bbox_threshold, bbox_dilation, crop_factor, drop_size,
sub_threshold, sub_dilation, sub_bbox_expansion,
+108 -30
View File
@@ -167,7 +167,11 @@ class SEGSDetailer:
"noise_mask": ("BOOLEAN", {"default": True, "label_on": "enabled", "label_off": "disabled"}),
"force_inpaint": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
"basic_pipe": ("BASIC_PIPE",),
"refiner_ratio": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0}),
},
"optional": {
"refiner_basic_pipe_opt": ("BASIC_PIPE",),
}
}
RETURN_TYPES = ("SEGS", )
@@ -177,9 +181,13 @@ class SEGSDetailer:
@staticmethod
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):
denoise, noise_mask, force_inpaint, basic_pipe, refiner_ratio=None, refiner_basic_pipe_opt=None):
model, clip, vae, positive, negative = basic_pipe
if refiner_basic_pipe_opt is None:
refiner_model, refiner_clip, refiner_positive, refiner_negative = None, None, None, None
else:
refiner_model, refiner_clip, _, refiner_positive, refiner_negative = refiner_basic_pipe_opt
new_segs = []
@@ -200,19 +208,26 @@ class SEGSDetailer:
enhanced_pil = core.enhance_detail(cropped_image, model, clip, vae, guide_size, guide_size_for, max_size,
seg.bbox, seed, steps, cfg, sampler_name, scheduler,
positive, negative, denoise, cropped_mask, force_inpaint)
positive, negative, denoise, cropped_mask, force_inpaint,
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)
if enhanced_pil is None:
new_cropped_image = cropped_image
else:
new_cropped_image = pil2numpy(enhanced_pil)
new_cropped_image = pil2numpy(enhanced_pil)
new_seg = SEG(new_cropped_image, seg.cropped_mask, seg.confidence, seg.crop_region, seg.bbox, seg.label)
new_segs.append(new_seg)
return segs[0], new_segs
def doit(self, image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
denoise, noise_mask, force_inpaint, basic_pipe):
denoise, noise_mask, force_inpaint, basic_pipe, refiner_ratio=None, refiner_basic_pipe_opt=None):
segs = SEGSDetailer.do_detail(image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
denoise, noise_mask, force_inpaint, basic_pipe)
segs = SEGSDetailer.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, refiner_basic_pipe_opt)
return (segs, )
@@ -573,7 +588,8 @@ class DetailerForEach:
@staticmethod
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):
image_pil = tensor2pil(image).convert('RGBA')
@@ -599,7 +615,10 @@ class DetailerForEach:
enhanced_pil = core.enhance_detail(cropped_image, model, clip, vae, guide_size, guide_size_for_bbox, max_size,
seg.bbox, seed, steps, cfg, sampler_name, scheduler,
positive, negative, denoise, cropped_mask, force_inpaint, wildcard_opt, detailer_hook)
positive, negative, denoise, cropped_mask, force_inpaint, wildcard_opt, 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)
if not (enhanced_pil is None):
# don't latent composite-> converting to latent caused poor quality
@@ -658,8 +677,12 @@ class DetailerForEachPipe:
"force_inpaint": ("BOOLEAN", {"default": True, "label_on": "enabled", "label_off": "disabled"}),
"basic_pipe": ("BASIC_PIPE", ),
"wildcard": ("STRING", {"multiline": True, "dynamicPrompts": False}),
"refiner_ratio": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0}),
},
"optional": {"detailer_hook": ("DETAILER_HOOK",), }
"optional": {
"detailer_hook": ("DETAILER_HOOK",),
"refiner_basic_pipe_opt": ("BASIC_PIPE",),
}
}
RETURN_TYPES = ("IMAGE", )
@@ -668,13 +691,21 @@ class DetailerForEachPipe:
CATEGORY = "ImpactPack/Detailer"
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, detailer_hook=None):
denoise, feather, noise_mask, force_inpaint, basic_pipe, wildcard, refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None):
model, clip, vae, positive, negative = basic_pipe
if refiner_basic_pipe_opt is None:
refiner_model, refiner_clip, refiner_positive, refiner_negative = None, None, None, None
else:
refiner_model, refiner_clip, _, refiner_positive, refiner_negative = refiner_basic_pipe_opt
enhanced_img, cropped, cropped_enhanced, cropped_enhanced_alpha = \
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,
force_inpaint, wildcard, detailer_hook)
force_inpaint, wildcard, detailer_hook,
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative)
return (enhanced_img, )
@@ -982,7 +1013,9 @@ class FaceDetailer:
bbox_threshold, bbox_dilation, bbox_crop_factor,
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=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):
# make default prompt as 'face' if empty prompt for CLIPSeg
bbox_detector.setAux('face')
segs = bbox_detector.detect(image, bbox_threshold, bbox_dilation, bbox_crop_factor, drop_size)
@@ -1003,7 +1036,10 @@ class FaceDetailer:
enhanced_img, _, cropped_enhanced, cropped_enhanced_alpha = \
DetailerForEach.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, detailer_hook)
force_inpaint, wildcard_opt, detailer_hook,
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
refiner_negative=refiner_negative)
# Mask Generator
mask = core.segs_to_combined_mask(segs)
@@ -1029,7 +1065,7 @@ class FaceDetailer:
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)
pipe = (model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook)
pipe = (model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook, None, None, None, None)
return enhanced_img, cropped_enhanced, cropped_enhanced_alpha, mask, pipe
@@ -1200,8 +1236,8 @@ class TiledKSamplerProvider:
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
"scheduler": (comfy.samplers.KSampler.SCHEDULERS, ),
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
"tile_width": ("INT", {"default": 512, "min": 256, "max": MAX_RESOLUTION, "step": 64}),
"tile_height": ("INT", {"default": 512, "min": 256, "max": MAX_RESOLUTION, "step": 64}),
"tile_width": ("INT", {"default": 512, "min": 320, "max": MAX_RESOLUTION, "step": 64}),
"tile_height": ("INT", {"default": 512, "min": 320, "max": MAX_RESOLUTION, "step": 64}),
"tiling_strategy": (["random", "padded", 'simple'], ),
"basic_pipe": ("BASIC_PIPE", )
}}
@@ -1236,8 +1272,8 @@ class PixelTiledKSampleUpscalerProvider:
"positive": ("CONDITIONING", ),
"negative": ("CONDITIONING", ),
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
"tile_width": ("INT", {"default": 512, "min": 256, "max": MAX_RESOLUTION, "step": 64}),
"tile_height": ("INT", {"default": 512, "min": 256, "max": MAX_RESOLUTION, "step": 64}),
"tile_width": ("INT", {"default": 512, "min": 320, "max": MAX_RESOLUTION, "step": 64}),
"tile_height": ("INT", {"default": 512, "min": 320, "max": MAX_RESOLUTION, "step": 64}),
"tiling_strategy": (["random", "padded", 'simple'], ),
},
"optional": {
@@ -1275,8 +1311,8 @@ class PixelTiledKSampleUpscalerProviderPipe:
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
"scheduler": (comfy.samplers.KSampler.SCHEDULERS, ),
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
"tile_width": ("INT", {"default": 512, "min": 256, "max": MAX_RESOLUTION, "step": 64}),
"tile_height": ("INT", {"default": 512, "min": 256, "max": MAX_RESOLUTION, "step": 64}),
"tile_width": ("INT", {"default": 512, "min": 320, "max": MAX_RESOLUTION, "step": 64}),
"tile_height": ("INT", {"default": 512, "min": 320, "max": MAX_RESOLUTION, "step": 64}),
"tiling_strategy": (["random", "padded", 'simple'], ),
"basic_pipe": ("BASIC_PIPE",)
},
@@ -1321,7 +1357,7 @@ class PixelKSampleUpscalerProvider:
"negative": ("CONDITIONING", ),
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
"use_tiled_vae": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
"tile_size": ("INT", {"default": 512, "min": 192, "max": 4096, "step": 64}),
"tile_size": ("INT", {"default": 512, "min": 320, "max": 4096, "step": 64}),
},
"optional": {
"upscale_model_opt": ("UPSCALE_MODEL", ),
@@ -1357,7 +1393,7 @@ class PixelKSampleUpscalerProviderPipe(PixelKSampleUpscalerProvider):
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
"use_tiled_vae": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
"basic_pipe": ("BASIC_PIPE",),
"tile_size": ("INT", {"default": 512, "min": 192, "max": 4096, "step": 64}),
"tile_size": ("INT", {"default": 512, "min": 320, "max": 4096, "step": 64}),
},
"optional": {
"upscale_model_opt": ("UPSCALE_MODEL", ),
@@ -1396,7 +1432,7 @@ class TwoSamplersForMaskUpscalerProvider:
"mask_sampler": ("KSAMPLER", ),
"mask": ("MASK", ),
"vae": ("VAE",),
"tile_size": ("INT", {"default": 512, "min": 192, "max": 4096, "step": 64}),
"tile_size": ("INT", {"default": 512, "min": 320, "max": 4096, "step": 64}),
},
"optional": {
"full_sampler_opt": ("KSAMPLER",),
@@ -1438,7 +1474,7 @@ class TwoSamplersForMaskUpscalerProviderPipe:
"mask_sampler": ("KSAMPLER", ),
"mask": ("MASK", ),
"basic_pipe": ("BASIC_PIPE",),
"tile_size": ("INT", {"default": 512, "min": 192, "max": 4096, "step": 64}),
"tile_size": ("INT", {"default": 512, "min": 320, "max": 4096, "step": 64}),
},
"optional": {
"full_sampler_opt": ("KSAMPLER",),
@@ -1590,6 +1626,7 @@ class FaceDetailerPipe:
"sam_mask_hint_use_negative": (["False", "Small", "Outter"],),
"drop_size": ("INT", {"min": 1, "max": MAX_RESOLUTION, "step": 1, "default": 10}),
"refiner_ratio": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0}),
},
}
@@ -1603,16 +1640,19 @@ class FaceDetailerPipe:
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,
sam_detection_hint, sam_dilation, sam_threshold, sam_bbox_expansion,
sam_mask_hint_threshold, sam_mask_hint_use_negative, drop_size):
sam_mask_hint_threshold, sam_mask_hint_use_negative, drop_size, refiner_ratio=None):
model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector, sam_model_opt, detailer_hook = detailer_pipe
model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector, sam_model_opt, detailer_hook, \
refiner_model, refiner_clip, refiner_positive, refiner_negative = detailer_pipe
enhanced_img, cropped_enhanced, cropped_enhanced_alpha, mask = FaceDetailer.enhance_face(
image, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler,
positive, negative, denoise, feather, noise_mask, force_inpaint,
bbox_threshold, bbox_dilation, bbox_crop_factor,
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, 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_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative)
if len(cropped_enhanced) == 0:
cropped_enhanced = [empty_pil_tensor()]
@@ -1663,13 +1703,22 @@ class DetailerForEachTestPipe(DetailerForEachPipe):
CATEGORY = "ImpactPack/Detailer"
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, detailer_hook=None):
denoise, feather, noise_mask, force_inpaint, basic_pipe, wildcard, refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None):
model, clip, vae, positive, negative = basic_pipe
if refiner_basic_pipe_opt is None:
refiner_model, refiner_clip, refiner_positive, refiner_negative = None, None, None, None
else:
refiner_model, refiner_clip, _, refiner_positive, refiner_negative = refiner_basic_pipe_opt
enhanced_img, cropped, cropped_enhanced, cropped_enhanced_alpha = \
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,
force_inpaint, wildcard, detailer_hook)
force_inpaint, wildcard, detailer_hook,
refiner_ratio=refiner_ratio, refiner_model=refiner_model,
refiner_clip=refiner_clip, refiner_positive=refiner_positive,
refiner_negative=refiner_negative)
# set fallback image
if len(cropped) == 0:
@@ -2571,7 +2620,7 @@ class ReencodeLatent:
"tile_mode": (["None", "Both", "Decode(input) only", "Encode(output) only"],),
"input_vae": ("VAE", ),
"output_vae": ("VAE", ),
"tile_size": ("INT", {"default": 512, "min": 192, "max": 4096, "step": 64}),
"tile_size": ("INT", {"default": 512, "min": 320, "max": 4096, "step": 64}),
},
}
@@ -2716,6 +2765,35 @@ class MakeImageList:
return (images, )
class ControlNetApplySEGS:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"segs": ("SEGS",),
"control_net": ("CONTROL_NET",),
"strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
},
"optional": {
"segs_preprocessor": ("SEGS_PREPROCESSOR",),
}
}
RETURN_TYPES = ("SEGS",)
FUNCTION = "doit"
CATEGORY = "ImpactPack/Util"
def doit(self, segs, control_net, strength, segs_preprocessor=None):
new_segs = []
for seg in segs[1]:
control_net_wrapper = impact.core.ControlNetWrapper(control_net, strength, segs_preprocessor)
new_seg = SEG(seg.cropped_image, seg.cropped_mask, seg.confidence, seg.crop_region, seg.bbox, seg.label, control_net_wrapper)
new_segs.append(new_seg)
return ((segs[0], new_segs), )
class StringSelector:
@classmethod
def INPUT_TYPES(s):
+135 -10
View File
@@ -27,10 +27,36 @@ class ToDetailerPipe:
def doit(self, *args, **kwargs):
pipe = (kwargs['model'], kwargs['clip'], kwargs['vae'], kwargs['positive'], kwargs['negative'], kwargs['wildcard'], kwargs['bbox_detector'],
kwargs.get('segm_detector_opt', None), kwargs.get('sam_model_opt', None), kwargs.get('detailer_hook', None))
kwargs.get('segm_detector_opt', None), kwargs.get('sam_model_opt', None), kwargs.get('detailer_hook', None),
kwargs.get('refiner_model', None), kwargs.get('refiner_clip', None),
kwargs.get('refiner_positive', None), kwargs.get('refiner_negative', None))
return (pipe, )
class ToDetailerPipeSDXL(ToDetailerPipe):
@classmethod
def INPUT_TYPES(s):
return {"required": {
"model": ("MODEL",),
"clip": ("CLIP",),
"vae": ("VAE",),
"positive": ("CONDITIONING",),
"negative": ("CONDITIONING",),
"refiner_model": ("MODEL",),
"refiner_clip": ("CLIP",),
"refiner_positive": ("CONDITIONING",),
"refiner_negative": ("CONDITIONING",),
"bbox_detector": ("BBOX_DETECTOR", ),
"wildcard": ("STRING", {"multiline": True, "dynamicPrompts": False}),
"Select to add LoRA": (["Select the LoRA to add to the text"] + folder_paths.get_filename_list("loras"),),
},
"optional": {
"sam_model_opt": ("SAM_MODEL",),
"segm_detector_opt": ("SEGM_DETECTOR",),
"detailer_hook": ("DETAILER_HOOK",),
}}
class FromDetailerPipe:
@classmethod
def INPUT_TYPES(s):
@@ -43,7 +69,7 @@ class FromDetailerPipe:
CATEGORY = "ImpactPack/Pipe"
def doit(self, detailer_pipe):
model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook = detailer_pipe
model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook, _, _, _, _ = detailer_pipe
return model, clip, vae, positive, negative, bbox_detector, sam_model_opt, segm_detector_opt, detailer_hook
@@ -59,10 +85,26 @@ class FromDetailerPipe_v2:
CATEGORY = "ImpactPack/Pipe"
def doit(self, detailer_pipe):
model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook = detailer_pipe
model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook, _, _, _, _ = detailer_pipe
return detailer_pipe, model, clip, vae, positive, negative, bbox_detector, sam_model_opt, segm_detector_opt, detailer_hook
class FromDetailerPipe_SDXL:
@classmethod
def INPUT_TYPES(s):
return {"required": {"detailer_pipe": ("DETAILER_PIPE",), }, }
RETURN_TYPES = ("DETAILER_PIPE", "MODEL", "CLIP", "VAE", "CONDITIONING", "CONDITIONING", "BBOX_DETECTOR", "SAM_MODEL", "SEGM_DETECTOR", "DETAILER_HOOK", "MODEL", "CLIP", "CONDITIONING", "CONDITIONING")
RETURN_NAMES = ("detailer_pipe", "model", "clip", "vae", "positive", "negative", "bbox_detector", "sam_model_opt", "segm_detector_opt", "detailer_hook", "refiner_model", "refiner_clip", "refiner_positive", "refiner_negative")
FUNCTION = "doit"
CATEGORY = "ImpactPack/Pipe"
def doit(self, detailer_pipe):
model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook, refiner_model, refiner_clip, refiner_positive, refiner_negative = detailer_pipe
return detailer_pipe, model, clip, vae, positive, negative, bbox_detector, sam_model_opt, segm_detector_opt, detailer_hook, refiner_model, refiner_clip, refiner_positive, refiner_negative
class ToBasicPipe:
@classmethod
def INPUT_TYPES(s):
@@ -148,7 +190,44 @@ class BasicPipeToDetailerPipe:
detailer_hook = kwargs.get('detailer_hook', None)
model, clip, vae, positive, negative = basic_pipe
pipe = model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook
pipe = model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook, None, None, None, None
return (pipe, )
class BasicPipeToDetailerPipeSDXL:
@classmethod
def INPUT_TYPES(s):
return {"required": {"base_basic_pipe": ("BASIC_PIPE",),
"refiner_basic_pipe": ("BASIC_PIPE",),
"bbox_detector": ("BBOX_DETECTOR", ),
"wildcard": ("STRING", {"multiline": True, "dynamicPrompts": False}),
"Select to add LoRA": (["Select the LoRA to add to the text"] + folder_paths.get_filename_list("loras"),),
},
"optional": {
"sam_model_opt": ("SAM_MODEL", ),
"segm_detector_opt": ("SEGM_DETECTOR",),
"detailer_hook": ("DETAILER_HOOK",),
},
}
RETURN_TYPES = ("DETAILER_PIPE", )
RETURN_NAMES = ("detailer_pipe", )
FUNCTION = "doit"
CATEGORY = "ImpactPack/Pipe"
def doit(self, *args, **kwargs):
base_basic_pipe = kwargs['base_basic_pipe']
refiner_basic_pipe = kwargs['refiner_basic_pipe']
bbox_detector = kwargs['bbox_detector']
wildcard = kwargs['wildcard']
sam_model_opt = kwargs.get('sam_model_opt', None)
segm_detector_opt = kwargs.get('segm_detector_opt', None)
detailer_hook = kwargs.get('detailer_hook', None)
model, clip, vae, positive, negative = base_basic_pipe
refiner_model, refiner_clip, refiner_vae, refiner_positive, refiner_negative = refiner_basic_pipe
pipe = model, clip, vae, positive, negative, wildcard, bbox_detector, segm_detector_opt, sam_model_opt, detailer_hook, refiner_model, refiner_clip, refiner_positive, refiner_negative
return (pipe, )
@@ -157,16 +236,17 @@ class DetailerPipeToBasicPipe:
def INPUT_TYPES(s):
return {"required": {"detailer_pipe": ("DETAILER_PIPE",), }}
RETURN_TYPES = ("BASIC_PIPE", )
RETURN_NAMES = ("basic_pipe", )
RETURN_TYPES = ("BASIC_PIPE", "BASIC_PIPE")
RETURN_NAMES = ("base_basic_pipe", "refiner_basic_pipe")
FUNCTION = "doit"
CATEGORY = "ImpactPack/Pipe"
def doit(self, detailer_pipe):
model, clip, vae, positive, negative, _, _, _, _, _ = detailer_pipe
model, clip, vae, positive, negative, _, _, _, _, _, refiner_model, refiner_clip, refiner_positive, refiner_negative = detailer_pipe
pipe = model, clip, vae, positive, negative
return (pipe, )
refiner_pipe = refiner_model, refiner_clip, vae, refiner_positive, refiner_negative
return (pipe, refiner_pipe)
class EditBasicPipe:
@@ -252,8 +332,12 @@ class EditDetailerPipe:
sam_model = kwargs.get('sam_model', None)
segm_detector = kwargs.get('segm_detector', None)
detailer_hook = kwargs.get('detailer_hook', None)
refiner_model = kwargs.get('refiner_model', None)
refiner_clip = kwargs.get('refiner_clip', None)
refiner_positive = kwargs.get('refiner_positive', None)
refiner_negative = kwargs.get('refiner_negative', None)
res_model, res_clip, res_vae, res_positive, res_negative, res_wildcard, res_bbox_detector, res_segm_detector, res_sam_model, res_detailer_hook = detailer_pipe
res_model, res_clip, res_vae, res_positive, res_negative, res_wildcard, res_bbox_detector, res_segm_detector, res_sam_model, res_detailer_hook, res_refiner_model, res_refiner_clip, res_refiner_positive, res_refiner_negative = detailer_pipe
if model is not None:
res_model = model
@@ -285,6 +369,47 @@ class EditDetailerPipe:
if detailer_hook is not None:
res_detailer_hook = detailer_hook
pipe = res_model, res_clip, res_vae, res_positive, res_negative, res_wildcard, res_bbox_detector, res_segm_detector, res_sam_model, res_detailer_hook
if refiner_model is not None:
res_refiner_model = refiner_model
if refiner_clip is not None:
res_refiner_clip = refiner_clip
if refiner_positive is not None:
res_refiner_positive = refiner_positive
if refiner_negative is not None:
res_refiner_negative = refiner_negative
pipe = (res_model, res_clip, res_vae, res_positive, res_negative, res_wildcard,
res_bbox_detector, res_segm_detector, res_sam_model, res_detailer_hook,
res_refiner_model, res_refiner_clip, res_refiner_positive, res_refiner_negative)
return (pipe, )
class EditDetailerPipeSDXL(EditDetailerPipe):
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"detailer_pipe": ("DETAILER_PIPE",),
"wildcard": ("STRING", {"multiline": True, "dynamicPrompts": False}),
"Select to add LoRA": (["Select the LoRA to add to the text"] + folder_paths.get_filename_list("loras"),),
},
"optional": {
"model": ("MODEL",),
"clip": ("CLIP",),
"vae": ("VAE",),
"positive": ("CONDITIONING",),
"negative": ("CONDITIONING",),
"refiner_model": ("MODEL",),
"refiner_clip": ("CLIP",),
"refiner_positive": ("CONDITIONING",),
"refiner_negative": ("CONDITIONING",),
"bbox_detector": ("BBOX_DETECTOR",),
"sam_model": ("SAM_MODEL",),
"segm_detector_opt": ("SEGM_DETECTOR",),
"detailer_hook": ("DETAILER_HOOK",),
},
}
File diff suppressed because it is too large Load Diff