CV Term Criteria
The Magic Number 3 Doesn't Have to Be Your Problem
- criteria
Half of OpenCV's interesting algorithms are iterative: corner refinement, k-means, optical flow, ECC registration, mean shift, PnP refinement. They don't run to completion, they run until enough - and "enough" arrives as a tuple of (type, max_count, epsilon), where type is a bit field whose most common value happens to be the integer 3.
This node builds that tuple for you, as a name-able thing you can wire anywhere. Stop counting in your head.
How it works
stop_on is the real decision, and there are only three sensible answers:
- max count or epsilon (whichever first) - the default, and what most OpenCV examples use. It stops after
max_countiterations or as soon as the change drops belowepsilon. - max count only - a fixed budget, run to the end. Use it when you want determinism more than speed.
- epsilon only - iterate until convergence, whatever it costs. Fine on a small image; a good way to hang a workflow on a bad one.
max_count (default 30) and epsilon (default 0.001) are the accompanying numbers. Which one is ignored depends on stop_on, and if you pick "max count only" and then agonise over epsilon you're tuning a parameter that isn't being read.
The output is a single criteria STRING - the literal (type, max_count, epsilon), resolved by the pack's node machinery when the downstream node runs. It's the same pattern the pack uses for other composite literals it can't express as a socket type.
Wiring it up
The consumers are the low-level wrappers: cv2_cornerSubPix, cv2_kmeans, cv2_calcOpticalFlowPyrLK, cv2_findTransformECC, cv2_meanShift, cv2_solvePnPRefineLM and friends. Their criteria widget has to be converted to an input first (right-click → Convert widget to input), then wired from this node's criteria output.
Convert once and reuse: one CV Term Criteria feeding a corner-refinement call, an ECC registration and a k-means step keeps all three converging under the same rule. That's the whole point - consistency you can see on the canvas instead of three numbers you half-remember.
One caveat that isn't the node's fault: epsilon means different things in different algorithms. For cornerSubPix it's sub-pixel accuracy in pixels; for ECC it's a correlation increase; for k-means it's movement of cluster centres. Same widget, different units. Don't copy a value across without thinking about it.
For higher-level nodes in the pack - the curated ones with a criteria input - you may find the tuple is built internally, which is usually the right call. This node is for the raw wrappers and for the cases where you actually want to tune the budget.
Install
ComfyUI Manager → search ComfyUI CV (publisher bmad4ever), or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Restart after. Python ≥ 3.12 and a recent ComfyUI on the V3 node API. Keep the contrib wheel - a plain opencv-python installed over it shares site-packages/cv2 and silently empties the contrib submodules, breaking siblings that need ximgproc. tools/repair_opencv_contrib.py --check / --apply is the fix.
The playground workflows that actually exercise these parameters - 34_corner_detection_playground.json, 39_optical_flow_playground.json, 24_kmeans_clusters.json - need the sample inputs from 01_install_example_inputs.json (run it, then reload the page).
Where it bites
The failure mode is a string that doesn't parse, which surfaces as an error on the downstream node rather than on this one - mildly annoying to trace, and the reason the pack resolves the flags and literals loudly rather than guessing.
The other bite is silence, not error: a too-generous max_count on a complicated image turns a two-second node into a two-minute one, and nothing in the UI tells you the difference. If a workflow suddenly feels slow and there's a corner-refinement step in it, check here before you blame the sampler.
Standing caveat from the pack README, worth knowing once: personal project, heavy LLM assistance, curated against one OpenCV build, no support planned. This node is a three-field builder and does exactly one thing, which makes it about as low-risk as the pack gets.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| stop_on | COMBO | max count or epsilon (whichever first) | When to stop iterating: after max_count iterations, when the change drops below epsilon, or whichever comes first. |
| max_count | INT | 301–100000 | Maximum iterations (ignored when 'epsilon only'). |
| epsilon | FLOAT | 0.00100–1000000 | Target accuracy / smallest change worth continuing for (ignored when 'max count only'). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| criteria | STRING | '(type, max_count, epsilon)' literal - feed it into a cv2 node's criteria input (convert that widget to an input). |