Refactor for ComfyUI Manager compatibility

This commit is contained in:
Jordan Thompson
2023-09-30 23:30:10 -07:00
parent 96e2392579
commit 2a9ebc4ae5
8 changed files with 388 additions and 350 deletions
+189 -189
View File
@@ -1,189 +1,189 @@
import torch
import math
def normalize(latent, target_min=None, target_max=None):
"""
Normalize a tensor `latent` between `target_min` and `target_max`.
Args:
latent (torch.Tensor): The input tensor to be normalized.
target_min (float, optional): The minimum value after normalization.
- When `None` min will be tensor min range value.
target_max (float, optional): The maximum value after normalization.
- When `None` max will be tensor max range value.
Returns:
torch.Tensor: The normalized tensor
"""
min_val = latent.min()
max_val = latent.max()
if target_min is None:
target_min = min_val
if target_max is None:
target_max = max_val
normalized = (latent - min_val) / (max_val - min_val)
scaled = normalized * (target_max - target_min) + target_min
return scaled
def slerp(a, b, t):
"""
Perform Spherical Linear Interpolation (SLERP) between two tensors.
This function interpolates between two input tensors `a` and `b` using SLERP,
which is a method for smoothly transitioning between orientations or vectors
represented as tensors.
Args:
a (tensor): The first input tensor.
b (tensor): The second input tensor.
t (float): The blending factor, a value between 0 and 1 that controls the interpolation.
Returns:
tensor: The result of SLERP interpolation between `a` and `b`.
Note:
SLERP provides a smooth, shortest-path interpolation between two orientations or vectors
represented as tensors. It's commonly used in applications like 3D graphics and robotics.
"""
if a.shape != b.shape:
raise ValueError("Input tensors a and b must have the same shape.")
a = torch.nn.functional.normalize(a, dim=-1)
b = torch.nn.functional.normalize(b, dim=-1)
dot_product = torch.sum(a * b, dim=-1).clamp(-1.0, 1.0)
angle = torch.acos(dot_product)
slerp_result = (
(a * torch.sin((1 - t) * angle) + b * torch.sin(t * angle)) /
torch.sin(angle)
)
slerp_result = normalize(slerp_result)
return slerp_result
def hslerp(a, b, t):
"""
Perform Hybrid Spherical Linear Interpolation (HSLERP) between two tensors.
This function combines two input tensors `a` and `b` using HSLERP, which is a specialized
interpolation method for smooth transitions between orientations or colors.
Args:
a (tensor): The first input tensor.
b (tensor): The second input tensor.
t (float): The blending factor, a value between 0 and 1 that controls the interpolation.
Returns:
tensor: The result of HSLERP interpolation between `a` and `b`.
Note:
HSLERP provides smooth transitions between orientations or colors, particularly useful
in applications like image processing and 3D graphics.
"""
if a.shape != b.shape:
raise ValueError("Input tensors a and b must have the same shape.")
num_channels = a.size(1)
interpolation_tensor = torch.zeros(1, num_channels, 1, 1, device=a.device, dtype=a.dtype)
interpolation_tensor[0, 0, 0, 0] = 1.0
result = (1 - t) * a + t * b
if t < 0.5:
result += (torch.norm(b - a, dim=1, keepdim=True) / 6) * interpolation_tensor
else:
result -= (torch.norm(b - a, dim=1, keepdim=True) / 6) * interpolation_tensor
return result
import torch
blending_modes = {
# Linearly combines the two input tensors a and b using the parameter t.
'add': lambda a, b, t: (a * t + b * (1 - t)),
# Interpolates between tensors a and b using normalized linear interpolation.
'bislerp': lambda a, b, t: (a * (1 - t) + b * t),
# Interpolates between tensors a and b using cosine interpolation.
'cosine interp': lambda a, b, t: (a + b - (a - b) * torch.cos(t * torch.tensor(math.pi))) / 2,
# Interpolates between tensors a and b using cubic interpolation.
'cuberp': lambda a, b, t: a + (b - a) * (3 * t ** 2 - 2 * t ** 3),
# Computes the absolute difference between tensors a and b, scaled by t.
'difference': lambda a, b, t: (abs(a - b) * t),
# Combines tensors a and b using an exclusion formula, scaled by t.
'exclusion': lambda a, b, t: ((a + b - 2 * a * b) * t),
# Interpolates between tensors a and b using normalized linear interpolation,
# with a twist when t is greater than or equal to 0.5.
'hslerp': lambda a, b, t: (a * (1 - t) + b * t) if t < 0.5 else (a * t + b * (1 - t)),
# Adds tensor b to tensor a, scaled by t.
'inject': lambda a, b, t: (a + b * t),
# Interpolates between tensors a and b using linear interpolation.
'lerp': lambda a, b, t: (a * (1 - t) + b * t),
# Generates random values and combines tensors a and b with random weights, scaled by t.
'random': lambda a, b, t: (a + (torch.rand_like(b) * b - a) * t),
# Interpolates between tensors a and b using spherical linear interpolation (SLERP).
'slerp': lambda a, b, t: (a * (1 - t) + b * t),
# Subtracts tensor b from tensor a, scaled by t.
'subtract': lambda a, b, t: (a * t - b * t),
}
class WAS_ConditioningBlend:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"conditioning_a": ("CONDITIONING", ),
"conditioning_b": ("CONDITIONING", ),
"blending_mode": (list(blending_modes.keys()), ),
"blending_strength": ("FLOAT", {"default": 0.5, "min": -10.0, "max": 10.0, "step": 0.001}),
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
}
}
RETURN_TYPES = ("CONDITIONING",)
RETURN_NAMES = ("conditioning",)
FUNCTION = "combine"
CATEGORY = "conditioning"
def combine(self, conditioning_a, conditioning_b, blending_mode, blending_strength, seed):
if seed > 0:
torch.manual_seed(seed)
a = conditioning_a[0][0].clone()
b = conditioning_b[0][0].clone()
pa = conditioning_a[0][1]["pooled_output"].clone()
pb = conditioning_b[0][1]["pooled_output"].clone()
cond = normalize(blending_modes[blending_mode](a, b, 1 - blending_strength))
pooled = normalize(blending_modes[blending_mode](pa, pb, 1 - blending_strength))
conditioning = [[cond, {"pooled_output": pooled}]]
return (conditioning, )
NODE_CLASS_MAPPINGS = {
"ConditioningBlend": WAS_ConditioningBlend,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"ConditioningBlend": "Conditioning (Blend)",
}
import torch
import math
def normalize(latent, target_min=None, target_max=None):
"""
Normalize a tensor `latent` between `target_min` and `target_max`.
Args:
latent (torch.Tensor): The input tensor to be normalized.
target_min (float, optional): The minimum value after normalization.
- When `None` min will be tensor min range value.
target_max (float, optional): The maximum value after normalization.
- When `None` max will be tensor max range value.
Returns:
torch.Tensor: The normalized tensor
"""
min_val = latent.min()
max_val = latent.max()
if target_min is None:
target_min = min_val
if target_max is None:
target_max = max_val
normalized = (latent - min_val) / (max_val - min_val)
scaled = normalized * (target_max - target_min) + target_min
return scaled
def slerp(a, b, t):
"""
Perform Spherical Linear Interpolation (SLERP) between two tensors.
This function interpolates between two input tensors `a` and `b` using SLERP,
which is a method for smoothly transitioning between orientations or vectors
represented as tensors.
Args:
a (tensor): The first input tensor.
b (tensor): The second input tensor.
t (float): The blending factor, a value between 0 and 1 that controls the interpolation.
Returns:
tensor: The result of SLERP interpolation between `a` and `b`.
Note:
SLERP provides a smooth, shortest-path interpolation between two orientations or vectors
represented as tensors. It's commonly used in applications like 3D graphics and robotics.
"""
if a.shape != b.shape:
raise ValueError("Input tensors a and b must have the same shape.")
a = torch.nn.functional.normalize(a, dim=-1)
b = torch.nn.functional.normalize(b, dim=-1)
dot_product = torch.sum(a * b, dim=-1).clamp(-1.0, 1.0)
angle = torch.acos(dot_product)
slerp_result = (
(a * torch.sin((1 - t) * angle) + b * torch.sin(t * angle)) /
torch.sin(angle)
)
slerp_result = normalize(slerp_result)
return slerp_result
def hslerp(a, b, t):
"""
Perform Hybrid Spherical Linear Interpolation (HSLERP) between two tensors.
This function combines two input tensors `a` and `b` using HSLERP, which is a specialized
interpolation method for smooth transitions between orientations or colors.
Args:
a (tensor): The first input tensor.
b (tensor): The second input tensor.
t (float): The blending factor, a value between 0 and 1 that controls the interpolation.
Returns:
tensor: The result of HSLERP interpolation between `a` and `b`.
Note:
HSLERP provides smooth transitions between orientations or colors, particularly useful
in applications like image processing and 3D graphics.
"""
if a.shape != b.shape:
raise ValueError("Input tensors a and b must have the same shape.")
num_channels = a.size(1)
interpolation_tensor = torch.zeros(1, num_channels, 1, 1, device=a.device, dtype=a.dtype)
interpolation_tensor[0, 0, 0, 0] = 1.0
result = (1 - t) * a + t * b
if t < 0.5:
result += (torch.norm(b - a, dim=1, keepdim=True) / 6) * interpolation_tensor
else:
result -= (torch.norm(b - a, dim=1, keepdim=True) / 6) * interpolation_tensor
return result
import torch
blending_modes = {
# Linearly combines the two input tensors a and b using the parameter t.
'add': lambda a, b, t: (a * t + b * (1 - t)),
# Interpolates between tensors a and b using normalized linear interpolation.
'bislerp': lambda a, b, t: (a * (1 - t) + b * t),
# Interpolates between tensors a and b using cosine interpolation.
'cosine interp': lambda a, b, t: (a + b - (a - b) * torch.cos(t * torch.tensor(math.pi))) / 2,
# Interpolates between tensors a and b using cubic interpolation.
'cuberp': lambda a, b, t: a + (b - a) * (3 * t ** 2 - 2 * t ** 3),
# Computes the absolute difference between tensors a and b, scaled by t.
'difference': lambda a, b, t: (abs(a - b) * t),
# Combines tensors a and b using an exclusion formula, scaled by t.
'exclusion': lambda a, b, t: ((a + b - 2 * a * b) * t),
# Interpolates between tensors a and b using normalized linear interpolation,
# with a twist when t is greater than or equal to 0.5.
'hslerp': lambda a, b, t: (a * (1 - t) + b * t) if t < 0.5 else (a * t + b * (1 - t)),
# Adds tensor b to tensor a, scaled by t.
'inject': lambda a, b, t: (a + b * t),
# Interpolates between tensors a and b using linear interpolation.
'lerp': lambda a, b, t: (a * (1 - t) + b * t),
# Generates random values and combines tensors a and b with random weights, scaled by t.
'random': lambda a, b, t: (a + (torch.rand_like(b) * b - a) * t),
# Interpolates between tensors a and b using spherical linear interpolation (SLERP).
'slerp': lambda a, b, t: (a * (1 - t) + b * t),
# Subtracts tensor b from tensor a, scaled by t.
'subtract': lambda a, b, t: (a * t - b * t),
}
class WAS_ConditioningBlend:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"conditioning_a": ("CONDITIONING", ),
"conditioning_b": ("CONDITIONING", ),
"blending_mode": (list(blending_modes.keys()), ),
"blending_strength": ("FLOAT", {"default": 0.5, "min": -10.0, "max": 10.0, "step": 0.001}),
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
}
}
RETURN_TYPES = ("CONDITIONING",)
RETURN_NAMES = ("conditioning",)
FUNCTION = "combine"
CATEGORY = "conditioning"
def combine(self, conditioning_a, conditioning_b, blending_mode, blending_strength, seed):
if seed > 0:
torch.manual_seed(seed)
a = conditioning_a[0][0].clone()
b = conditioning_b[0][0].clone()
pa = conditioning_a[0][1]["pooled_output"].clone()
pb = conditioning_b[0][1]["pooled_output"].clone()
cond = normalize(blending_modes[blending_mode](a, b, 1 - blending_strength))
pooled = normalize(blending_modes[blending_mode](pa, pb, 1 - blending_strength))
conditioning = [[cond, {"pooled_output": pooled}]]
return (conditioning, )
NODE_CLASS_MAPPINGS = {
"ConditioningBlend": WAS_ConditioningBlend,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"ConditioningBlend": "Conditioning (Blend)",
}
@@ -1,61 +1,61 @@
# Provides demonstration of PR https://github.com/comfyanonymous/ComfyUI/pull/1574/commits/297d1cff422198806cda40e4b6d71a6e6aa05453
import torch
class WAS_VAEEncodeForInpaint:
@classmethod
def INPUT_TYPES(s):
return {"required": { "pixels": ("IMAGE", ), "vae": ("VAE", ), "mask": ("MASK", ), "mask_offset": ("INT", {"default": 6, "min": -128, "max": 128, "step": 1}),}}
RETURN_TYPES = ("LATENT",)
FUNCTION = "encode"
CATEGORY = "latent/inpaint"
def encode(self, vae, pixels, mask, mask_offset=6):
x = (pixels.shape[1] // 8) * 8
y = (pixels.shape[2] // 8) * 8
mask = torch.nn.functional.interpolate(mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])), size=(pixels.shape[1], pixels.shape[2]), mode="bilinear")
pixels = pixels.clone()
if pixels.shape[1] != x or pixels.shape[2] != y:
x_offset = (pixels.shape[1] % 8) // 2
y_offset = (pixels.shape[2] % 8) // 2
pixels = pixels[:,x_offset:x + x_offset, y_offset:y + y_offset,:]
mask = mask[:,:,x_offset:x + x_offset, y_offset:y + y_offset]
mask_erosion = self.modify_mask(mask, mask_offset)
m = (1.0 - mask_erosion.round()).squeeze(1)
for i in range(3):
pixels[:,:,:,i] -= 0.5
pixels[:,:,:,i] *= m
pixels[:,:,:,i] += 0.5
t = vae.encode(pixels)
return ({"samples":t, "noise_mask": (mask_erosion[:,:,:x,:y].round())}, )
def modify_mask(self, mask, modify_by):
if modify_by == 0:
return mask
if modify_by > 0:
kernel_size = 2 * modify_by + 1
kernel_tensor = torch.ones((1, 1, kernel_size, kernel_size))
padding = modify_by
modified_mask = torch.clamp(torch.nn.functional.conv2d(mask.round(), kernel_tensor, padding=padding), 0, 1)
else:
kernel_size = 2 * abs(modify_by) + 1
kernel_tensor = torch.ones((1, 1, kernel_size, kernel_size))
padding = abs(modify_by)
eroded_mask = torch.nn.functional.conv2d(1 - mask.round(), kernel_tensor, padding=padding)
modified_mask = torch.clamp(1 - eroded_mask, 0, 1)
return modified_mask
NODE_CLASS_MAPPINGS = {
"VAEEncodeForInpaint (WAS)": WAS_VAEEncodeForInpaint,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"VAEEncodeForInpaint (WAS)": "Inpainting VAE Encode (WAS)",
# Provides demonstration of PR https://github.com/comfyanonymous/ComfyUI/pull/1574/commits/297d1cff422198806cda40e4b6d71a6e6aa05453
import torch
class WAS_VAEEncodeForInpaint:
@classmethod
def INPUT_TYPES(s):
return {"required": { "pixels": ("IMAGE", ), "vae": ("VAE", ), "mask": ("MASK", ), "mask_offset": ("INT", {"default": 6, "min": -128, "max": 128, "step": 1}),}}
RETURN_TYPES = ("LATENT",)
FUNCTION = "encode"
CATEGORY = "latent/inpaint"
def encode(self, vae, pixels, mask, mask_offset=6):
x = (pixels.shape[1] // 8) * 8
y = (pixels.shape[2] // 8) * 8
mask = torch.nn.functional.interpolate(mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])), size=(pixels.shape[1], pixels.shape[2]), mode="bilinear")
pixels = pixels.clone()
if pixels.shape[1] != x or pixels.shape[2] != y:
x_offset = (pixels.shape[1] % 8) // 2
y_offset = (pixels.shape[2] % 8) // 2
pixels = pixels[:,x_offset:x + x_offset, y_offset:y + y_offset,:]
mask = mask[:,:,x_offset:x + x_offset, y_offset:y + y_offset]
mask_erosion = self.modify_mask(mask, mask_offset)
m = (1.0 - mask_erosion.round()).squeeze(1)
for i in range(3):
pixels[:,:,:,i] -= 0.5
pixels[:,:,:,i] *= m
pixels[:,:,:,i] += 0.5
t = vae.encode(pixels)
return ({"samples":t, "noise_mask": (mask_erosion[:,:,:x,:y].round())}, )
def modify_mask(self, mask, modify_by):
if modify_by == 0:
return mask
if modify_by > 0:
kernel_size = 2 * modify_by + 1
kernel_tensor = torch.ones((1, 1, kernel_size, kernel_size))
padding = modify_by
modified_mask = torch.clamp(torch.nn.functional.conv2d(mask.round(), kernel_tensor, padding=padding), 0, 1)
else:
kernel_size = 2 * abs(modify_by) + 1
kernel_tensor = torch.ones((1, 1, kernel_size, kernel_size))
padding = abs(modify_by)
eroded_mask = torch.nn.functional.conv2d(1 - mask.round(), kernel_tensor, padding=padding)
modified_mask = torch.clamp(1 - eroded_mask, 0, 1)
return modified_mask
NODE_CLASS_MAPPINGS = {
"VAEEncodeForInpaint (WAS)": WAS_VAEEncodeForInpaint,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"VAEEncodeForInpaint (WAS)": "Inpainting VAE Encode (WAS)",
}
+101 -101
View File
@@ -1,101 +1,101 @@
import torch
import numpy as np
from PIL import Image, ImageOps, ImageFilter, ImageEnhance
# Tensor to PIL
def tensor2pil(image):
return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))
# PIL to Tensor
def pil2tensor(image):
return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0)
# Vivid Light and Overlay methods adopted from layeris (an overlooked gem)
# https://github.com/subwaymatch/layer-is-python
def vivid_light(A, B, opacity=1.0):
with np.errstate(divide='ignore', invalid='ignore'):
b = np.where(B > 0, 1 - (1 - A) / (2 * B), 0)
d = np.where(B < 1, A / (2 * (1 - B)), 1)
result = np.clip(np.where(B <= 0.5, b, d), 0, 1)
return alpha_blend(A, result, opacity)
def overlay(A, B, opacity=1.0):
B = rgb_float_if_hex(B)
d1 = (2 * A) * B
d2 = 1 - 2 * (1 - A) * (1 - B)
result = np.where(A <= 0.5, d1, d2)
return alpha_blend(A, result, opacity)
def alpha_blend(base, blend, opacity):
if opacity < 1.0:
return base * (1.0 - opacity) + blend * opacity
return blend
def hex_to_rgb_float(hex_string):
return np.array(list((int(hex_string.lstrip('#')[i:i + 2], 16) / 255) for i in (0, 2, 4)))
def rgb_float_if_hex(blend_data):
if isinstance(blend_data, str):
return hex_to_rgb_float(blend_data)
return blend_data
def vivid_sharpen(image, radius=5, strength=1.0):
original = image.copy()
sg = Image.new('RGB', original.size, (255, 255, 255))
sg.paste(original, (0, 0))
sg = ImageOps.invert(sg)
sg = sg.filter(ImageFilter.GaussianBlur(radius=radius))
original_data = np.array(original).astype(float) / 255.0
sg_data = np.array(sg).astype(float) / 255.0
result_data = vivid_light(original_data, sg_data, 1.0)
result_data = overlay(original_data, result_data, 1.0)
result_image = Image.fromarray((result_data * 255).astype('uint8'))
result_image = Image.blend(original, result_image, strength)
return result_image
class VividSharpen:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"images": ("IMAGE",),
"radius": ("FLOAT", {"default": 1.5, "min": 0.01, "max": 64.0, "step": 0.01}),
"strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
},
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("images",)
FUNCTION = "sharpen"
CATEGORY = "image/postprocessing"
def sharpen(self, images, radius, strength):
results = []
if images.size(0) > 1:
for image in images:
image = tensor2pil(image)
results.append(pil2tensor(vivid_sharpen(image, radius=radius, strength=strength)))
results = torch.cat(results, dim=0)
else:
results = pil2tensor(vivid_sharpen(tensor2pil(images), radius=radius, strength=strength))
return (results,)
NODE_CLASS_MAPPINGS = {
"VividSharpen": VividSharpen,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"VividSharpen": "VividSharpen",
}
import torch
import numpy as np
from PIL import Image, ImageOps, ImageFilter, ImageEnhance
# Tensor to PIL
def tensor2pil(image):
return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))
# PIL to Tensor
def pil2tensor(image):
return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0)
# Vivid Light and Overlay methods adopted from layeris (an overlooked gem)
# https://github.com/subwaymatch/layer-is-python
def vivid_light(A, B, opacity=1.0):
with np.errstate(divide='ignore', invalid='ignore'):
b = np.where(B > 0, 1 - (1 - A) / (2 * B), 0)
d = np.where(B < 1, A / (2 * (1 - B)), 1)
result = np.clip(np.where(B <= 0.5, b, d), 0, 1)
return alpha_blend(A, result, opacity)
def overlay(A, B, opacity=1.0):
B = rgb_float_if_hex(B)
d1 = (2 * A) * B
d2 = 1 - 2 * (1 - A) * (1 - B)
result = np.where(A <= 0.5, d1, d2)
return alpha_blend(A, result, opacity)
def alpha_blend(base, blend, opacity):
if opacity < 1.0:
return base * (1.0 - opacity) + blend * opacity
return blend
def hex_to_rgb_float(hex_string):
return np.array(list((int(hex_string.lstrip('#')[i:i + 2], 16) / 255) for i in (0, 2, 4)))
def rgb_float_if_hex(blend_data):
if isinstance(blend_data, str):
return hex_to_rgb_float(blend_data)
return blend_data
def vivid_sharpen(image, radius=5, strength=1.0):
original = image.copy()
sg = Image.new('RGB', original.size, (255, 255, 255))
sg.paste(original, (0, 0))
sg = ImageOps.invert(sg)
sg = sg.filter(ImageFilter.GaussianBlur(radius=radius))
original_data = np.array(original).astype(float) / 255.0
sg_data = np.array(sg).astype(float) / 255.0
result_data = vivid_light(original_data, sg_data, 1.0)
result_data = overlay(original_data, result_data, 1.0)
result_image = Image.fromarray((result_data * 255).astype('uint8'))
result_image = Image.blend(original, result_image, strength)
return result_image
class VividSharpen:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"images": ("IMAGE",),
"radius": ("FLOAT", {"default": 1.5, "min": 0.01, "max": 64.0, "step": 0.01}),
"strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
},
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("images",)
FUNCTION = "sharpen"
CATEGORY = "image/postprocessing"
def sharpen(self, images, radius, strength):
results = []
if images.size(0) > 1:
for image in images:
image = tensor2pil(image)
results.append(pil2tensor(vivid_sharpen(image, radius=radius, strength=strength)))
results = torch.cat(results, dim=0)
else:
results = pil2tensor(vivid_sharpen(tensor2pil(images), radius=radius, strength=strength))
return (results,)
NODE_CLASS_MAPPINGS = {
"VividSharpen": VividSharpen,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"VividSharpen": "VividSharpen",
}
+38
View File
@@ -0,0 +1,38 @@
import importlib
import time
extras = [
".ConditioningBlend",
".VAEEncodeForInpaint",
".VividSharpen",
]
NODE_CLASS_MAPPINGS = {}
NODE_DISPLAY_NAME_MAPPINGS = {}
module_timings = {}
print("[\033[94m\033[1mWAS Extras\033[0m] Loading extra custom nodes...")
for module_name in extras:
start_time = time.time()
success = True
try:
module = importlib.import_module(module_name, package=__name__)
except Exception:
success = False
pass
end_time = time.time()
timing = end_time - start_time
module_timings[module.__file__] = (timing, success)
NODE_CLASS_MAPPINGS.update(getattr(module, 'NODE_CLASS_MAPPINGS', {}))
NODE_DISPLAY_NAME_MAPPINGS.update(getattr(module, 'NODE_DISPLAY_NAME_MAPPINGS', {}))
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
print("[\033[94m\033[1mWAS Extras\033[0m] Import times for extras:")
for module, (timing, success) in module_timings.items():
print(f" {timing:.1f} seconds{('' if success else ' (IMPORT FAILED)')}: {module}")
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.