QFT Spectral Residual Saliency
Find the interesting part of an image, with zero model downloads
- image
- saliency_map
This pack is a single node and a single idea: QFTSpectralResidualSaliency looks at any color image and tells you where a human eye would land. It outputs a saliency map - a white-on-black intensity image where bright means "salient," i.e. visually interesting. No model download, no prompt, no GPU requirement. It's classical signal processing, done with the numpy that already ships with ComfyUI.
That last part is the real hook. ComfyUI is drowning in nodes that each drag in a multi-gigabyte model and a requirements.txt that quietly breaks something else (the ecosystem essay calls this dependency hell, accurately). This one is a 9 KB Python file and a README that actually explains the math. It computes on CPU in well under a second for a 512×512 image. That is refreshing.
How it works (the math is the mechanism)
The trick is in the name. Most simple saliency detectors crunch each color channel separately and lose the information in how channels correlate. This one packs RGB into a single pure quaternion q = R·i + G·j + B·k, then runs a Quaternion Fourier Transform on it. Thanks to a symplectic decomposition trick, that's just two ordinary 2D FFTs under the hood - so it's fast and needs no special library.
From there it's the classic Spectral Residual pipeline: take the log of the frequency magnitude, smooth it with an averaging filter to get the "boring average spectrum," and treat the difference as the interesting part. Salient regions deviate from the repetitive structure of the scene, so they pop out as large residuals. Weight the original transform by exp(-prior), inverse-FFT, square the magnitude, Gaussian-blur, normalize to [0, 1]. Done.
The inputs that matter
Only three knobs, and you'll mostly touch two:
image(required) - any IMAGE, batches supported, any resolution. A single-channel input degrades gracefully to luminance.smooth_kernel(1–128, default 8) - the averaging-filter size on the log spectrum. Bigger = higher contrast between subject and background, but values past ~32 start swallowing fine details. The 4–16 range the README recommends is genuinely good advice.gaussian_sigma(0–100, default 8) - blur on the final map. Scale it with resolution: 8–16 at 512×512, higher if you're upscaling.output_mode-grayscale(default) orheatmap. Heatmap is just a built-in jet colormap for eyeballing; grayscale is what you feed downstream.
Output: one saliency_map IMAGE, float in [0, 1], same spatial size as the input.
Where it fits in a workflow
The obvious use is automatic region detection: saliency map → threshold → mask → inpaint or composite. That's the case mask-based inpainting still uniquely owns - bit-identical unmasked pixels, only the interesting region regenerated - and this node hands you the "interesting region" for free, with no segmentation model to source. It's also handy for auto-cropping a subject out of a busy scene, or weighting where to spend detail in a two-pass upscale.
Installing it
ComfyUI Manager: search ComfyUI_QFT_SRSM and install. Or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/bemoregt/ComfyUI_QFT_SRSM
Then restart ComfyUI. It appears under image/analysis as "QFT Spectral Residual Saliency". The only dependency beyond ComfyUI's bundled numpy/torch is scipy, and even that is optional - if it's missing, the node silently falls back to pure-NumPy filters. pip install scipy if you want the faster path, but you'll find the node works fine without it.
Gotchas worth knowing
The saliency map comes out as a 3-channel IMAGE (the grayscale duplicated), not a MASK. If you're feeding it into an inpaint or compositing node that wants a MASK, run it through an image-to-mask converter first. Also note normalization is per-image: each frame in a batch is min-max normalized independently, so a batch of very different images won't share comparable brightness levels. And smooth_kernel gets bumped to the next odd number internally - you won't notice, but the node is doing it. It's a niche tool, but for "tell me where the subject is without downloading anything," it's the lightest, least dramatic answer on the shelf.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| smooth_kernelopt | INT | 81–128 | — |
| gaussian_sigmaopt | FLOAT | 8.00–100 | — |
| output_modeopt | COMBO | grayscale | 2 options: grayscale, heatmap |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| saliency_map | IMAGE | — |