Udpate
Add noise blending type and operation used. Add support for Brownian noise samplers Sharpen added noise a wee-bit near the end for possibly better high frequency details
This commit is contained in:
@@ -371,6 +371,10 @@ The `PPFNKSamplerAdvanced` class is part of the Power Noise Suite and provides a
|
||||
|
||||
- `noise_type`: ["white", "grey", "pink", "green", "blue", "mix"]:
|
||||
- The type of [power-law noise](https://en.wikipedia.org/wiki/Colors_of_noise#Technical_definitions) to generate.
|
||||
- `noise_blending`: ["bislerp", "cosine interp", "cuberp", "hslerp", "lerp", "add", "inject"]
|
||||
- The noise blending method used during sampling
|
||||
- `noise_mode`: ["additive", "subtractive"]
|
||||
- The noise operation used on the Power noise added to base noise.
|
||||
- `frequency` (FLOAT): The frequency of the noise range.
|
||||
- Default: 3.141592653589793
|
||||
- Range: 0.001 to 1024.0
|
||||
|
||||
+47
-18
@@ -1,5 +1,6 @@
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
import math
|
||||
|
||||
from .latent_util import normalize
|
||||
|
||||
@@ -14,9 +15,12 @@ def sharpen_latents(latent, alpha=1.5):
|
||||
Returns:
|
||||
torch.Tensor: The sharpened latent tensor.
|
||||
"""
|
||||
# Ensure that all operations are done on the input 'latent' device
|
||||
device = latent.device
|
||||
|
||||
sharpen_kernel = torch.tensor([[-1, -1, -1],
|
||||
[-1, 9, -1],
|
||||
[-1, -1, -1]], dtype=torch.float32)
|
||||
[-1, -1, -1]], dtype=torch.float32, device=device)
|
||||
|
||||
sharpen_kernel = sharpen_kernel.view(1, 1, 3, 3)
|
||||
sharpen_kernel /= sharpen_kernel.sum()
|
||||
@@ -56,8 +60,6 @@ def high_pass_latents(latent, radius=3, strength=1.0):
|
||||
gaussian_kernel = torch.exp(-(x ** 2) / (2 * sigma ** 2))
|
||||
gaussian_kernel = gaussian_kernel / gaussian_kernel.sum()
|
||||
|
||||
padding_size = int((kernel_size - 1) // 2)
|
||||
|
||||
high_pass_overlays = []
|
||||
|
||||
for channel in range(latent.size(1)):
|
||||
@@ -69,20 +71,20 @@ def high_pass_latents(latent, radius=3, strength=1.0):
|
||||
input_blur_h = F.conv2d(
|
||||
channel_tensor,
|
||||
weight_h,
|
||||
padding=(0, padding_size),
|
||||
padding=0,
|
||||
)
|
||||
input_blur_v = F.conv2d(
|
||||
input_blur_h,
|
||||
weight_v,
|
||||
padding=(padding_size, 0),
|
||||
padding=0,
|
||||
)
|
||||
input_blur_h = F.interpolate(input_blur_h, size=(channel_tensor.size(2), channel_tensor.size(3)), mode='nearest')
|
||||
input_blur_v = F.interpolate(input_blur_v, size=(channel_tensor.size(2), channel_tensor.size(3)), mode='nearest')
|
||||
|
||||
input_blur_h = F.interpolate(input_blur_h, size=channel_tensor.shape[-2:], mode='bilinear', align_corners=False)
|
||||
input_blur_v = F.interpolate(input_blur_v, size=channel_tensor.shape[-2:], mode='bilinear', align_corners=False)
|
||||
|
||||
high_pass_component = channel_tensor - input_blur_v
|
||||
|
||||
high_pass_channel = channel_tensor + strength * high_pass_component
|
||||
high_pass_channel = high_pass_channel[:, :, padding_size:-padding_size, padding_size:-padding_size]
|
||||
high_pass_channel = torch.clamp(high_pass_channel, 0, 1)
|
||||
|
||||
high_pass_overlays.append(high_pass_channel)
|
||||
@@ -91,6 +93,42 @@ def high_pass_latents(latent, radius=3, strength=1.0):
|
||||
|
||||
return high_pass_overlay
|
||||
|
||||
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
|
||||
|
||||
blending_modes = {
|
||||
|
||||
# Args:
|
||||
@@ -121,16 +159,7 @@ blending_modes = {
|
||||
|
||||
# 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: (
|
||||
(1 - t) * a + t * b +
|
||||
((torch.norm(b - a, dim=1, keepdim=True) / 6) * torch.tensor([1.0, 0.0, 0.0], device=a.device, dtype=a.dtype)
|
||||
.unsqueeze(0).unsqueeze(2).unsqueeze(3).expand_as(a))
|
||||
if t < 0.5
|
||||
else
|
||||
(1 - t) * a + t * b -
|
||||
((torch.norm(b - a, dim=1, keepdim=True) / 6) * torch.tensor([1.0, 0.0, 0.0], device=a.device, dtype=a.dtype)
|
||||
.unsqueeze(0).unsqueeze(2).unsqueeze(3).expand_as(a))
|
||||
),
|
||||
'hslerp': hslerp,
|
||||
|
||||
# Simulates a glowing effect by applying a formula based on the input tensors a and b, scaled by t.
|
||||
'glow': lambda a, b, t: torch.where(a <= 1, a ** 2 / (1 - b + 1e-6), b * (a - 1) / (a + 1e-6)),
|
||||
|
||||
@@ -54,3 +54,67 @@ def latents_to_images(latents, l2rgb=False):
|
||||
tensors = latents.permute(0, 2, 3, 1)
|
||||
|
||||
return tensors
|
||||
|
||||
def noise_sigma_scale(noise, sigma_min, sigma_max):
|
||||
"""
|
||||
Scales the input noise values to a specified sigma range.
|
||||
|
||||
Args:
|
||||
noise (Tensor): The input noise tensor.
|
||||
sigma_min (float): The lower bound of the sigma range.
|
||||
sigma_max (float): The upper bound of the sigma range.
|
||||
|
||||
Returns:
|
||||
Tensor: The scaled noise tensor within the specified sigma range.
|
||||
"""
|
||||
normalized_noise = normalize(noise)
|
||||
scaled_noise = sigma_min + (sigma_max - sigma_min) * normalized_noise
|
||||
|
||||
return scaled_noise
|
||||
|
||||
def within_percentage_range(num, total, percentage, tolerance_factor):
|
||||
"""
|
||||
Check if a number is within a specified percentage of a total accounting for a tolerance.
|
||||
|
||||
Args:
|
||||
numb (float): The number to check.
|
||||
total (float): The total value against which to compare.
|
||||
percentage (float): The desired percentage (between 0 and 1, e.g., 0.5 for 50%).
|
||||
tolerance_factor (float): The tolerance factor as a percentage (between 0 and 1, e.g., 0.1 for 10%).
|
||||
|
||||
Returns:
|
||||
bool: True if the number is within the specified range, False otherwise.
|
||||
"""
|
||||
lower_bound = total * (percentage - tolerance_factor)
|
||||
upper_bound = total * (percentage + tolerance_factor)
|
||||
return lower_bound <= num <= upper_bound
|
||||
|
||||
|
||||
def scale_from_perentage(number, total, percentage, tolerance_factor):
|
||||
"""
|
||||
Calculate a scaling factor within a percentage tolerance range.
|
||||
|
||||
This function calculates a scaling factor that is 1.0 at the exact percentage value
|
||||
and scales down towards 0.0 within the tolerance_factor range.
|
||||
|
||||
Args:
|
||||
number (float): The number to check against the percentage.
|
||||
total (float): The total value against which the percentage is calculated.
|
||||
percentage (float): The target percentage value (between 0.0 and 1.0).
|
||||
tolerance_factor (float): The tolerance factor for the percentage range.
|
||||
|
||||
Returns:
|
||||
float: A scaling factor that indicates how close the number is to the target percentage
|
||||
within the specified tolerance range. A value of 1.0 indicates an exact match,
|
||||
while values closer to 0.0 indicate deviation from the target within the tolerance range.
|
||||
"""
|
||||
|
||||
lower_bound = percentage - tolerance_factor
|
||||
upper_bound = percentage + tolerance_factor
|
||||
|
||||
if lower_bound <= (number / total) <= upper_bound:
|
||||
return 1.0
|
||||
if lower_bound <= percentage and (number / total) >= lower_bound:
|
||||
return (number / (total / 2)) * 0.25
|
||||
elif upper_bound >= percentage and (number / total) <= upper_bound:
|
||||
return (number / (total / 2)) * 0.25
|
||||
@@ -1,13 +1,20 @@
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
import torchsde
|
||||
import math
|
||||
|
||||
import nodes
|
||||
import comfy.samplers
|
||||
import comfy.k_diffusion.sampling
|
||||
import comfy.model_management
|
||||
|
||||
|
||||
from .modules.latent_util import (
|
||||
normalize,
|
||||
latents_to_images
|
||||
latents_to_images,
|
||||
noise_sigma_scale,
|
||||
scale_from_perentage,
|
||||
within_percentage_range
|
||||
)
|
||||
from .modules.latent_filters import (
|
||||
sharpen_latents,
|
||||
@@ -54,6 +61,7 @@ class PPFNoiseNode:
|
||||
},
|
||||
"optional": {
|
||||
"optional_vae": ("VAE",),
|
||||
"ppf_settings": ("PPF_SETTINGS",),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,9 +69,24 @@ class PPFNoiseNode:
|
||||
RETURN_NAMES = ("latents","previews")
|
||||
FUNCTION = "power_fractal_latent"
|
||||
|
||||
CATEGORY = "Power Noise Suite/Latent/Noise"
|
||||
CATEGORY = "Power Noise Suite/Noise"
|
||||
|
||||
def power_fractal_latent(self, batch_size, width, height, resampling, X, Y, Z, evolution, frame, scale, octaves, persistence, lacunarity, exponent, brightness, contrast, clamp_min, clamp_max, seed, device, optional_vae=None):
|
||||
def power_fractal_latent(self, batch_size, width, height, resampling, X, Y, Z, evolution, frame, scale, octaves, persistence, lacunarity, exponent, brightness, contrast, clamp_min, clamp_max, seed, device, optional_vae=None, ppf_settings=None):
|
||||
|
||||
if ppf_settings:
|
||||
ppf = ppf_settings
|
||||
X = ppf['X']
|
||||
Y = ppf['Y']
|
||||
Z = ppf['Z']
|
||||
evolution = ppf['evolution']
|
||||
frame = ppf['frame']
|
||||
scale = ppf['scale']
|
||||
octaves = ppf['octaves']
|
||||
persistence = ppf['persistence']
|
||||
lacunarity = ppf['lacunarity']
|
||||
exponent = ppf['exponent']
|
||||
brightness = ppf['brightness']
|
||||
contrast = ppf['contrast']
|
||||
|
||||
color_intensity = 1
|
||||
masking_intensity = 1
|
||||
@@ -145,7 +168,7 @@ class PPFNPowerLawNoise:
|
||||
RETURN_NAMES = ("latents", "previews")
|
||||
FUNCTION = "power_noise"
|
||||
|
||||
CATEGORY = "Power Noise Suite/Latent/Noise"
|
||||
CATEGORY = "Power Noise Suite/Noise"
|
||||
|
||||
def power_noise(self, batch_size, width, height, resampling, noise_type, frequency, attenuation, seed, device, optional_vae=None):
|
||||
|
||||
@@ -201,6 +224,7 @@ class PPFNCrossHatchNode:
|
||||
},
|
||||
"optional": {
|
||||
"optional_vae": ("VAE",),
|
||||
"ch_settings": ("CH_SETTINGS",),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,9 +232,21 @@ class PPFNCrossHatchNode:
|
||||
RETURN_NAMES = ("latents","previews")
|
||||
FUNCTION = "cross_hatch"
|
||||
|
||||
CATEGORY = "Power Noise Suite/Latent/Noise"
|
||||
CATEGORY = "Power Noise Suite/Noise"
|
||||
|
||||
def cross_hatch(self, batch_size, width, height, resampling, frequency, octaves, persistence, color_tolerance, num_colors, angle_degrees, brightness, contrast, blur, clamp_min, clamp_max, seed, device, optional_vae=None):
|
||||
def cross_hatch(self, batch_size, width, height, resampling, frequency, octaves, persistence, color_tolerance, num_colors, angle_degrees, brightness, contrast, blur, clamp_min, clamp_max, seed, device, optional_vae=None, ch_settings=None):
|
||||
|
||||
if ch_settings:
|
||||
ch = ch_settings
|
||||
frequency = ch['frequency']
|
||||
octaves = ch['octaves']
|
||||
persistence = ch['persistence']
|
||||
color_tolerance = ch['color_tolerance']
|
||||
num_colors = ch['num_colors']
|
||||
angle_degrees = ch['angle_degrees']
|
||||
brightness = ch['brightness']
|
||||
contrast = ch['contrast']
|
||||
blur = ch['blur']
|
||||
|
||||
cross_hatch = CrossHatchPowerFractal(width=width, height=height, frequency=frequency, octaves=octaves, persistence=persistence, num_colors=num_colors, color_tolerance=color_tolerance, angle_degrees=angle_degrees, blur=blur, clamp_min=clamp_min, clamp_max=clamp_max)
|
||||
tensors = cross_hatch(batch_size, device, seed).to(device="cpu")
|
||||
@@ -268,7 +304,7 @@ class PPFNLinearCrossHatchNode:
|
||||
RETURN_NAMES = ("latents","previews")
|
||||
FUNCTION = "cross_hatch"
|
||||
|
||||
CATEGORY = "Power Noise Suite/Latent/Noise"
|
||||
CATEGORY = "Power Noise Suite/Noise"
|
||||
|
||||
def cross_hatch(self, batch_size, width, height, resampling, frequency, gain, octaves, persistence, add_noise, linear_range, linear_tolerance, angle_degrees, brightness, contrast, seed, device, optional_vae=None):
|
||||
|
||||
@@ -507,7 +543,7 @@ class PPFNKSamplerAdvanced:
|
||||
pln = PowerLawNoise('cpu')
|
||||
noise_types = pln.get_noise_types()
|
||||
noise_types.append('vanilla_comfy')
|
||||
samplers = [x for x in comfy.samplers.KSampler.SAMPLERS if x in ['euler_ancestral', 'dpm_2_ancestral', 'dpmpp_2s_ancestral', 'dpm_fast', 'dpm_adaptive']]
|
||||
samplers = ['dpmpp_sde', 'dpmpp_sde_gpu', 'dpmpp_2m', 'dpmpp_2m_sde', 'dpmpp_2m_sde_gpu', 'dpmpp_3m_sde', 'dpmpp_3m_sde_gpu', 'euler_ancestral', 'dpm_2_ancestral', 'dpmpp_2s_ancestral', 'dpm_fast', 'dpm_adaptive']
|
||||
return {
|
||||
"required": {
|
||||
"model": ("MODEL",),
|
||||
@@ -526,9 +562,12 @@ class PPFNKSamplerAdvanced:
|
||||
},
|
||||
"optional": {
|
||||
"noise_type": (noise_types,),
|
||||
"frequency": ("FLOAT", {"default": 3.141592653589793, "max": 1024.0, "min": 0.001, "step": 0.001}),
|
||||
"noise_blending": (["bislerp", "cosine interp", "cuberp", "hslerp", "lerp", "add", "inject"],),
|
||||
"noise_mode": (["additive", "subtractive"],),
|
||||
"frequency": ("FLOAT", {"default": 64, "max": 1024.0, "min": 0.001, "step": 0.001}),
|
||||
"attenuation": ("FLOAT", {"default": 0.75, "max": 1024.0, "min": 0.001, "step": 0.001}),
|
||||
"sigma_tolerance": ("FLOAT", {"default": 0.5, "max": 1.0, "min": 0.0, "step": 0.001}),
|
||||
"boost_leading_sigma": (["false", "true"],),
|
||||
"ppf_settings": ("PPF_SETTINGS",),
|
||||
"ch_settings": ("CH_SETTINGS",),
|
||||
}
|
||||
@@ -539,12 +578,13 @@ class PPFNKSamplerAdvanced:
|
||||
|
||||
CATEGORY = "Power Noise Suite/Sampling"
|
||||
|
||||
def sample(self, model, add_noise, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, return_with_leftover_noise, denoise=1.0, noise_type='grey', frequency=11.6, attenuation=0.75, sigma_tolerance=1.0, ppf_settings=None, ch_settings=None):
|
||||
|
||||
def ppfn_noise_sampler(x):
|
||||
def sample(self, model, add_noise, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, return_with_leftover_noise, denoise=1.0, noise_type='grey', noise_blending="bislerp", noise_mode="additive", frequency=11.6, attenuation=0.75, sigma_tolerance=1.0, boost_leading_sigma="false", ppf_settings=None, ch_settings=None):
|
||||
|
||||
# WHITE-NOISE SAMPLER HIJACK
|
||||
|
||||
def pns_noise_sampler(x):
|
||||
seed_base = seed
|
||||
noise_idx = [0]
|
||||
sigma_base = [None]
|
||||
height = int(x.shape[2] * 8)
|
||||
width = int(x.shape[3] * 8)
|
||||
method = noise_type
|
||||
@@ -553,8 +593,12 @@ class PPFNKSamplerAdvanced:
|
||||
sigma_tol = sigma_tolerance
|
||||
ppfs = ppf_settings
|
||||
chs = ch_settings
|
||||
total_steps = steps
|
||||
blending_mode = noise_blending
|
||||
blend_type = noise_mode
|
||||
boost_sigma = (boost_leading_sigma == "true")
|
||||
|
||||
def ppfn_return_noise(seed, x, sigma, sigma_tol, method, freq, atten, blending_modes, ppfs, chs):
|
||||
def pns_return_noise(seed, x, sigma, sigma_tol, boost_sigma, total_steps, method, freq, atten, blending_modes, blending_mode, ppfs, chs):
|
||||
seed = seed_base + noise_idx[0]
|
||||
rand_noise = torch.randn_like(x)
|
||||
|
||||
@@ -563,7 +607,17 @@ class PPFNKSamplerAdvanced:
|
||||
|
||||
sigma_min = 0
|
||||
sigma_max = 14.614643096923828
|
||||
scaled_sigma = ((sigma.item() - sigma_min) / (sigma_max - sigma_min)) * sigma_tol
|
||||
if isinstance(sigma, torch.Tensor) and sigma.numel() == 1:
|
||||
sigma = sigma.item()
|
||||
elif isinstance(sigma, float):
|
||||
sigma = sigma
|
||||
else:
|
||||
sigma = 0
|
||||
|
||||
scaled_sigma = ((sigma - sigma_min) / (sigma_max - sigma_min)) * sigma_tol
|
||||
|
||||
if boost_sigma and noise_idx[0] < (total_steps // 4):
|
||||
scaled_sigma = scaled_sigma * 1.25 if scaled_sigma * 1.25 <= 1.0 else 1.0
|
||||
|
||||
if not ppfs and not chs:
|
||||
power_law = PowerLawNoise(device=rand_noise.device)
|
||||
@@ -583,30 +637,133 @@ class PPFNKSamplerAdvanced:
|
||||
alpha = torch.ones((1, x.shape[2], x.shape[3], 1), dtype=x.dtype, device=x.device).permute(0, 3, 1, 2)
|
||||
noise = torch.cat((noise, alpha), dim=1)
|
||||
|
||||
blended_noise = rand_noise + 0.25 * (blending_modes["bislerp"](rand_noise.to(device=rand_noise.device), noise.to(device=rand_noise.device), scaled_sigma) - rand_noise)
|
||||
|
||||
if blend_type == "additive":
|
||||
blended_noise = rand_noise + 0.25 * (blending_modes[blending_mode](rand_noise.to(device=rand_noise.device), noise.to(device=rand_noise.device), scaled_sigma) - rand_noise)
|
||||
else:
|
||||
blended_noise = rand_noise - 0.25 * (blending_modes[blending_mode](rand_noise.to(device=rand_noise.device), noise.to(device=rand_noise.device), scaled_sigma) - rand_noise)
|
||||
|
||||
noise_idx[0] += 1
|
||||
|
||||
return blended_noise
|
||||
|
||||
return lambda sigma, sigma_next, **kwargs: ppfn_return_noise(seed_base + noise_idx[0], x, sigma, sigma_tol, method, freq, atten, blending_modes, ppfs, chs)
|
||||
return lambda sigma, sigma_next, **kwargs: pns_return_noise(seed_base + noise_idx[0], x, sigma, sigma_tol, boost_sigma, total_steps, method, freq, atten, blending_modes, blending_mode, ppfs, chs)
|
||||
|
||||
# BROWNIAN NOISE SAMPLER HIJACK
|
||||
|
||||
class PNSNoiseSampler:
|
||||
|
||||
seed_base = seed
|
||||
noise_idx = [0]
|
||||
method = noise_type
|
||||
freq = frequency
|
||||
atten = attenuation
|
||||
sigma_tol = sigma_tolerance
|
||||
ppfs = ppf_settings
|
||||
chs = ch_settings
|
||||
total_steps = steps
|
||||
blending_mode = noise_blending
|
||||
blend_type = noise_mode
|
||||
boost_sigma = (boost_leading_sigma == "true")
|
||||
|
||||
def __init__(self, x, sigma_min, sigma_max, seed=None, transform=lambda x: x, cpu=False):
|
||||
self.noise_idx = [0]
|
||||
self.x = x
|
||||
self.height = int(x.shape[2] * 8)
|
||||
self.width = int(x.shape[3] * 8)
|
||||
self.sigma_min = sigma_min
|
||||
self.sigma_max = sigma_max
|
||||
self.transform = transform
|
||||
t0, t1 = self.transform(torch.as_tensor(sigma_min)), self.transform(torch.as_tensor(sigma_max))
|
||||
self.tree = comfy.k_diffusion.sampling.BatchedBrownianTree(x, t0, t1, seed, cpu=cpu)
|
||||
|
||||
def __call__(self, sigma, sigma_next):
|
||||
noise = self.sample_noise(self.x, sigma, sigma_next)
|
||||
return noise
|
||||
|
||||
def sample_noise(self, x, sigma, sigma_next):
|
||||
t0, t1 = self.transform(torch.as_tensor(sigma)), self.transform(torch.as_tensor(sigma_next))
|
||||
tree = self.tree(t0, t1) / (t1 - t0).abs().sqrt()
|
||||
|
||||
seed = self.seed_base + self.noise_idx[0]
|
||||
rand_noise = torch.randn_like(x)
|
||||
|
||||
if self.sigma_tol == 0.0:
|
||||
return tree
|
||||
|
||||
sigma_min = self.sigma_min
|
||||
sigma_max = self.sigma_max / 2 # 14.614643096923828
|
||||
if isinstance(sigma, torch.Tensor) and sigma.numel() == 1:
|
||||
sigma = sigma.item()
|
||||
elif isinstance(sigma, float):
|
||||
sigma = sigma
|
||||
else:
|
||||
sigma = 0
|
||||
|
||||
scaled_sigma = (((sigma - sigma_min) / (sigma_max - sigma_min)) * self.sigma_tol) / 2
|
||||
|
||||
if self.boost_sigma and self.noise_idx[0] < (self.total_steps // 4):
|
||||
scaled_sigma = scaled_sigma * 1.25 if scaled_sigma * 1.25 <= 1.0 else 1.0
|
||||
|
||||
ppfs = self.ppfs
|
||||
chs = self.chs
|
||||
|
||||
if not ppfs and not chs:
|
||||
power_law = PowerLawNoise(device=tree.device)
|
||||
noise = power_law(1, self.width, self.height, noise_type=self.method, frequency=self.freq, attenuation=self.atten, seed=seed)
|
||||
elif ppfs:
|
||||
power_fractal = PPFNoiseNode()
|
||||
noise = power_fractal.power_fractal_latent(1, self.width, self.height, 'nearest', ppfs['X'], ppfs['Y'], ppfs['Z'], ppfs['evolution'], ppfs['frame'], ppfs['scale'], ppfs['octaves'], ppfs['persistence'], ppfs['lacunarity'], ppfs['exponent'], ppfs['brightness'], ppfs['contrast'], 0.0, 1.0, seed, device=('cuda' if torch.cuda.is_available() else 'cpu'), optional_vae=None)[0]['samples'].to(device=tree.device)
|
||||
elif chs:
|
||||
ch_fractal = PPFNCrossHatchNode()
|
||||
noise = ch_fractal.cross_hatch(1, self.width, self.height, 'nearest', chs['frequency'], chs['octaves'], chs['persistence'], chs['color_tolerance'], chs['num_colors'], chs['angle_degrees'], chs['brightness'], chs['contrast'], chs['blur'], 0.0, 1.0, seed, device=('cuda' if torch.cuda.is_available() else 'cpu'), optional_vae=None)[0]['samples'].to(device=tree.device)
|
||||
|
||||
noise = noise_sigma_scale(noise, self.sigma_min, self.sigma_max)
|
||||
|
||||
noise = noise.permute(0, 3, 1, 2)
|
||||
noise = F.interpolate(noise, size=(x.shape[2], x.shape[3]), mode='nearest')
|
||||
noise = noise[:, :tree.shape[1], :, :]
|
||||
|
||||
if not ppfs and not chs:
|
||||
alpha = torch.ones((1, x.shape[2], x.shape[3], 1), dtype=x.dtype, device=x.device).permute(0, 3, 1, 2)
|
||||
noise = torch.cat((noise, alpha), dim=1)
|
||||
|
||||
if self.blend_type == "additive":
|
||||
blended_noise = tree + 0.025 * (blending_modes[self.blending_mode](tree.to(device=tree.device), sharpen_latents(noise.to(device=tree.device), 1.5), scaled_sigma) - tree)
|
||||
else:
|
||||
blended_noise = tree - 0.025 * (blending_modes[self.blending_mode](tree.to(device=tree.device), sharpen_latents(noise.to(device=tree.device), 1.5), scaled_sigma) - tree)
|
||||
|
||||
self.noise_idx[0] += 1
|
||||
|
||||
return blended_noise
|
||||
|
||||
force_full_denoise = True
|
||||
if return_with_leftover_noise == "enable":
|
||||
force_full_denoise = False
|
||||
disable_noise = False
|
||||
|
||||
if add_noise == "disable":
|
||||
disable_noise = True
|
||||
else:
|
||||
if noise_type != "vanilla_comfy":
|
||||
print("Running with PNS Noise Samplers")
|
||||
dns = comfy.k_diffusion.sampling.default_noise_sampler
|
||||
comfy.k_diffusion.sampling.default_noise_sampler = ppfn_noise_sampler
|
||||
btns = comfy.k_diffusion.sampling.BrownianTreeNoiseSampler
|
||||
comfy.k_diffusion.sampling.default_noise_sampler = pns_noise_sampler
|
||||
comfy.k_diffusion.sampling.BrownianTreeNoiseSampler = PNSNoiseSampler
|
||||
|
||||
result = nodes.common_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=denoise, disable_noise=disable_noise, start_step=start_at_step, last_step=end_at_step, force_full_denoise=force_full_denoise)
|
||||
|
||||
try:
|
||||
result = nodes.common_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=denoise, disable_noise=disable_noise, start_step=start_at_step, last_step=end_at_step, force_full_denoise=force_full_denoise)
|
||||
except comfy.model_management.InterruptProcessingException as e:
|
||||
if noise_type != "vanilla_comfy":
|
||||
print("Restoring ComfyUI Noise Samplers.")
|
||||
comfy.k_diffusion.sampling.default_noise_sampler = dns
|
||||
comfy.k_diffusion.sampling.BrownianTreeNoiseSampler = btns
|
||||
raise e
|
||||
|
||||
if noise_type != "vanilla_comfy":
|
||||
print("\nRestoring ComfyUI Noise Samplers")
|
||||
comfy.k_diffusion.sampling.default_noise_sampler = dns
|
||||
comfy.k_diffusion.sampling.BrownianTreeNoiseSampler = btns
|
||||
|
||||
return result
|
||||
|
||||
|
||||
Reference in New Issue
Block a user