Nodes/comfyui_cv/CV Visual Odometry (Sequence)
ComfyUI Node

CV Visual Odometry (Sequence)

Monocular visual odometry over a whole frame BATCH: the camera's path through a static scene, dead-reckoned from the video alone. Per consecutive pair it runs the same three steps as 'CV Track Features (KLT)' -> 'OpenCV Recover Pose (Essential Matrix)' -> 'CV Compose Pose (Trajectory)' (it calls the very same code), carrying the surviving tracks into the next frame and re-detecting corners only when too few are left. Use the three single-step nodes to SEE the pipeline on a couple of frames; use this one to RUN it on a video, where a per-frame graph loop cannot collect the trajectory (a foreach fold keeps one accumulator, and the pose needs two). Monocular geometry fixes the translation DIRECTION only, never its length - supply the step length through 'scale_source' (a constant, wheel odometry, or a reference track). Failure-tolerant throughout: a pair with no recoverable motion (blank frame, no parallax, too few inliers) HOLDS the previous pose and marks that frame 0 in 'found_mask' rather than halting, so the trajectory always has exactly one row per input frame. Draw the result with 'CV Project To Plane' -> 'CV Fit Points To Box' -> 'CV Draw Path (ordered)', and score it against a reference track with 'CV Trajectory Error (ATE / RPE)'.

By bmad4ever·Created 3 months ago·Updated 2 days ago· 0
CV Visual Odometry (Sequence)
  • frames
  • camera_matrix
  • scale_reference
  • trajectory
  • rotations
  • found_mask
  • inlier_counts
  • track_counts
  • redetections
  • found
max_features2000
quality0.010
min_distance7.00
redetect_below1000
win_size21
max_level3
fb_threshold1.0
methodRANSAC
threshold1.0
confidence0.999
min_inliers15
scale_sourceconstant
scale1.00
motion_gatenone
min_step0.00
Categoryimage/CV/features

Inputs (18)

NameTypeDefaultDescription
framesNPARRAY,IMAGEThe video as an IMAGE batch, in order ('Load Video' -> 'Get Video Components'). Fewer than 2 frames is a valid input: the result is a single origin and found=false.
camera_matrixNPARRAY3x3 intrinsic matrix K of the camera that shot the sequence ('CV Camera Matrix' or 'Calibrate Camera'). An uncalibrated guess bends the whole path - the essential matrix cannot be recovered without it.
max_featuresINT20000–20000Maximum corners to detect when a re-detection happens (goodFeaturesToTrack); 0 = every corner found. Higher means a slower but steadier pose.
qualityFLOAT0.0100.0001–1Minimum corner quality relative to the strongest corner (qualityLevel); lower keeps weaker corners.
min_distanceFLOAT7.001–100Minimum spacing in pixels between detected corners.
redetect_belowINT10005–20000Re-run corner detection once the surviving tracks drop under this count. Tracks die as the camera advances, so this is what keeps the pose fed; too low and the pose degrades before the refill, too high and it re-detects every frame (slower, and it throws away long tracks).
win_sizeINT213–101Lucas-Kanade search window (forced odd); larger tolerates bigger motion but blurs fine detail.
max_levelINT30–8Pyramid levels (0 = no pyramid); more levels track larger displacements - a fast-moving camera needs them.
fb_thresholdFLOAT1.00–30Forward-backward consistency gate in pixels: a track is dropped if re-tracking it back misses its origin by more than this. 0 disables the check.
methodCOMBORANSACRobust estimator for the essential matrix. RANSAC is the standard choice for tracked corners.
thresholdFLOAT1.00.1–100Max distance in pixels from a point to its epipolar line to count as an inlier (RANSAC).
confidenceFLOAT0.9990.5–1Desired probability that the estimate is correct.
min_inliersINT155–10000Minimum cheirality-consistent inliers for a step to count. Below it the step is rejected and the pose held.
scale_sourceCOMBOconstantWhere each step's LENGTH comes from, since the video cannot supply it. 'constant': every step is 'scale' long - the path's shape is right, its size is arbitrary. 'per-step lengths (array)': one length per step in 'scale_reference'. 'reference trajectory (step lengths)': 'scale_reference' is an Nx3 track (GPS, wheel odometry, ground truth) and its consecutive distances are used - this is how a monocular result is made metric.
scaleFLOAT1.000–1000000Step length for scale_source = 'constant'.
scale_referenceoptNPARRAYThe step lengths, as either an (N-1,) / (N,) array of lengths or an Nx3 reference trajectory. Shorter than the batch: the last value repeats. Ignored when scale_source = 'constant'.
motion_gateoptCOMBOnoneOptional sanity check on each recovered direction. 'forward-dominant' rejects a step whose translation is mostly sideways or vertical rather than along the optical axis - the classic guard for a forward-facing vehicle camera, where such a step is nearly always a bad essential-matrix fit. Leave at 'none' for a camera that really can move sideways (a drone, a handheld orbit).
min_stepoptFLOAT0.000–1000000Reject steps shorter than this (same unit as 'scale'). At a standstill the translation direction is pure noise, so integrating it only adds drift; 0.1 m is the usual choice for a car at 10 fps. 0 accepts every step.

Outputs (7)

NameTypeDescription
trajectoryNPARRAYCamera centres, Nx3 float64 - one row per input frame, row 0 at the origin. Feed 'CV Project To Plane'.
rotationsNPARRAYRunning camera-to-world rotations, Nx3x3 float64 (rotations[0] is the identity).
found_maskNPARRAY(N,) uint8 - 1 where that frame's pose came from a real recovered step, 0 where it was HELD because the step failed. Index 0 is 1 (the origin is known by definition). Feed it to 'CV Draw Path (ordered)' as 'gap_mask' so the held stretches are visible.
inlier_countsNPARRAY(N,) int32 cheirality inliers per step (0 at index 0).
track_countsNPARRAY(N,) int32 tracks that survived into each frame - the health signal to watch; a collapse here precedes a collapse in the pose.
redetectionsINTHow many times corners had to be re-detected.
foundBOOLEANTrue if at least one step was recovered. Gate the downstream preview on it with 'if/else'.