Nodes/ComfyUI CV/cv2.calcOpticalFlowPyrLK
ComfyUI Node

cv2.calcOpticalFlowPyrLK

Track points between two frames, and know which ones you lost

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.calcOpticalFlowPyrLK
  • prevImg
  • nextImg
  • prevPts
  • nextPts
  • winSize
  • nextPts
  • status
  • err
◄maxLevel3►
◄criteria_typemax count or epsilon (whichever first)►
◄criteria_max_count30►
◄criteria_epsilon0.00►
◄flagsnone (0)►
◄minEigThreshold0.0001►

This is Lucas-Kanade with a pyramid, known everywhere as KLT: hand it a handful of interesting points in frame A, and it finds where each of them went in frame B. It's sparse rather than dense - you get N tracked points, not a vector per pixel - and unlike Farneback's dense flow it tells you, per point, whether the match succeeded. That status output is the reason it's still the workhorse behind stabilisation, tracking, and visual odometry in 2026.

A raw wrapper from comfyui_cv, the pack of ~470 cv2.* nodes. The author has effectively no community footprint to argue about - the pack name returns nothing in the Reddit corpus, and his earlier ComfyUI pack (a cartesian-product list node) is from 2024 - so if you're using this, the OpenCV docs and the source are your references, not a tutorial thread.

The inputs that matter

  • prevImg, nextImg (required) - the two frames, 8-bit. IMAGE, MASK or NPARRAY all land here, but remember an IMAGE link converts to uint8 BGR and only frame 0 of a batch is used.
  • prevPts (required, NPARRAY) - the points to track: an N×1×2 float32 array. Sources: cv2.goodFeaturesToTrack, the pack's feature detectors, or CV Grid Points if you want a regular lattice rather than detected corners.
  • nextPts (required, NPARRAY) - the second point array, and this one is the confusing part. In OpenCV it's the output, and when OPTFLOW_USE_INITIAL_FLOW is set it's also the initial guess you feed in. The pack declares it required, so you must supply an array: the easy move is to hand it the same points you gave prevPts, which is what OpenCV assumes when the flag is off anyway.
  • winSize (optional, default (0,0)) - the search window per pyramid level. Set it; (21,21) is the OpenCV default and a sane starting point. Bigger window tracks larger motion and smears more.
  • maxLevel (default 3) - pyramid depth, already preset to OpenCV's default. 0 means no pyramid, i.e. small motion only.
  • criteria_type, criteria_max_count (30), criteria_epsilon (0.001) - the iteration stop rule, split into three widgets rather than a criteria string. "Whichever first" is the normal choice.
  • flags (default none (0)) - a real dropdown with toggles for OPTFLOW_USE_INITIAL_FLOW and OPTFLOW_LK_GET_MIN_EIGENVALS.
  • minEigThreshold (0.0001) - the quality gate. Points whose neighbourhood is too flat to solve get filtered out entirely, which is both faster and more honest.

Outputs

Three NPARRAY sockets: nextPts (where the points moved to), status (one flag per point - tracked or lost), and err (the per-point error, L1 patch distance by default, or the minimum eigenvalue if you set OPTFLOW_LK_GET_MIN_EIGENVALS).

None of the three is an image, and status in particular is not a mask you can wire into a mask input - it's a column of flags the length of your point list. Use it to filter: keep the points whose status is 1 before you draw them or average them. Losing 30% of your points between two frames is information, not a failure.

Where it fits

The classic chain is goodFeaturesToTrack → KLT → new points → repeat, and the pack has curated help for every stage: CV Track Features (KLT) is described as "pyramidal Lucas-Kanade tracking with status filtering" - the plumbing done - and CV Visual Odometry (Sequence) folds the whole KLT → recoverPose → compose chain over an IMAGE batch, carrying tracks between frames and re-detecting when too few survive. That last one exists for a reason worth quoting: a graph loop cannot collect a trajectory, because a foreach fold keeps one accumulator and a pose needs two.

