Nodes/comfyui_cv/CV Quasi-Dense Stereo
ComfyUI Node

CV Quasi-Dense Stereo

Stereo matching by SEED-AND-GROW (cv2.stereo.QuasiDenseStereo), the third answer next to 'Stereo Disparity (SGBM)' and '(BM)'. Those two search a disparity RANGE at every pixel independently; this one tracks a few hundred good-features-to-track seeds with Lucas-Kanade and then GROWS each match into its neighbourhood as long as the correlation and the local disparity gradient hold up. Consequences worth knowing: there is no num_disparities to get wrong (a seed can sit anywhere, so a wide baseline costs nothing), it answers only where the image has texture to propagate through - the output is quasi-dense, not dense - and it needs no rectification to run, though the disparity output only means anything on a RECTIFIED pair. The class is not reachable from the raw wrappers. Failure-tolerant: a pair with no trackable features (a blank frame) returns found=false and empty arrays instead of the OpenCV assertion the class raises.

By bmad4ever·Created 3 months ago·Updated 2 days ago· 0
CV Quasi-Dense Stereo
  • left
  • right
  • disparity
  • valid
  • displacement
  • points_left
  • points_right
  • seeds_left
  • seeds_right
  • dense_count
  • seed_count
  • found
max_seeds500
seed_quality0.010
seed_min_distance10
correlation_window5
correlation_threshold0.50
texture_threshold200
disparity_gradient1
neighborhood_size5
border15
Categoryimage/CV/features

Inputs (11)

NameTypeDefaultDescription
leftNPARRAY,IMAGELeft frame (grayscaled internally). 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.
rightNPARRAY,IMAGERight frame; resized to left if the sizes differ - the class asserts on mismatched frames. 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.
max_seedsINT50010–5000How many goodFeaturesToTrack seeds to start from (gftMaxNumFeatures). More seeds reach more regions - propagation cannot cross a texture-less gap, so an unseeded area stays empty however good the matching is.
seed_qualityFLOAT0.0100.0001–1Corner quality of a seed relative to the strongest corner (gftQualityThres). Lower accepts weaker corners, i.e. more seeds in flat regions.
seed_min_distanceINT101–200Minimum pixel distance between seeds (gftMinSeperationDist) - spreads them over the frame instead of clustering on one strong texture.
correlation_windowINT53–31Half-window of the correlation test used when growing a match (corrWinSizeX/Y). Larger is more reliable and blurs across depth discontinuities.
correlation_thresholdFLOAT0.500–1Minimum normalized correlation for a grown match to be kept. Raise it to trade coverage for correctness.
texture_thresholdFLOAT2000–10000Minimum local texture (sum of squared gradients) a pixel must have before propagation continues into it. This is what stops the growth from flooding a blank wall or the sky with an invented disparity.
disparity_gradientINT10–10How much the disparity may change between neighbouring pixels. 1 keeps surfaces smooth; larger follows steep slopes and lets the growth leak across object edges.
neighborhood_sizeoptINT53–21Size of the neighbourhood a confirmed match propagates into.
borderoptINT150–100Image margin (borderX/borderY) excluded from matching, so a correlation window never runs off the frame.

Outputs (10)

NameTypeDescription
disparityNPARRAYHxW float32 SIGNED horizontal disparity in pixels (x_left - x_right), the same convention as 'Stereo Disparity (SGBM)' / '(BM)' - so it feeds 'CV Disparity Interpolate', cv2.reprojectImageTo3D and the WLS filter directly. Built from the match set, NOT from cv2's own getDisparity(), which returns the UNSIGNED euclidean displacement (see 'displacement'). 0 where unmatched - read 'valid', not zero.
validNPARRAYuint8 0/255 mask of pixels that actually got a match (the quasi-dense support).
displacementNPARRAYHxW float32 of cv2's own getDisparity(): the EUCLIDEAN length of each match's displacement, sqrt(dx^2 + dy^2), unsigned and including vertical motion. On a rectified pair it is |disparity|; on an unrectified one the two differ by tens of pixels, which is why the disparity output above is not this. NaN (cv2's 'no match') is written as 0.
points_leftNPARRAYNx1x2 float32 left-image coordinates of every DENSE match - wire straight into 'Triangulate Points', 'Find Homography (RANSAC)' or 'Draw Points'.
points_rightNPARRAYNx1x2 float32 right-image coordinates, row-aligned with points_left.
seeds_leftNPARRAYNx1x2 float32 left-image coordinates of the SPARSE seed matches the propagation started from - a few hundred against the dense set's tens of thousands.
seeds_rightNPARRAYNx1x2 float32 right-image coordinates of the seeds.
dense_countINTNumber of quasi-dense matches.
seed_countINTNumber of seed matches.
foundBOOLEANFalse when the pair produced no dense match at all (blank or uncorrelated frames); the arrays are then empty and the disparity is all zero.