CV Filter Contours
Keep the round ones, throw away the squiggles
- contours
- contours
- count
- values
CV Find Contours gives you every blob in the frame, sorted by area. This node is how you tell it which ones you meant: measure a property on each contour, keep the ones inside a numeric range. Chain two or three of them and you've built a shape classifier out of arithmetic.
What you can filter on
The property combo is the interesting part, because it isn't just size:
area (px^2)andperimeter (px)- absolute pixel measurements. Useful, but they change when you change resolution, so they're the wrong first choice for anything you'll reuse.circularity (4*pi*A/P^2, 1 = perfect circle)- scale-free. A perfect circle scores 1; a wobbly blob scores lower. This is the "find the round things" knob.aspect ratio (bbox width / height)- the "find the wide things" knob. A line at 6:1, a square at 1:1.extent (area / bbox area)- how much of its own bounding box the shape fills. A plus sign has low extent; a filled square has 1.solidity (area / convex hull area)- solid blobs versus squiggly ones. A star or an irregular splat has low solidity because its convex hull is much bigger than the shape.
Those last three are ratios in 0–1, so they survive a resolution change and are the ones worth building on.
How to use it
min_value and max_value are inclusive bounds, and both accept anything from -1e9 to 1e9 with a step of 0.05. There is no magic and no preset - you tune it by inspection, and the node hands you the tool:
the values output is a float32 array holding the measured property of each kept contour, aligned with the contours output. So the workflow is to widen the range until everything passes, read the values with Inspect CV Data, and then set the bounds where the histogram actually separates. That's a much better loop than guessing 0.8 and re-running.
Outputs are contours (the kept ones, in the incoming order - the node doesn't re-sort), count, and values. Zero matches is a valid result with count = 0, not an error.
Stacking filters
The node description recommends chaining several to combine criteria, and that's the intended idiom: a first pass on circularity above 0.85, a second on area above a minimum in pixels, and you've got "coins, not specks" without any machine learning. Each node is one measurement, which keeps the graph honest - you can see what rule is rejecting your object instead of staring at a single node with six linked sliders.
Two practical warnings. First, area is meaningless for an open contour. A broken outline that traces out and back has near-zero area even though it looks big - so if you're filtering a shape whose edge broke into arcs, measure by perimeter instead. Second, aspect ratio is computed from the axis-aligned bounding box, so it changes with rotation: a diagonal line has an aspect ratio near 1. If you need rotation-invariant shape matching, that's a different node (CV Filter Contours By Shape, which uses Hu moments).
Install
# ComfyUI Manager → search "ComfyUI CV" → install → restart
# or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
cd comfyui_cv && pip install -r requirements.txt
Python ≥ 3.12 and a recent ComfyUI (V3 node API - on an older build the pack's nodes don't register at all). The only dependency is opencv-contrib-python-headless~=5.0.0.93; this node is a plain cv2 call, so it works even if the contrib submodules of your cv2 install have been clobbered by a stray opencv-python wheel. If contrib nodes do vanish from your menu, that's the cause, and tools/repair_opencv_contrib.py --check then --apply is the pack's own fix.
Where it sits
Typical graph: edges or a threshold → CV Find Contours → CV Filter Contours (maybe twice) → CV Enclosing Circle, CV Shape Moments, CV Draw Contours, or a contour-to-points bridge if you want the geometry as data. It's the middle of the pipeline, and it's the part that decides whether your pipeline is a measurement tool or a demo.
The pack is bmad4ever's, a fork of geroldmeisinger's opencv-comfyui rewritten on the V3 API, and the author says plainly that it was written with heavy LLM assistance and isn't production-grade. On a node whose whole job is a comparison between two numbers, that risk is small - but the tooltip-level details above are worth reading anyway, because the traps here are conceptual, not code.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| contours | CV_CONTOURS | From 'CV Find Contours'. | |
| property | COMBO | area (px^2) | What to measure on each contour. Circularity, extent and solidity are scale-free ratios in 0-1; area/perimeter are in pixels. |
| min_value | FLOAT | 0.00-1000000000–1000000000 | Smallest accepted property value (inclusive). |
| max_value | FLOAT | 1000000000.00-1000000000–1000000000 | Largest accepted property value (inclusive). |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| contours | CV_CONTOURS | The kept contours, in the incoming order. |
| count | INT | — |
| values | NPARRAY | float32 property value per kept contour (aligned with the contour output). |