So: use the raw node when you want the three outputs as data (your own filtering, your own geometry, feeding points into something else entirely). Use the curated nodes when you want tracking or odometry.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv

Restart, or ComfyUI Manager → search "comfyui_cv". Python ≥ 3.12, recent ComfyUI on the V3 node API, plus:

pip install "opencv-contrib-python-headless~=5.0.0.93"

Common issues

Points aren't float32. OpenCV requires single-precision coordinates, and an array that came through an integer path will either be rejected or silently track badly.

winSize left at (0,0). A zero window finds nothing useful; set a real size.

Everything is lost between frames. Either the motion exceeds what a 3-level pyramid with a 21px window can follow, or the frames differ too much for the brightness-constancy assumption KLT is built on - a cut, a flash, or a big exposure change. More pyramid levels and a bigger window buy you some slack; nothing buys you a scene change.

Categoryimage/CV/low-level/cv2 C

Inputs (11)

NameTypeDefaultDescription
prevImgNPARRAY,IMAGE,MASKfirst 8-bit input image or pyramid constructed by buildOpticalFlowPyramid. 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.
nextImgNPARRAY,IMAGE,MASKsecond input image or pyramid of the same size and the same type as prevImg. 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.
prevPtsNPARRAYvector of 2D points for which the flow needs to be found; point coordinates must be single-precision floating-point numbers. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
nextPtsNPARRAYoutput vector of 2D points (with single-precision floating-point coordinates) containing the calculated new positions of input features in the second image; when OPTFLOW_USE_INITIAL_FLOW flag is passed, the vector must have the same size as in the input. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
winSizeoptCV_TUPLE0,0size of the search window at each pyramid level. One value with 2 components (w, h) - it travels as a whole, so it cannot arrive half-connected. Wire it from 'CV Tuple' or type the components in place.
maxLeveloptINT3-2147483648–21474836470-based maximal pyramid level number; if set to 0, pyramids are not used (single level), if set to 1, two levels are used, and so on; if pyramids are passed to input then algorithm will use as many levels as pyramids have but no more than maxLevel. Preset to the OpenCV default (3).
criteria_typeoptCOMBOmax count or epsilon (whichever first)When to stop iterating: after max_count iterations, when the change drops below epsilon, or whichever comes first.
criteria_max_countoptINT301–2147483647Maximum iterations (ignored when 'epsilon only').
criteria_epsilonoptFLOAT0.000–1e+38Target accuracy / smallest change worth continuing for (ignored when 'max count only').
flagsoptSTRINGnone (0)operation flags: - **OPTFLOW_USE_INITIAL_FLOW** uses initial estimations, stored in nextPts; if the flag is not set, then prevPts is copied to nextPts and is considered the initial estimate. - **OPTFLOW_LK_GET_MIN_EIGENVALS** use minimum eigen values as an error measure (see minEigThreshold description); if the flag is not set, then L1 distance between patches around the original and a moved point, divided by number of pixels in a window, is used as a error measure. cv2.calcOpticalFlowPyrLK flags: one of none (0) plus any of OPTFLOW_USE_INITIAL_FLOW, OPTFLOW_LK_GET_MIN_EIGENVALS, pipe-joined (e.g. "none (0) | OPTFLOW_USE_INITIAL_FLOW"). In the UI this renders as a dropdown with one toggle per flag.
minEigThresholdoptFLOAT0.0001-1e+38–1e+38the algorithm calculates the minimum eigen value of a 2x2 normal matrix of optical flow equations (this matrix is called a spatial gradient matrix in ), divided by number of pixels in a window; if this value is less than minEigThreshold, then a corresponding feature is filtered out and its flow is not processed, so it allows to remove bad points and get a performance boost. The function implements a sparse iterative version of the Lucas-Kanade optical flow in pyramids. See Preset to the OpenCV default (0.0001).

Outputs (3)

NameTypeDescription
nextPtsNPARRAY—
statusNPARRAY—
errNPARRAY—