Spectral Magnitude Blend
Borrow a natural photo's texture without borrowing its content
- image_a
- image_b
- image
Here's a fact that underpins half of this pack: in an image's Fourier representation, the magnitude encodes what kind of texture is present, and the phase encodes where things are. So it's possible to take the content and layout of one image, swap in the spectral character of another, and get something that keeps image A's subject while feeling like image B. SpectralMagnitudeBlend is that trick, packaged as a node.
The typical use case the README pitches is a good one: feed a known-clean natural photograph as image_b and your AI-generated image as image_a. At blend 0.3–0.5 you get A's content with B's spectral texture - an AI image that suddenly feels more natural to the VAE encoder, because its high-frequency character now matches the kind of image the encoder was trained on. If you've been fighting "my Flux img2img keeps adding grain/sparkle," this is a gentler, more targeted alternative to the whole suppression chain: rather than removing artifacts, you're donating a natural spectrum.
How it works
Both images get an FFT per channel. The output always keeps image_a's phase (spatial structure), and takes a linear blend of the two magnitudes: new_mag = (1-blend) * mag_a + blend * mag_b. The frequency_band control restricts which radial band gets blended - outside the band, A's magnitude is kept untouched - with the band boundaries being all (0–1), low (0–0.15), mid (0.15–0.5), and high (0.5–1.0) in normalized radius.
That band control is what makes it flexible: high adopts only B's high-frequency texture, which is where most "AI-ness" lives, while leaving A's large-scale structure alone. If B is a natural photo, blending just the highs is often enough to calm the synthetic character without changing the image's composition at all.
The inputs that matter
image_a- primary image; phase always comes from here.image_b- spectral donor; magnitude is blended from here.blend(default 0.3) - 0 = keep A's magnitude entirely, 1 = B's entirely. The README's sweet spot is 0.3–0.5.frequency_band(defaultall) - restrict the blend toall,low,mid, orhigh. Start withhighif you just want the texture character.
One image output. (It also resizes B to match A if the dimensions differ - a small but real convenience.)
Installing it
Part of ComfyUI-Spectral-Preprocessing-Nodes - one install, all sixteen nodes under Spectral Preprocessing. ComfyUI Manager (search "ComfyUI-Spectral-Preprocessing-Nodes"), or:
cd ComfyUI/custom_nodes
git clone https://github.com/EdoardoGuerriero/ComfyUI-Spectral-Preprocessing-Nodes
Restart. Only numpy and scipy (bundled); nothing to download.
Where people get burned
The classic miss is expecting a mix of the two images. It isn't - the output is entirely A's content; B only donates texture character, and only if the phase from A is still coherent. If B is very different in brightness or the blend is pushed toward 1, you can get odd high-frequency residue because you're combining A's phase with B's magnitude and the two don't perfectly correspond. Keep blend moderate (0.3–0.5) and, if things look weird, back it off or restrict to high band. Also note this is a blend node, not a suppressor - it needs a good reference image, whereas the Spike Suppressor needs nothing but its own parameters. Have a clean natural photo handy and this is one of the friendliest nodes in the pack.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image_a | IMAGE | Primary image — phase is always taken from here. | |
| image_b | IMAGE | Spectral donor — magnitude is blended from here. | |
| blend | FLOAT | 0.300–1 | 0 = keep A's magnitude entirely, 1 = use B's magnitude entirely. |
| frequency_band | COMBO | all | Restrict blending to a radial frequency band. 'all' blends the full spectrum. 'high' only adopts B's high-frequency texture. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |