diff --git a/nodes.py b/nodes.py index 2d1b626..c256be6 100644 --- a/nodes.py +++ b/nodes.py @@ -9,7 +9,7 @@ import librosa from scipy.special import erf from .fluid import Fluid import comfy.model_management - +import math from nodes import MAX_RESOLUTION script_dir = os.path.dirname(os.path.abspath(__file__)) @@ -266,6 +266,83 @@ class CreateFadeMask: return (1.0 - torch.cat(out, dim=0),) return (torch.cat(out, dim=0),) +class CrossFadeImages: + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "crossfadeimages" + CATEGORY = "KJNodes" + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "images_1": ("IMAGE",), + "images_2": ("IMAGE",), + "interpolation": (["linear", "ease_in", "ease_out", "ease_in_out", "bounce", "elastic", "glitchy", "exponential_ease_out"],), + "transition_start_index": ("INT", {"default": 1,"min": 0, "max": 4096, "step": 1}), + "transitioning_frames": ("INT", {"default": 1,"min": 0, "max": 4096, "step": 1}), + "start_level": ("FLOAT", {"default": 1.0,"min": 0.0, "max": 1.0, "step": 0.01}), + "end_level": ("FLOAT", {"default": 0.0,"min": 0.0, "max": 1.0, "step": 0.01}), + }, + } + + def crossfadeimages(self, images_1, images_2, transition_start_index, transitioning_frames, interpolation, start_level, end_level): + + def crossfade(images_1, images_2, alpha): + crossfade = (1 - alpha) * images_1 + alpha * images_2 + return crossfade + def ease_in(t): + return t * t + def ease_out(t): + return 1 - (1 - t) * (1 - t) + def ease_in_out(t): + return 3 * t * t - 2 * t * t * t + def bounce(t): + if t < 0.5: + return self.ease_out(t * 2) * 0.5 + else: + return self.ease_in((t - 0.5) * 2) * 0.5 + 0.5 + def elastic(t): + return math.sin(13 * math.pi / 2 * t) * math.pow(2, 10 * (t - 1)) + def glitchy(t): + return t + 0.1 * math.sin(40 * t) + def exponential_ease_out(t): + return 1 - (1 - t) ** 4 + + easing_functions = { + "linear": lambda t: t, + "ease_in": ease_in, + "ease_out": ease_out, + "ease_in_out": ease_in_out, + "bounce": bounce, + "elastic": elastic, + "glitchy": glitchy, + "exponential_ease_out": exponential_ease_out, + } + + + batch_size = images_1.size(0) + crossfade_images = [] + #transition_frame_length = int(batch_size / transitioning_frames) + + alphas = torch.linspace(start_level, end_level, batch_size) + for i in range(batch_size): + alpha = alphas[i] + image1 = images_1[i] + image2 = images_2[i] + easing_function = easing_functions.get(interpolation) + if i >= transition_start_index and i < transition_start_index + transitioning_frames: + # Apply transition effect within the transition frame length + transition_alpha = (i - transition_start_index) / transitioning_frames + alpha = easing_function(transition_alpha) # Apply the easing function to the alpha value + else: + alpha = end_level if i < transition_start_index else start_level + + crossfade_image = crossfade(image1, image2, alpha) + crossfade_images.append(crossfade_image) + + return (torch.stack(crossfade_images, dim=0),) + class CreateTextMask: RETURN_TYPES = ("IMAGE", "MASK",) @@ -764,6 +841,7 @@ NODE_CLASS_MAPPINGS = { "CreateFadeMask": CreateFadeMask, "CreateFluidMask" :CreateFluidMask, "VRAM_Debug" : VRAM_Debug, + "CrossFadeImages": CrossFadeImages } NODE_DISPLAY_NAME_MAPPINGS = { "INTConstant": "INT Constant", @@ -779,4 +857,5 @@ NODE_DISPLAY_NAME_MAPPINGS = { "CreateFadeMask" : "CreateFadeMask", "CreateFluidMask" : "CreateFluidMask", "VRAM_Debug" : "VRAM Debug", + "CrossFadeImages": "CrossFadeImages" } \ No newline at end of file