Nodes/ComfyUI CV/CV Term Criteria
ComfyUI Node

CV Term Criteria

The Magic Number 3 Doesn't Have to Be Your Problem

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
CV Term Criteria
    • criteria
    ◄stop_onmax count or epsilon (whichever first)►
    ◄max_count30►
    ◄epsilon0.0010►

    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_count iterations or as soon as the change drops below epsilon.
    • 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.

    Categoryimage/CV/low-level

    Inputs (3)

    NameTypeDefaultDescription
    stop_onCOMBOmax count or epsilon (whichever first)When to stop iterating: after max_count iterations, when the change drops below epsilon, or whichever comes first.
    max_countINT301–100000Maximum iterations (ignored when 'epsilon only').
    epsilonFLOAT0.00100–1000000Target accuracy / smallest change worth continuing for (ignored when 'max count only').

    Outputs (1)

    NameTypeDescription
    criteriaSTRING'(type, max_count, epsilon)' literal - feed it into a cv2 node's criteria input (convert that widget to an input).