Nodes/ComfyUI CV/cv2.idft
ComfyUI Node

cv2.idft

The inverse FFT, and the DFT_SCALE tick everyone forgets

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
cv2.idft
  • src
  • nparray
◄flagsnone (0)►
◄nonzeroRows0►

Inverse Discrete Fourier Transform: coefficients in, image out. If you have ever wanted to remove a periodic pattern - a moiré grid from a screen capture, JPEG blocking, a watermark tiled across an entire frame, scanner interference - the technique is boring and effective: cv2.dft to the frequency domain, blank the offending spot in the spectrum, cv2.idft back. Almost all of that work happens in the spectrum, and this node is how you get out of it.

It is a plumbing node. It never does anything clever by itself, and you will only reach for it because cv2.dft put a complex array on a wire. But it is also where the most common FFT mistake in image code lives, so the flags dropdown is worth two minutes.

How it works

cv2.idft(src, flags, nonzeroRows). The input is a floating-point array, either two-channel (real and imaginary parts interleaved) or single-channel - which is convenient, since cv2.dft's complex output and cv2.mulSpectrums' results both land in the two-channel form and can be fed straight in without splitting them into separate re/im arrays.

flags is a dropdown of the DFT flag bits, and the pack renders flag groups as a pipe-joined string, so you will see values like none (0) and none (0) | DFT_SCALE. What each one does for the inverse:

  • DFT_SCALE - this is the important one. OpenCV's forward and inverse transforms are not normalised against each other, so a dft → idft round trip without DFT_SCALE returns your image multiplied by the pixel count. Tick it and the round trip is the identity.
  • DFT_REAL_OUTPUT - collapse the complex spectrum back to a single-channel real result. This is what you want when you are reconstructing a picture rather than doing complex arithmetic on the spectrum.
  • DFT_COMPLEX_OUTPUT / DFT_COMPLEX_INPUT - tell cv2 what shape to expect in and out; useful when your spectrum was built synthetically rather than by cv2.dft.
  • DFT_ROWS - treat each row as an independent 1-D transform.
  • DFT_INVERSE - already implied by calling idft; harmless if you tick it.

nonzeroRows optionally tells cv2 how many destination rows are actually nonzero (a convolution optimisation); 0 means all of them, which is the right answer unless you are doing overlap-add style work.

One more thing that matters for value ranges: the inverse transform of a spectrum you edited can produce small negative values and values above 255, because you changed the data. That is normal and it will look like noise until you scale properly.

Input and output

  • src - floating-point NPARRAY; a data-array socket, so it takes an NPARRAY link, not an IMAGE tensor.
  • flags - the dropdown described above.
  • nonzeroRows - advanced, 0 by default.
  • Output nparray - the reconstructed array.

To see it: Preview CV Array in normalize mode is the quickest honest look, cv2.convertScaleAbs turns it into a viewable 8-bit image, and CV Array → Image bridges it back to an IMAGE socket. In the other direction, Image → CV Array plus CV Cast Array gets you from a picture to float32 data, and CV Roll (FFT Shift) moves the DC term to the middle of the spectrum so "blank the bright spot" means what you think it means.

The companions, all in this pack: cv2.dft, cv2.dct / cv2.idct, cv2.mulSpectrums and cv2.divSpectrums for combining spectra (the frequency-domain multiply that is a convolution in space), cv2.magnitude / cv2.phase to inspect a spectrum, and cv2.normalize. There is also CV DFT Flags, a small node that authors a flag string as data - the escape hatch for feeding flags from a wire instead of a dropdown.

Because idft is in the pack's per-frame list, a batch of IMAGE-derived arrays is looped frame by frame and restacked, unlike several of the Hough wrappers which only ever look at frame 0.

Install

Manager → search comfyui_cv (bmad4ever), or:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"

Python ≥ 3.12 and a recent ComfyUI on the V3 node API; that pinned OpenCV wheel is the only runtime dependency and there is nothing to download.

When it goes wrong

  • The reconstructed image is uniformly black or white. Almost always the missing DFT_SCALE: you are looking at the image times N, clipped. Tick the flag before you go hunting for a bug in your masking.
  • Nothing at all looks changed. A very common outcome, and usually not a node problem: you masked the spectrum at too small a radius, or you masked the magnitude of a spectrum whose DC and low frequencies dominate. Work on the shifted spectrum with CV Roll (FFT Shift) so the pattern you are removing is where you expect it.
  • Ring/banding artifacts after masking. Editing a spectrum is convolution in image space: soft, bell-shaped masks behave, hard rectangular ones ring. Feather the mask (cv2.GaussianBlur works) rather than carving a rectangle.
  • An IMAGE link refuses to connect. Data-array socket by design. Convert first.
  • uint8 in, garbage out. Coefficients need float32; a uint8 round trip has already destroyed the negative half of the data.
Categoryimage/CV/low-level/cv2 I

Inputs (3)

NameTypeDefaultDescription
srcNPARRAYinput floating-point real or complex array. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
flagsoptSTRINGnone (0)operation flags (see dft and #DftFlags). cv2.idft flags: one of none (0) plus any of DFT_COMPLEX_OUTPUT, DFT_REAL_OUTPUT, DFT_SCALE, DFT_INVERSE, DFT_ROWS, DFT_COMPLEX_INPUT, pipe-joined (e.g. "none (0) | DFT_COMPLEX_OUTPUT"). In the UI this renders as a dropdown with one toggle per flag.
nonzeroRowsoptINT0-2147483648–2147483647number of dst rows to process; the rest of the rows have undefined content (see the convolution sample in dft description. Preset to the OpenCV default (0).

Outputs (1)

NameTypeDescription
nparrayNPARRAY—