cv2.phaseCorrelateIterative
OpenCV 5's beefed-up version, with no confidence score
- src1
- src2
- shift
A cv2 5.0 addition, and one of the newer entries in this pack - the author groups it with the other "functions cv2 5.0 added" in their parameter documentation. It does the same job as phaseCorrelate (sub-pixel translation between two frames, measured in the frequency domain) but refines the estimate iteratively, over a correlation neighbourhood you size with L2size, for up to maxIters rounds.
Same four inputs as its older sibling plus two optional integers:
src1,src2- the pair. Both documented as "Source floating point array (CV_32FC1 or CV_64FC1)". Single channel, float. The pack's own parameter note is blunt: "Single-channel FLOAT array (CV_32F or CV_64F) - not an 8-bit image. Window both inputs (cv2.createHanningWindow) to suppress the edge response."L2size- optional, preset to 7: "The size of the correlation neighbourhood the sub-pixel refinement fits over."maxIters- optional, preset to 10: the iteration cap.- Output:
shift, aCV_TUPLEcarrying(x, y)as one composite value. Wire it into any point input, or split it with CV Split Tuple / CV Split Point.
What's missing relative to phaseCorrelate
No response. The non-iterative version hands you signal power at the peak so you can tell a real lock from a hallucinated one; this one gives you a shift and nothing else. There's no found flag either, so there's no built-in way to branch on "did this work".
That's the thing to understand before you build on it. With phaseCorrelate you write if response > 0.3, and the pack's curated CV Phase Correlate (Translation) node makes that a found output you route with a switch. Here you have to sanity-check the number yourself: split the tuple, look at the magnitude of the shift, and reject anything that's bigger than plausible motion for your footage. A silent garbage answer is the failure mode this node's interface invites.
The second thing: no window input, same as its sibling
Neither the generated wrapper for phaseCorrelate nor this one exposes the optional window parameter, even though the pack's parameter documentation has text for it. In the non-iterative curve that's a real defect, because image borders are a giant artificial edge that can own the correlation peak. The pack's own improvement here is honest about it: its parameter note tells you to window both inputs. Since cv2.createHanningWindow isn't in the registry (it's a create* factory, and the pack's generator only wraps top-level functions), "window it yourself" means building that array some other way and multiplying it in with a low-level cv2.multiply. Doable, annoying, and the single biggest reason to prefer the curated non-iterative node for ordinary stabilisation work.
Where the iterative version actually helps
The refinement loop exists for the cases where the plain estimate is coarse: displacements that aren't a clean integer-ish shift, aliased or noisy frames, small images where the peak is broad. If you're seeing unstable sub-pixel estimates frame to frame from phaseCorrelate, raising L2size (bigger neighbourhood, smoother fit, less local jitter) or letting the iteration run is the natural next move - that's what the parameters are for.
Practically, though: this is a brand-new function with essentially no field testing. This pack is a one-person 2026 fork with no community threads I could find, so there's no accumulated wisdom about good L2size/maxIters values, no comparisons against the non-iterative path, no reports. Anyone telling you what numbers to use here is guessing, including me. What I'd do: run both nodes on the same pair and look at how far apart the answers are. If they agree, use the one that gives you a response value. If they disagree, find out which one is tracking your actual motion before you trust either.
And the base requirement hasn't changed: same-size single-channel float inputs. A ComfyUI IMAGE resolves to 8-bit BGR in this pack, so both sides need Image → CV Array → cv2.cvtColor → CV Cast Array before they get here. There's no batch handling - an IMAGE batch gives you frame 0 - so pair frames explicitly with CV Index Batch if you're walking a clip.
Installing
ComfyUI Manager → search ComfyUI CV → Install → restart, 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 - the pack is built on the V3 node API. And this one genuinely needs OpenCV 5: the pack wraps whatever functions your installed cv2 exposes, so on an older OpenCV this node isn't broken, it simply isn't generated and won't appear in the menu at all. The pack is curated against opencv-contrib-python-headless~=5.0.0.93, so pin that and stop wondering. No models, no extra downloads.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| src1 | NPARRAY,IMAGE,MASK | Source floating point array (CV_32FC1 or CV_64FC1) Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size. | |
| src2 | NPARRAY,IMAGE,MASK | Source floating point array (CV_32FC1 or CV_64FC1) Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size. | |
| L2sizeopt | INT | 7-2147483648–2147483647 | The size of the correlation neighborhood used by the iterative shift refinement algorithm. Preset to the OpenCV default (7). |
| maxItersopt | INT | 10-2147483648–2147483647 | The maximum number of iterations the iterative refinement algorithm will run. s detected sub-pixel shift between the two arrays. Preset to the OpenCV default (10). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| shift | CV_TUPLE | - - - Subpixel coordinates (x, y) as ONE composite value - wire it straight into any cv2 point input, or into 'CV Split Tuple' for the separate numbers. |