diff --git a/README.md b/README.md index ffabeb0..6284753 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,7 @@ NOTE: The UltralyticsDetectorProvider node is not part of the ComfyUI-Impact-Pac * `PreviewDetailerHook` - Connecting this hook node helps provide assistance for viewing previews whenever SEGS Detailing tasks are completed. When working with a large number of SEGS, such as Make Tile SEGS, it allows for monitoring the situation as improvements progress incrementally. * Since this is the hook applied when pasting onto the original image, it has no effect on nodes like `SEGSDetailer`. * `VariationNoiseDetailerHookProvider` - Apply variation seed to the detailer. It can be applied in multiple stages through combine. + * `CustomSamplerDetailerHookProvider` - Apply a hook that allows you to use a custom sampler in the Detailer nodes. When using `DetailerHookCombine`, the sampler from the first hook is applied. ### Iterative Upscale nodes * `Iterative Upscale (Latent/on Pixel Space)` - The upscaler takes the input upscaler and splits the scale_factor into steps, then iteratively performs upscaling. diff --git a/__init__.py b/__init__.py index 829e5d0..8f577c0 100644 --- a/__init__.py +++ b/__init__.py @@ -122,6 +122,7 @@ NODE_CLASS_MAPPINGS = { "UnsamplerHookProvider": UnsamplerHookProvider, "CoreMLDetailerHookProvider": CoreMLDetailerHookProvider, "PreviewDetailerHookProvider": PreviewDetailerHookProvider, + "CustomSamplerDetailerHookProvider": CustomSamplerDetailerHookProvider, "DetailerHookCombine": DetailerHookCombine, "NoiseInjectionDetailerHookProvider": NoiseInjectionDetailerHookProvider, diff --git a/modules/impact/config.py b/modules/impact/config.py index 9370bb2..1096ead 100644 --- a/modules/impact/config.py +++ b/modules/impact/config.py @@ -1,7 +1,7 @@ import configparser import os -version_code = [8, 15, 3] +version_code = [8, 16] version = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '') dependency_version = 24 diff --git a/modules/impact/core.py b/modules/impact/core.py index eb5200f..ccb7f3d 100644 --- a/modules/impact/core.py +++ b/modules/impact/core.py @@ -344,6 +344,10 @@ def enhance_detail(image, model, clip, vae, guide_size, guide_size_for_bbox, max refined_latent = latent_image + sampler_opt=None + if detailer_hook is not None: + sampler_opt = detailer_hook.get_custom_sampler() + # ksampler for i in range(0, cycle): if detailer_hook is not None: @@ -364,7 +368,7 @@ def enhance_detail(image, model, clip, vae, guide_size, guide_size_for_bbox, max refined_latent = impact_sampling.ksampler_wrapper(model2, seed2, steps2, cfg2, sampler_name2, scheduler2, positive2, negative2, refined_latent, denoise2, refiner_ratio, refiner_model, refiner_clip, refiner_positive, refiner_negative, - noise=noise, scheduler_func=scheduler_func) + noise=noise, scheduler_func=scheduler_func, sampler_opt=sampler_opt) if detailer_hook is not None: refined_latent = detailer_hook.pre_decode(refined_latent) @@ -513,11 +517,16 @@ def enhance_detail_for_animatediff(image_frames, model, clip, vae, guide_size, g 'samples': latent_frames } + + sampler_opt=None + if detailer_hook is not None: + sampler_opt = detailer_hook.get_custom_sampler() + if detailer_hook is not None: latent = detailer_hook.post_encode(latent) refined_latent = impact_sampling.ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, - latent, denoise, refiner_ratio, refiner_model, refiner_clip, refiner_positive, refiner_negative, scheduler_func=scheduler_func) + latent, denoise, refiner_ratio, refiner_model, refiner_clip, refiner_positive, refiner_negative, scheduler_func=scheduler_func, sampler_opt=sampler_opt) if detailer_hook is not None: refined_latent = detailer_hook.pre_decode(refined_latent) diff --git a/modules/impact/hooks.py b/modules/impact/hooks.py index ea35ee1..b150dde 100644 --- a/modules/impact/hooks.py +++ b/modules/impact/hooks.py @@ -109,6 +109,12 @@ class DetailerHookCombine(PixelKSampleHookCombine): noise_2nd, is_touched = self.hook2.get_custom_noise(seed, noise, is_touched) return noise, is_touched + def get_custom_sampler(): + if self.hook1.get_custom_sampler() is not None: + return self.hook1.get_custom_sampler() + else: + return self.hook2.get_custom_sampler() + class SimpleCfgScheduleHook(PixelKSampleHook): target_cfg = 0 @@ -173,6 +179,18 @@ class DetailerHook(PixelKSampleHook): def get_custom_noise(self, seed, noise, is_touched): return noise, is_touched + def get_custom_sampler(self): + return None + + +class CustomSamplerDetailerHookProvider(DetailerHook): + def __init__(self, sampler): + super().__init__() + self.sampler = sampler + + def get_custom_sampler(self): + return self.sampler + # class CustomNoiseDetailerHookProvider(DetailerHook): # def __init__(self, noise): diff --git a/modules/impact/impact_pack.py b/modules/impact/impact_pack.py index 64d22c5..e70d15e 100644 --- a/modules/impact/impact_pack.py +++ b/modules/impact/impact_pack.py @@ -811,6 +811,26 @@ class CoreMLDetailerHookProvider: return (hook, ) +class CustomSamplerDetailerHookProvider: + @classmethod + def INPUT_TYPES(s): + return {"required": { + "sampler": ("SAMPLER", ), + }, + } + + RETURN_TYPES = ("DETAILER_HOOK",) + FUNCTION = "doit" + + CATEGORY = "ImpactPack/Detailer" + + DESCRIPTION = "Apply a hook that allows you to use a custom sampler in the Detailer nodes. When using `DetailerHookCombine`, the sampler from the first hook is applied." + + def doit(self, sampler): + hook = hooks.CustomSamplerDetailerHookProvider(sampler) + return (hook, ) + + class CfgScheduleHookProvider: schedules = ["simple"] diff --git a/modules/impact/impact_sampling.py b/modules/impact/impact_sampling.py index 4690942..7ced551 100644 --- a/modules/impact/impact_sampling.py +++ b/modules/impact/impact_sampling.py @@ -194,7 +194,7 @@ def impact_sample(model, seed, steps, cfg, sampler_name, scheduler, positive, ne 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, sigma_factor=1.0, noise=None, scheduler_func=None): + refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None, refiner_negative=None, sigma_factor=1.0, noise=None, scheduler_func=None, sampler_opt=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: # Use separated_sample instead of KSampler for `AYS scheduler` @@ -206,7 +206,7 @@ def ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, refined_latent = separated_sample(model, True, seed, advanced_steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, False, - sigma_ratio=sigma_factor, noise=noise, scheduler_func=scheduler_func) + sigma_ratio=sigma_factor, sampler_opt=sampler_opt, noise=noise, scheduler_func=scheduler_func) else: advanced_steps = math.floor(steps / denoise) start_at_step = advanced_steps - steps @@ -215,7 +215,7 @@ def ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, # print(f"pre: {start_at_step} .. {end_at_step} / {advanced_steps}") temp_latent = separated_sample(model, True, seed, advanced_steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, True, - sigma_ratio=sigma_factor, noise=noise, scheduler_func=scheduler_func) + sigma_ratio=sigma_factor, sampler_opt=sampler_opt, noise=noise, scheduler_func=scheduler_func) if 'noise_mask' in latent_image: # noise_latent = \ @@ -229,7 +229,7 @@ def ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, # print(f"post: {end_at_step} .. {advanced_steps + 1} / {advanced_steps}") refined_latent = separated_sample(refiner_model, False, seed, advanced_steps, cfg, sampler_name, scheduler, refiner_positive, refiner_negative, temp_latent, end_at_step, advanced_steps + 1, False, - sigma_ratio=sigma_factor, scheduler_func=scheduler_func) + sigma_ratio=sigma_factor, sampler_opt=sampler_opt, scheduler_func=scheduler_func) return refined_latent diff --git a/pyproject.toml b/pyproject.toml index 89dfc28..28d67d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui-impact-pack" description = "This node pack offers various detector nodes and detailer nodes that allow you to configure a workflow that automatically enhances facial details. And provide iterative upscaler." -version = "8.15.3" +version = "8.16" license = { file = "LICENSE.txt" } dependencies = ["segment-anything", "scikit-image", "piexif", "transformers", "opencv-python-headless", "GitPython", "scipy>=1.11.4"]