CV Compute Descriptors
FAST corners described by SIFT, because OpenCV splits the two
- image
- keypoints
- keypoints
- descriptors
- count
What this is for
Feature detection and feature description are two different jobs in OpenCV, and the reason to care is that pairing them separately is how you get the good combinations: FAST corners (fast, cheap, descriptorless) described with SIFT (slow, robust), or blobs described with ORB if you want something that matches at speed. CV Detect Features does detect-then-describe with one algorithm chosen up front; this node is for the other half of that split.
It's also a neat illustration of the pack's boundary. cv2.Feature2D is a class - you call create() on it, then detect(), then compute() - and the auto-generated wrappers only reach top-level functions. So the compute()-only half is something a curated node has to bridge, exactly like cv2.aruco.CharucoDetector and the create* factories.
How it works
Feed it keypoints from any descriptor-free detector - CV Detect Corners, CV Detect Blobs, whatever, or points you placed by hand - plus the image those keypoints were found in, and it runs compute() with the descriptor you picked. The image is converted to grayscale internally, so matching the detector's preprocessing is one less thing to worry about.
Three descriptors are on the menu, and the choice determines the matcher setting downstream:
ORB (binary, fast)- binary descriptors, match with Hamming. The default, and a reasonable one.SIFT (float, robust)- 128-D float descriptors, match with L2. Better under scale and rotation changes; slower.BRISK (binary, scale-aware)- binary, with its own scale handling.
There's one sharp-edged detail, and the tooltip says it plainly: the descriptor drops keypoints too close to the border (the patch it would sample doesn't exist). So the keypoints output here is not the list you fed in - it's the subset that could actually be described, row-aligned with the descriptors. If you match using the original keypoint list, indices no longer line up and you'll get nonsense correspondences that look almost plausible. Use this node's output.
When nothing survives, you still get an empty descriptor matrix with the right dtype rather than None, so count and downstream matching can proceed without a special case.
Inputs and outputs
Required: image, keypoints (a CV_KEYPOINTS socket), descriptor (the combo above). Three outputs: keypoints (the describable subset - the one to wire onward), descriptors (N×D, uint8 for ORB/BRISK, float32 for SIFT) and count.
Wire keypoints + descriptors into CV Match Features exactly as you would from CV Detect Features. The matcher needs the norm that goes with the descriptor - Hamming for the binary ones, L2 for SIFT - and that's a widget on the matcher, not on this node, so it's on you to keep the pair consistent.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
# restart ComfyUI
Manager users: ComfyUI CV (bmad4ever). Needs Python ≥ 3.12, a recent V3-node-API ComfyUI, and opencv-contrib-python-headless~=5.0.0.93. SIFT and friends live in contrib, so this is another node that depends on the contrib wheel winning - see below. No model or download.
Common issues
- "No keypoints" / count 0. The detector returned nothing, or every keypoint was within the border margin the descriptor refuses. The second case is the sneaky one: a detector run on a small image can put all its points near the edges, and
countat the detector looks fine. - Matching produces garbage. Two candidates, in order: you fed the matcher the pre-description keypoint list, or the matcher's norm doesn't match the descriptor (Hamming versus L2). Both give you plausible-looking wrong matches rather than an error.
CV Detect Corners/ SIFT nodes missing from the pack. Contrib submodules were emptied, usually by another pack installing a non-contribopencv-pythonover the sharedsite-packages/cv2.python tools/repair_opencv_contrib.py --check, then--apply.- Slow on big images. SIFT will do that. ORB is the default for a reason; use SIFT when matching actually fails, not by reflex.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| image | NPARRAY,IMAGE | The image the keypoints were detected in (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. | |
| keypoints | CV_KEYPOINTS | Keypoints to describe, from any detector node. | |
| descriptor | COMBO | ORB (binary, fast) | ORB/BRISK give binary descriptors (match with Hamming), SIFT gives 128-D float descriptors (match with L2). The matcher node must use the norm that goes with the descriptor. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| keypoints | CV_KEYPOINTS | The keypoints that COULD be described (border keypoints are dropped) - row-aligned with the descriptors. |
| descriptors | NPARRAY | NxD descriptor matrix; uint8 for ORB/BRISK, float32 for SIFT. Empty with the right dtype when nothing survives. |
| count | INT | How many keypoints kept a descriptor. |