Nodes/ComfyUI CV/CV Detect Corners
ComfyUI Node

CV Detect Corners

Picking corner detectors that hand you keypoints, not bare points

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
CV Detect Corners
  • image
  • keypoints
  • points
  • sizes
  • responses
  • count
◄detectorGFTT (Shi-Tomasi)►
◄threshold10►
◄non_max_suppressiontrue►
◄max_features500►
◄quality_level0.010►
◄min_distance10►
◄fast_type9/16 (default)►
◄block_size3►
◄harris_k0.04►

CV Detect Corners is the descriptor-free corner detector: FAST, or GFTT scored with Shi-Tomasi or Harris. It finds interesting pixels and gives you cv2.KeyPoints - no descriptors, no matching, just locations and strengths.

The distinction that makes this node exist: the pack also ships a raw cv2_goodFeaturesToTrack wrapper, and that returns bare point coordinates. This node returns proper keypoints with a response value, so they chain into CV Draw Keypoints, CV Compute Descriptors and the matching nodes. And FAST has no function form in OpenCV at all - it's a class - so for "give me corners as fast as possible" this is the only door.

When to reach for each: FAST when you need thousands of corners per millisecond and don't care how many - tracking, optical-flow seeding, a SLAM-style front end. GFTT when you want a bounded, evenly-spread set, which is the classic Kanade-Lucas-Tomasi seed and what you want before CV Track Features (KLT).

How it works

FAST tests a ring of 16 pixels around each candidate; if enough of them are consistently brighter or darker than the centre by threshold, it's a corner. fast_type picks how many of the 16 must agree - 9/16 is the standard, and shorter arcs fire more often (and on noise). With non_max_suppression on, you keep only the locally strongest corner instead of every pixel that passed, which is the difference between a usable set and a wall of dots.

GFTT computes a second-moment matrix in a block_size window and scores it: Shi-Tomasi takes the smaller eigenvalue, Harris takes det(M) - k*trace(M)^2 with harris_k as the free parameter. Then it keeps at most max_features of the strongest, subject to quality_level (a fraction of the best corner's score) and min_distance - that last one being what spreads them out instead of clustering them all on one high-contrast edge.

Inputs and outputs

Required: image (grayscale internally), detector (FAST / GFTT Shi-Tomasi / GFTT Harris), then the knobs for whichever you chose - threshold and non_max_suppression for FAST; max_features (default 500), quality_level (0.01) and min_distance (10) for GFTT. The fields belonging to the other detector are simply ignored, so don't panic when changing harris_k does nothing on FAST.

Optional: fast_type (9/16 by default), block_size (3, forced odd) and harris_k (0.04) for the GFTT side.

Outputs are the standard four plus a count: keypoints, points (Nx2 centres for the point-set nodes - k-means, polar conversion, CV Delaunay / Voronoi), sizes, responses, and count. Zero corners is a valid result.

Install

From comfyui_cv (bmad4ever/comfyui_cv). ComfyUI Manager → search "ComfyUI CV", or:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"

Restart ComfyUI. Python ≥ 3.12 and a V3-API ComfyUI. The contrib requirement is about the pack as a whole rather than this node, but it's not optional: all four OpenCV distributions share one site-packages/cv2, so a plain opencv-python installed by some other pack silently removes the contrib nodes. tools/repair_opencv_contrib.py --check detects that, --apply repairs it.

Common issues

  • FAST returns tens of thousands of points. That's FAST working as designed. Raise threshold (from 10 upward) and keep non_max_suppression on. Left at defaults on a detailed image it will absolutely fill the frame.
  • GFTT gives you all 500 corners on one object. min_distance too small and quality_level too low. Raise quality_level to ~0.05 and min_distance until the corners spread out - that's literally the point of the node.
  • Corners land a pixel or two off. FAST is a discrete test, and GFTT's Shi-Tomasi peak is not sub-pixel. cv2_cornerSubPix exists in the low-level wrappers if you need to refine, and the feature detectors (CV Detect Features) refine for you.
  • You wanted descriptions, not just locations. Corners alone can't be matched. Send keypoints through CV Compute Descriptors, or use CV Detect Features, which detects and describes in one step.

A last note: adding CLAHE-style contrast equalisation upstream (CV Contrast (CLAHE/Equalize)) will change your corner count substantially on badly-lit images. Worth doing once, deliberately, rather than wondering why the same photo gives you 400 corners on one node run and 40 on another.

Categoryimage/CV/features

Inputs (10)

NameTypeDefaultDescription
imageNPARRAY,IMAGEImage to search (converted to grayscale 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.
detectorCOMBOGFTT (Shi-Tomasi)FAST: very fast, unbounded count, driven by 'threshold'. GFTT Shi-Tomasi: bounded, evenly spread, driven by max_features/quality_level/min_distance. GFTT Harris: same but scored with the Harris measure (harris_k), which prefers sharper corners.
thresholdINT101–255FAST only: how much brighter/darker the arc of pixels around a candidate must be. Lower = many more corners.
non_max_suppressionBOOLEANtrueFAST only: keep only the locally strongest corner instead of every pixel that passes the test.
max_featuresINT5001–100000GFTT only: keep at most this many of the strongest corners.
quality_levelFLOAT0.0100.0001–1GFTT only: minimum corner score as a FRACTION of the best corner's score. 0.01 keeps everything within 1% of the best; raise it to keep only strong corners.
min_distanceFLOAT100–1000GFTT only: minimum spacing in pixels between kept corners - this is what spreads them over the image.
fast_typeoptCOMBO9/16 (default)FAST only: how many of the 16 ring pixels must agree. 9/16 is the standard; shorter arcs fire more often.
block_sizeoptINT31–31GFTT only: neighbourhood size used to compute the corner score (forced odd).
harris_koptFLOAT0.040.001–0.5GFTT Harris only: the free parameter k of the Harris response det(M) - k*trace(M)^2.

Outputs (5)

NameTypeDescription
keypointsCV_KEYPOINTScv2.KeyPoint list - draw with 'CV Draw Keypoints', or give them descriptors with 'CV Compute Descriptors' to feed 'CV Match Features'.
pointsNPARRAYNx2 float32 (x, y) centres - the point-set form for 'OpenCV Draw Points', k-means, polar conversion, ...
sizesNPARRAY(N,) float32 keypoint diameter in pixels.
responsesNPARRAY(N,) float32 detector strength per keypoint - threshold it to keep only the strong ones.
countINTHow many were found; 0 is a valid result, not an error.