Add latent frequency split node

This commit is contained in:
Ken Simpson
2025-09-29 14:49:40 -07:00
parent 89dcea44c9
commit 574ade726f
2 changed files with 74 additions and 0 deletions
+5
View File
@@ -18,6 +18,10 @@ Runs the rectified-flow ODE backwards to re-noise an encoded latent. Supports de
Applies a Gaussian blur directly in latent space. `Spatial Only` blurs each channel independently; `Spatial and Channel` performs a joint 3D blur across channels for stronger smoothing.
### Latent Frequency Split
Separates a latent into low-pass structure and high-frequency detail bands using a Gaussian crossover so you can process each side differently before recombining.
### Add Latent Noise (Seeded)
Adds seeded Gaussian noise scaled by the input latent's standard deviation. Useful whenever a latent needs a controlled bump in noise without touching the schedule.
@@ -50,6 +54,7 @@ Image exploration rarely means chasing a single "correct" answer. These nodes ar
- Follow the noise with `Conditioning (Gaussian Blur)` to soften abrupt emphasis changes or to merge multi-prompt blends into a single vibe. Blurring after noise often produces dreamlike, painterly shifts instead of chaotic drift.
- Use `Conditioning (Scale)` as a volume knob while iterating: dial the factor down to 0.3–0.5 when you want the image to respond mostly to the recovered latent, then crank it above 1.5 when the textual guidance should take the lead.
- Pair `Latent Gaussian Blur` with `Conditioning (Gaussian Blur)` for holistic smoothing—latent blur calms texture while conditioning blur calms prompt pacing. Reintroduce energy by sprinkling in `Add Latent Noise` or ramping the conditioning scale afterwards.
- Split a latent with `Latent Frequency Split`, sharpen or noise the high band while blurring the low band, then recombine via `Latent Mixer`/`Add` nodes to weave sharp detail onto soft composition.
- Swap seeds between the inverter, forward diffusion, and noise nodes as you iterate. Small tweaks here can shift the interplay between latent detail and prompt guidance, rewarding playful experimentation.
Treat each slider as a brushstroke: push a setting until it breaks, back off to the sweet spot, and capture the happy accidents along the way.
+69
View File
@@ -302,6 +302,73 @@ class LatentGaussianBlur:
out["samples"] = blurred_tensor.cpu()
return (out,)
class LatentFrequencySplit:
"""Splits a latent into low- and high-frequency bands via Gaussian smoothing."""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"latent": ("LATENT",),
"sigma": ("FLOAT", {
"default": 1.5,
"min": 0.0,
"max": 20.0,
"step": 0.1,
"tooltip": "Radius of the Gaussian used for the low-pass. Higher values move detail into the high band."
}),
}
}
RETURN_TYPES = ("LATENT", "LATENT")
RETURN_NAMES = ("low_pass", "high_pass")
FUNCTION = "split"
CATEGORY = "Latent/Filter"
def split(self, latent, sigma):
device = comfy.model_management.get_torch_device()
latent_tensor = latent["samples"].clone().to(device)
if sigma <= 0.0:
low_samples = latent_tensor
high_samples = torch.zeros_like(latent_tensor)
else:
low_samples = self._gaussian_blur(latent_tensor, sigma)
high_samples = latent_tensor - low_samples
low_latent = latent.copy()
low_latent["samples"] = low_samples.cpu()
high_latent = latent.copy()
high_latent["samples"] = high_samples.cpu()
return (low_latent, high_latent)
@staticmethod
def _gaussian_blur(latent_tensor, sigma):
tensor = latent_tensor
is_5d = tensor.dim() == 5
if is_5d:
b, c, t, h, w = tensor.shape
tensor_4d = tensor.permute(0, 2, 1, 3, 4).reshape(b * t, c, h, w)
else:
tensor_4d = tensor
kernel_size = int(sigma * 6) + 1
if kernel_size % 2 == 0:
kernel_size += 1
blurred_4d = TF.gaussian_blur(tensor_4d, kernel_size=kernel_size, sigma=sigma)
if is_5d:
blurred = blurred_4d.view(b, t, c, h, w).permute(0, 2, 1, 3, 4)
else:
blurred = blurred_4d
return blurred
class LatentAddNoise:
"""
Adds a configurable amount of seeded random noise to a latent tensor.
@@ -602,6 +669,7 @@ class ConditioningScale:
NODE_CLASS_MAPPINGS = {
"QwenRectifiedFlowInverter": QwenRectifiedFlowInverter,
"LatentGaussianBlur": LatentGaussianBlur,
"LatentFrequencySplit": LatentFrequencySplit,
"LatentAddNoise": LatentAddNoise,
"LatentForwardDiffusion": LatentForwardDiffusion,
"LatentHybridInverter": LatentHybridInverter,
@@ -613,6 +681,7 @@ NODE_CLASS_MAPPINGS = {
NODE_DISPLAY_NAME_MAPPINGS = {
"QwenRectifiedFlowInverter": "Qwen Rectified Flow Inverter",
"LatentGaussianBlur": "Latent Gaussian Blur",
"LatentFrequencySplit": "Latent Frequency Split",
"LatentAddNoise": "Add Latent Noise (Seeded)",
"LatentForwardDiffusion": "Forward Diffusion (Add Scheduled Noise)",
"LatentHybridInverter": "Latent Hybrid Inverter (Qwen)",