From 04a1eea3c8e43dc9adaf571deaba807f02800758 Mon Sep 17 00:00:00 2001 From: Chan <925355568@qq.com> Date: Thu, 14 Mar 2024 10:14:06 +0800 Subject: [PATCH] add easing_type --- main.py | 24 ++++---- utils.py | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 184 insertions(+), 16 deletions(-) diff --git a/main.py b/main.py index d7a0587..17a5f97 100644 --- a/main.py +++ b/main.py @@ -1,10 +1,9 @@ from nodes import VAEDecode, VAEEncode import comfy -from .utils import image_2dtransform +from .utils import image_2dtransform, apply_easing, easing_functions import torch from tqdm import tqdm -import random @@ -21,6 +20,7 @@ class Easy2DDeforum: "positive": ("CONDITIONING", ), "negative": ("CONDITIONING", ), "image": ("IMAGE", ), + "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), "steps": ("INT", {"default": 20, "min": 1, "max": 10000}), "cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step":0.1, "round": 0.01}), "sampler_name": (comfy.samplers.KSampler.SAMPLERS, ), @@ -32,6 +32,7 @@ class Easy2DDeforum: "angle": ("INT", {"default": -1, "step": 1, "min": -360, "max": 360}), "denoise_min": ("FLOAT", {"default": 0.40, "min": 0.00, "max": 1.00, "step":0.01}), "denoise_max": ("FLOAT", {"default": 0.60, "min": 0.00, "max": 1.00, "step":0.01}), + "easing_type": (list(easing_functions.keys()), ), } } @@ -41,35 +42,36 @@ class Easy2DDeforum: CATEGORY = "easyDeforum" - def apply(self, model, vae, positive, negative, image, frame, steps, cfg, sampler_name, scheduler, x, y, zoom, angle, denoise_min, denoise_max): + def apply(self, model, vae, positive, negative, image, frame, seed, steps, cfg, sampler_name, scheduler, x, y, zoom, angle, denoise_min, denoise_max, easing_type): # 初始化模型 vaedecode = VAEDecode() vaeencode = VAEEncode() res = [image] - seed = random.randint(0, 1000000000) - pbar = comfy.utils.ProgressBar(frame) for i in tqdm(range(frame)): + + # 计算噪声 + denoise = (denoise_max - denoise_min) * apply_easing((i+1)/frame, easing_type) + denoise_min - denoise = (denoise_max - denoise_min) * (i+1) / frame + denoise_min - + # 变换 image = image_2dtransform(image, x, y, zoom, angle, 0, "reflect") + # 编码 latent = vaeencode.encode(vae, image)[0] - # 这里得关闭进度 - # latent = ksampler.sample(model, i, steps, cfg, sampler_name, scheduler, positive, negative, latent, denoise)[0] - # 这里是关闭 + # 计算噪声 noise = comfy.sample.prepare_noise(latent["samples"], i, None) + + # 采样 samples = comfy.sample.sample(model, noise, steps, cfg, sampler_name, scheduler, positive, negative, latent["samples"], denoise=denoise, disable_noise=False, start_step=None, last_step=None, force_full_denoise=False, noise_mask=None, callback=None, disable_pbar=True, seed=seed+i) - + # 解码 image = vaedecode.decode(vae, {"samples": samples})[0] # 这里还能加预览图片 diff --git a/utils.py b/utils.py index e5e7fb2..00ebe47 100644 --- a/utils.py +++ b/utils.py @@ -1,13 +1,13 @@ from typing import List, Union import numpy as np -import torch +import torch, math from PIL import Image import torch import torchvision.transforms.functional as TF -from math import sqrt, ceil from typing import cast + def tensor2pil(image: torch.Tensor) -> List[Image.Image]: batch_count = image.size(0) if len(image.shape) > 3 else 1 if batch_count > 1: @@ -50,8 +50,8 @@ def image_2dtransform( new_height, new_width = int(frame_height * zoom), int(frame_width * zoom) # - Calculate diagonal of the original image - diagonal = sqrt(frame_width**2 + frame_height**2) - max_padding = ceil(diagonal * zoom - min(frame_width, frame_height)) + diagonal = math.sqrt(frame_width**2 + frame_height**2) + max_padding = math.ceil(diagonal * zoom - min(frame_width, frame_height)) # Calculate padding for zoom pw = int(frame_width - new_width) ph = int(frame_height - new_height) @@ -81,4 +81,170 @@ def image_2dtransform( img = img.crop((left, upper, right, bottom)) - return pil2tensor(img) \ No newline at end of file + return pil2tensor(img) + + +# --------------------------- Easing functions +def easeInBack(t): + s = 1.70158 + return t * t * ((s + 1) * t - s) + +def easeOutBack(t): + s = 1.70158 + return ((t - 1) * t * ((s + 1) * t + s)) + 1 + +def easeInOutBack(t): + s = 1.70158 * 1.525 + if t < 0.5: + return (t * t * (t * (s + 1) - s)) * 2 + return ((t - 2) * t * ((s + 1) * t + s) + 2) * 2 + +# Elastic easing functions +def easeInElastic(t): + if t == 0: + return 0 + if t == 1: + return 1 + p = 0.3 + s = p / 4 + return -(math.pow(2, 10 * (t - 1)) * math.sin((t - 1 - s) * (2 * math.pi) / p)) + +def easeOutElastic(t): + if t == 0: + return 0 + if t == 1: + return 1 + p = 0.3 + s = p / 4 + return math.pow(2, -10 * t) * math.sin((t - s) * (2 * math.pi) / p) + 1 + +def easeInOutElastic(t): + if t == 0: + return 0 + if t == 1: + return 1 + p = 0.3 * 1.5 + s = p / 4 + t = t * 2 + if t < 1: + return -0.5 * ( + math.pow(2, 10 * (t - 1)) * math.sin((t - 1 - s) * (2 * math.pi) / p) + ) + return ( + 0.5 * math.pow(2, -10 * (t - 1)) * math.sin((t - 1 - s) * (2 * math.pi) / p) + + 1 + ) + +# Bounce easing functions +def easeInBounce(t): + return 1 - easeOutBounce(1 - t) + +def easeOutBounce(t): + if t < (1 / 2.75): + return 7.5625 * t * t + elif t < (2 / 2.75): + t -= 1.5 / 2.75 + return 7.5625 * t * t + 0.75 + elif t < (2.5 / 2.75): + t -= 2.25 / 2.75 + return 7.5625 * t * t + 0.9375 + else: + t -= 2.625 / 2.75 + return 7.5625 * t * t + 0.984375 + +def easeInOutBounce(t): + if t < 0.5: + return easeInBounce(t * 2) * 0.5 + return easeOutBounce(t * 2 - 1) * 0.5 + 0.5 + +# Quart easing functions +def easeInQuart(t): + return t * t * t * t + +def easeOutQuart(t): + t -= 1 + return -(t**2 * t * t - 1) + +def easeInOutQuart(t): + t *= 2 + if t < 1: + return 0.5 * t * t * t * t + t -= 2 + return -0.5 * (t**2 * t * t - 2) + +# Cubic easing functions +def easeInCubic(t): + return t * t * t + +def easeOutCubic(t): + t -= 1 + return t**2 * t + 1 + +def easeInOutCubic(t): + t *= 2 + if t < 1: + return 0.5 * t * t * t + t -= 2 + return 0.5 * (t**2 * t + 2) + +# Circ easing functions +def easeInCirc(t): + return -(math.sqrt(1 - t * t) - 1) + +def easeOutCirc(t): + t -= 1 + return math.sqrt(1 - t**2) + +def easeInOutCirc(t): + t *= 2 + if t < 1: + return -0.5 * (math.sqrt(1 - t**2) - 1) + t -= 2 + return 0.5 * (math.sqrt(1 - t**2) + 1) + +# Sine easing functions +def easeInSine(t): + return -math.cos(t * (math.pi / 2)) + 1 + +def easeOutSine(t): + return math.sin(t * (math.pi / 2)) + +def easeInOutSine(t): + return -0.5 * (math.cos(math.pi * t) - 1) + +def easeLinear(t): + return t + +easing_functions = { + "Linear": easeLinear, + "Sine In": easeInSine, + "Sine Out": easeOutSine, + "Sine In/Out": easeInOutSine, + "Quart In": easeInQuart, + "Quart Out": easeOutQuart, + "Quart In/Out": easeInOutQuart, + "Cubic In": easeInCubic, + "Cubic Out": easeOutCubic, + "Cubic In/Out": easeInOutCubic, + "Circ In": easeInCirc, + "Circ Out": easeOutCirc, + "Circ In/Out": easeInOutCirc, + "Back In": easeInBack, + "Back Out": easeOutBack, + "Back In/Out": easeInOutBack, + "Elastic In": easeInElastic, + "Elastic Out": easeOutElastic, + "Elastic In/Out": easeInOutElastic, + "Bounce In": easeInBounce, + "Bounce Out": easeOutBounce, + "Bounce In/Out": easeInOutBounce, +} + +def apply_easing(value, easing_type): + function_ease = easing_functions.get(easing_type) + if function_ease: + return function_ease(value) + + raise ValueError(f"Unknown easing type: {easing_type}") + +# --------------------------- Easing functions \ No newline at end of file