cv2.idct
Turning DCT coefficients back into an image
- src
- nparray
The inverse discrete cosine transform. If cv2.dct took your image into frequency space - the JPEG trick, energy packed into the top-left corner of the coefficient block - cv2.idct brings it back. On its own it is not a filter and not an effect; it is the return leg of a round trip, and it exists in this pack because the forward transform is here too and a one-way transform would be useless.
Where it earns its place: any processing you do on coefficients. Zero out high-frequency terms and you have a low-pass. Quantise coefficients and you have an approximation experiment. In a ComfyUI graph the honest version of that story is: someone else's node produced coefficients (or you built them from cv2.dct), and you need pixels again.
For the photograph-level jobs people actually want - blur, denoise, sharpen - the pack has direct nodes (cv2.GaussianBlur, cv2.bilateralFilter, the curated CV Contrast). Reaching for a transform round trip to smooth an image is a detour (post-processing.md covers the filter layer that would actually do it).
How it works
cv2.idct(src, flags). The input must be a floating-point array - the tooltip says single channel, single precision - because the coefficients are signed and fractional, and a uint8 array would destroy them. The output has the same size and type as the input, so this is a pure transform: no rescaling inside.
flags is a dropdown in this pack because the pack exposes flag groups as pipe-joined strings. You get none (0) as the base plus the bits that apply to the cosine transform: DCT_INVERSE and DCT_ROWS. Two notes on those:
DCT_INVERSEis already implied by callingidctat all - it is the inverse transform - so ticking it is harmless rather than wrong.DCT_ROWSis the one that changes behaviour: it treats every row as an independent 1-D transform. That is what you want if you took your coefficients row-wise (per-row spectral analysis) rather than as a 2-D block.
One scaling caveat that shows up in practice: OpenCV's transform functions are not normalised for you. A dct → idct round trip with matching flags reconstructs the data up to a constant factor, so if your "reconstructed" image looks uniformly too bright or too dark, that is the convention, not your arithmetic. This is exactly the same trap the DFT has, where the missing DFT_SCALE on the inverse costs you a factor of the pixel count.
Input and output
src- floating-point NPARRAY, single channel. The socket is marked as a data array, not an image: this node will not accept an IMAGE tensor link, only an NPARRAY. If you are starting from a picture, convert withImage → CV Array(or* → CV Array) and cast withCV Cast Arrayso you arrive as float32 rather than uint8.- Output
nparray- float32 pixels back.
Getting that result on screen: it is a raw float array, so send it to Preview CV Array (normalize mode, for a value-stretched look) or to CV Array → Image to get an actual IMAGE socket back, clipping out the negatives and over-255 values on the way. If you are reconstructing a picture you intend to compare against the original, cv2.convertScaleAbs is the usual bridge from signed float data to a viewable 8-bit image.
Because idct is in the pack's per-frame list, a batch of IMAGE-derived arrays is processed frame by frame and restacked - unlike the Hough and corner wrappers, which quietly only look at frame 0.
Related nodes in the same territory: cv2.dct (forward), cv2.dft / cv2.idft (the complex counterpart), cv2.mulSpectrums and cv2.divSpectrums for working in the frequency domain, cv2.magnitude / cv2.phase for interpreting complex results, and CV Roll (FFT Shift) for moving the DC term to the centre of a spectrum before you look at it.
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. One pinned dependency, no models, no downloads.
When it goes wrong
- An IMAGE link will not connect. The input is a data array, deliberately: an IMAGE tensor is not what cv2 wants here. Run it through
Image → CV Arrayfirst. - Everything comes back black or saturated. You are looking at signed float data as if it were 8-bit, or you skipped the scaling factor. Normalize for preview (
Preview CV Arrayin normalize mode) and only convert to real pixels via a scale-and-abs step. - uint8 input. Coefficients stored as 0–255 have already lost their negative values; the transform cannot recover them. Cast to float32 before
cv2.dct, not after. - The result is wrong for row-wise coefficients. Tick
DCT_ROWS- 2-D versus per-row is the difference between "bleeding between rows" and "each row independent". - Treating this as a compression pipeline. It is a transform, not a codec. Real JPEG-style compression adds quantisation and entropy coding, which is out of scope for this node and for the pack.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| src | NPARRAY | input floating-point single-channel array. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. | |
| flagsopt | STRING | none (0) | operation flags. cv2.idct flags: one of none (0) plus any of DCT_INVERSE, DCT_ROWS, pipe-joined (e.g. "none (0) | DCT_INVERSE"). In the UI this renders as a dropdown with one toggle per flag. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | — |