FindFFTSpot
FindFFTSpot finds the grid for you
- ff
- image
The annoying part of removing a grid pattern from a scanned photo isn't the math - it's finding where the grid actually lives in the frequency domain. Bright dots and crosses on an FFT display are small, faint, and easy to miss. FindFFTSpot, from the fssorc/ComfyUI_FFT pack, is the helper node that tries to hunt them down for you, so you can build the removal mask without hunting by eye.
It's not the pack's headline act (that's InvertFFTWithMask), and it won't clean your image by itself. Think of it as a spotter: it takes the same FFTData from FFTNode and outputs a map of where the periodic high-frequency energy - i.e. your grid - is sitting.
How it works
The approach is a bit roundabout but sensible. FindFFTSpot starts from the frequency spectrum, discards the big low-frequency blob in the center (that's all the actual photo content), and runs the inverse FFT on what's left. What survives in the spatial domain is exactly the periodic high-frequency stuff: the grid. It then zeroes out the dead center and the central cross - which usually contain the strongest artifacts you don't care about - normalizes, and (with threshold above zero) binarizes the result to pure white-on-black. The output is a map of the grid's location in frequency space, which is what you use to build your removal mask.
One honest caveat: it only inspects the first (red) channel of the FFT data, not all three. For a typical grayish scan moiré that's usually fine, since the pattern is roughly the same across channels, but it's not a full per-channel analysis.
The inputs that matter
Four integers, all with sensible defaults:
hiPassFactor(10) - how much of the low-frequency center to throw away before looking for spots. Crank it up if you're catching photo detail instead of grid.centerRange(30) - radius of the central blob you always zero out.crossWidth(30) - how thick the central cross you erase is. Set 0 to leave the cross alone.threshold(100) - binarize everything above it to white, below to black. Set 0 to keep the map as grayscale instead of binary.
You'll tune all of these per image; grid patterns vary wildly between scans, and the defaults are a starting point, not a finish line.
What to do with the output
The image output is white where the spots are. Remember that InvertFFTWithMask keeps white frequency content and removes black, so the spot map as-is would nuke everything except the grid. Feed it through a mask conversion and an invert (e.g. ImageToMask → InvertMask) so the spots go black, then wire that into InvertFFTWithMask alongside the original FFTData. Or skip the auto-mask entirely and just use the map as a reference for painting your own.
Install
From ComfyUI Manager, search for "ComfyUI_FFT" and install, or clone manually:
cd ComfyUI/custom_nodes
git clone https://github.com/fssorc/ComfyUI_FFT
Then restart ComfyUI. There's no requirements.txt and no models to fetch - the pack only needs numpy, scipy, and OpenCV, all of which a normal ComfyUI install already has. It's a small, unmaintained-since-2024 single-author pack, so don't expect updates, but the code is plain enough that what you see is what runs.
FindFFTSpot is fiddly, and for clean scans you can often just paint the mask by hand. But when the grid is subtle enough that you can't tell where it ends, having a machine point at it is a real time-saver.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| ff | FFTData | — | |
| hiPassFactor | INT | 101–1024 | — |
| centerRange | INT | 301–1024 | — |
| crossWidth | INT | 300–100 | — |
| threshold | INT | 1000–254 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |