cv2.getOptimalDFTSize
Pad before you FFT, or pay for it
- int
One integer in, one integer out: give it a size, get back the smallest size that OpenCV's FFT implementation actually likes. It exists because the Cooley–Tukey algorithm underneath cv2.dft is fast when your dimensions factor into small primes and slow when they don't - a prime width like 1009 isn't just slower, it can be an order of magnitude slower. This is the node that stops you from finding that out at runtime.
How it works
vecsize is an INT - the dimension you were about to transform, usually an image width or height. The output int is the recommended padded size: the nearest value at-or-above your input whose factors are 2, 3 and 5 only. That's why the answers cluster around 512, 600, 640, 720, 768, 1024, 1080 and their neighbours rather than tracking whatever you typed.
There's nothing magic in the pack here; it's a direct wrapper of cv2.getOptimalDFTSize, generated at import time from the pack's registry of cv2 functions like all ~470 others. It has no image input and no batch behaviour - it's arithmetic on one number, and it costs nothing to call.
The recipe it exists for
You call it twice - once per axis - then pad the image to that size with copyMakeBorder before the transform. Both of those padded dimensions are integers, and in this pack two int outputs compose into one size value through CV Tuple, whose component sockets accept INT links: two calls, one (w, h) composite, straight into copyMakeBorder's dsize-style size input. Then cv2.dft, do whatever frequency-domain work you came for, and crop back with CV Slice Array once you're done.
Two things this saves you from. First, the performance cliff: cv2.dft will happily pad internally, but if you're the one doing the padding you can pick the size deliberately and keep the whole chain predictable. Second, the correctness trap that follows a manual pad - a (w, h) computed as a literal integer pair is easy to get wrong by one pixel once you start cropping back, and the whole working pipeline is measurably cleaner when the numbers came from the function that knows the answer.
Where this matters in practice: anything that moves a frame into the frequency domain. Phase correlation for sub-pixel registration is the classic one, and this pack has wrappers for it; periodicity-based denoising, sharpening in frequency space, and the CV Roll (FFT Shift) helper node all live in the same neighbourhood.
One thing to watch
vecsize defaults to 0, and unlike some parameters in this pack the wrapper has no curated OpenCV default to fall back on for it - so a 0 here isn't "let OpenCV decide", it's just a nonsense input. Give it the real dimension. Same for the pairing with dft: the size only helps if the array you actually pass to the transform is the padded one.
Install
The dependency is the contrib OpenCV wheel, which the pack declares as headless because nothing in it touches OpenCV's GUI functions:
pip install "opencv-contrib-python-headless~=5.0.0.93"
ComfyUI Manager → search ComfyUI CV, or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
then restart. Needs Python ≥ 3.12 and a recent ComfyUI on the V3 node API; the pack's own behaviour is curated against OpenCV 5.0.0.93.
Friction worth knowing about
The pack's low-level lane is auto-generated and explicitly uncurated - the README says so outright, along with a note that the whole codebase was written with heavy LLM involvement. Practically, that means these nodes do one cv2 call and hand you the raw result: no clamping, no dtype fixing, no "did you mean BGR". Inspect CV Data (wire its summary into core Preview as Text) is the fastest way to confirm that the number you got back is the number you think you asked for.
And one wheel gotcha that applies to every node in this pack: opencv-python, opencv-python-headless, opencv-contrib-python and opencv-contrib-python-headless all write into the same site-packages/cv2. Installing a non-contrib variant over a contrib one strips the contrib submodules, and a slice of this pack's nodes simply stops appearing in the menu. tools/repair_opencv_contrib.py --check will tell you whether that has happened to you.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| vecsize | INT | 0-2147483648–2147483647 | vector size. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| int | INT | — |