Nodes/ComfyUI CV/cv2.goodFeaturesToTrack (1/2)
ComfyUI Node

cv2.goodFeaturesToTrack (1/2)

The corner detector behind every tracking pipeline

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
cv2.goodFeaturesToTrack (1/2)
  • image
  • mask
  • nparray
◄maxCorners0►
◄qualityLevel0.0000►
◄minDistance0.0000►
◄blockSize3►
◄useHarrisDetectorfalse►
◄k0.0400►

Also known as Shi-Tomasi, though nobody calls it that except the comment in the pack's own workflow. You point it at a grayscale image and it gives you back a list of "good features" - corners, in the loose sense of pixels whose local neighbourhood looks distinctive in two directions. This is the front half of optical flow: you can't track points you never picked, and picking them badly is the single most common reason a KLT tracker falls apart three frames later.

The output, and where it goes

One output, nparray: an N×1×2 array of float32 coordinates. Note what it is not - a list of keypoint objects, or a mask, or an annotated image. It's a bare point array, and that shape determines everything downstream:

  • cv2.cornerSubPix to refine each corner to sub-pixel accuracy - the pack's 34_corner_detection_playground workflow wires exactly this chain: detect at (100, 0.01, 10), then refine with a (5, 5) window and a 40-count/0.001-epsilon stopping criterion. Coarse detection, fine refinement is the standard two-step, and it's worth knowing that the refinement window is a separate node's input rather than a parameter here.
  • CV Draw Points when you want to see whether your thresholds are sane, which is most of the time you're tuning.
  • CV Track Features (KLT) and the video-lane nodes - this is the load-bearing use. Optical flow seeds from a corner set and re-detects when too few survive; the pack's spatial-tracking and visual-odometry examples all lean on that pattern, and CV Visual Odometry (Sequence) is the same chain folded over a batch with re-detection built in.

If you're heading for the descriptor/matching world instead - SIFT/ORB keypoints, ratio tests, homographies - use the curated CV Detect Corners instead. It wraps FAST/GFTT/Harris as keypoints, which is what the descriptor and matching lane wants. This node gives you numbers, which is what the tracking lane wants. Two different jobs that look like one.

The parameters that actually matter

The input image wants 8-bit or float32, single channel. Link a ComfyUI IMAGE and the pack grayscales it for you - that conversion is hardcoded for this function, since a 3-channel input is rejected by cv2 - and a MASK or raw NPARRAY passes through as you supply it. It takes frame 0 of a batch, not the whole batch: corners of a video are per-frame anyway.

maxCorners - how many to return. 100 is what the shipped examples use on ordinary frames, and 0 means "no limit", which is a trap rather than a convenience: the detector will hand you back every pixel that survives the quality test.

qualityLevel - the one people get wrong. It's relative: the threshold is this fraction multiplied by the best corner's quality measure. The pack's tooltip spells it out with the numbers worth remembering - if the strongest corner scores 1500 and qualityLevel is 0.01, everything under 15 is thrown away. That's why the same value works on wildly different images, and why 0 is meaningless: a zero threshold rejects nothing, so with maxCorners also at 0 you've asked for every pixel in the image. Both defaults are 0 here; set both.

minDistance - minimum Euclidean distance between returned corners, in pixels. Without it you get a pile of adjacent pixels on the same strong corner, which wastes your budget and makes tracking redundant. 10 is a sane starting point.

mask (optional) - a CV_8UC1 mask the same size as the image, restricting where corners may be found. This is how you corner only part of a frame: mask out the moving sky, or a lens vignette, and the tracker seeds where the geometry is stable. Genuinely useful, and the reason it's optional rather than absent.

blockSize (default 3), useHarrisDetector (default False) and k (default 0.04) - the pack presets these to OpenCV's documented defaults, unlike the three above. blockSize is the neighbourhood used to compute the derivative covariance. Flipping useHarrisDetector switches from the minimum-eigenvalue measure to Harris with k as its free parameter; for optical-flow seeding, leave it off.

There's also a sibling node - cv2.goodFeaturesToTrack (2/2) - the other cv2 overload, where mask and blockSize are required and an extra gradientSize appears. Same detector, different signature. Pick the one whose parameters you need.

Install

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

ComfyUI Manager → search ComfyUI CV, or:

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

then restart. Python ≥ 3.12 and a recent ComfyUI (V3 node API) are required; the pack is curated against OpenCV 5.0.0.93. No models to fetch.

Where people get burned

  • A number with no picture. The output is data, so nothing shows up on the node. Preview CV Array renders raw arrays, and Inspect CV Data gives you shape/dtype/stats - the fastest way to confirm you got 100 corners and not 40,000.
  • Missing nodes after an OpenCV upgrade. All four OpenCV PyPI distributions share one site-packages/cv2; install a non-contrib wheel over the contrib one and a slice of this pack's nodes quietly disappears from the menu. tools/repair_opencv_contrib.py --check then --apply.
  • Corner detection is cheap to verify. Draw the points, look, adjust, keep the exposure fixed while you do it - and remember the pack's own README says the raw wrappers are uncurated, so the tuning numbers are yours to find.
Categoryimage/CV/low-level/cv2 G

Inputs (8)

NameTypeDefaultDescription
imageNPARRAY,IMAGE,MASKInput 8-bit or floating-point 32-bit, single-channel image. 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.
maxCornersINT0-2147483648–2147483647Maximum number of corners to return. If there are more corners than are found, the strongest of them is returned. `maxCorners <= 0` implies that no limit on the maximum is set and all detected corners are returned.
qualityLevelFLOAT0.0000-1e+38–1e+38Parameter characterizing the minimal accepted quality of image corners. The parameter value is multiplied by the best corner quality measure, which is the minimal eigenvalue (see #cornerMinEigenVal ) or the Harris function response (see #cornerHarris ). The corners with the quality measure less than the product are rejected. For example, if the best corner has the quality measure = 1500, and the qualityLevel=0.01 , then all the corners with the quality measure less than 15 are rejected.
minDistanceFLOAT0.0000-1e+38–1e+38Minimum possible Euclidean distance between the returned corners.
maskoptNPARRAY,IMAGE,MASKOptional region of interest. If the image is not empty (it needs to have the type CV_8UC1 and the same size as image ), it specifies the region in which the corners are detected. 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.
blockSizeoptINT3-2147483648–2147483647Size of an average block for computing a derivative covariation matrix over each pixel neighborhood. See cornerEigenValsAndVecs . Preset to the OpenCV default (3).
useHarrisDetectoroptBOOLEANfalseParameter indicating whether to use a Harris detector (see #cornerHarris) or #cornerMinEigenVal. Preset to the OpenCV default (False).
koptFLOAT0.0400-1e+38–1e+38Free parameter of the Harris detector. Preset to the OpenCV default (0.04).

Outputs (1)

NameTypeDescription
nparrayNPARRAY—