OpenCV cornerSubPix_0
CornerSubPix_0 — make your corners sub-pixel precise (yes, really)
- image
- corners
- nparray
cornerSubPix_0 is cv2.cornerSubPix, and it does a genuinely neat thing: takes corner locations that are only accurate to the nearest pixel and refines them to sub-pixel precision - fractions of a pixel. That sounds like overkill until you need it. Camera calibration, stereo matching, and precision registration all fail quietly on whole-pixel corner locations; the calibration error budget is often measured in hundredths of a pixel. If your workflow involves any geometry that gets turned into numbers (not pictures), this is the node that takes your corners from "good enough for the eye" to "good enough for the math."
Where does it fit in a diffusion pipeline? Honestly, rarely - same story as the other corner nodes. But it sits right after the other corner nodes in a graph: detect corners (say with cornerHarris_0, or the pack's goodFeaturesToTrack), then feed the detected points here to polish them, then use the refined points for alignment or calibration. It's the finishing step of a feature-detection stage.
How it works
You hand it an image and a starting set of corner points. Around each point it iteratively fits the local image gradient structure - the same structure tensor family - and nudges the location toward where the gradients actually intersect, using a window you specify. The iteration stops when the movement per step drops below a threshold or hits a max iteration count. Result: the same points, moved by sub-pixel amounts, returned as an nparray you can feed straight into geometry code.
The inputs that matter - and the string trap
This is where the pack's quirks bite. Composite OpenCV types can't be widgets, so the generator turned them into STRING inputs parsed with ast.literal_eval. You type Python literals:
image- grayscale nparray (it must be the same image the corners came from).corners- your detected corner points as an N×2 (or N×1×2)float32nparray.winSize- string, e.g."(5, 5)"- the search window.zeroZone- string, e.g."(-1, -1)"- a dead zone in the middle (use-1for "none").criteria- string, a TermCriteria tuple(type, maxIter, epsilon), e.g."(3, 40, 0.001)"- type 3 meansEPS + MAX_ITER. This is the "stop when movement < 0.001 px" control.
The classic failure: you type (5, 5) and it works, then you type [5, 5] and get invalid syntax (<unknown>, line 0) - that's the literal_eval choke. The README's troubleshooting section calls this exact error out. Tuples parse fine; malformed literals don't.
Install
Ships with opencv-comfyui. ComfyUI Manager → search opencv-comfyui → install, or:
cd ComfyUI/custom_nodes
git clone https://github.com/geroldmeisinger/opencv-comfyui
Restart. Needs opencv-contrib-python (+ numpy, torch). No model files.
Common issues
invalid syntax (<unknown>, line 0)→ one of the STRING inputs isn't a valid Python literal. Check your tuple syntax.- Wrong point type →
cornersmust befloat32. IfgoodFeaturesToTrackgave you ints, cast before wiring. - Output looks like the input → that's correct behavior. Sub-pixel shifts are invisible at a glance; that's the point. Compare coordinates numerically, not visually.
_0vs_1→ identical overloads; either works.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| image | NPARRAY | — | |
| corners | NPARRAY | — | |
| winSize | STRING | — | |
| zeroZone | STRING | — | |
| criteria | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | — |