Filter Contour
Rank Shapes With a One-Line Fitness Function
- contours
- image
- aux_contour
- CV_CONTOUR
- CV_CONTOURS
Filter Contour is the node that ranks a pile of detected contours and keeps the ones that fit. You give it a list of contours and a one-line "fitness" expression, and it either picks the single best, worst, or most common contour, or filters the whole list down to the ones that pass your test. It's the deepest node in bmad4ever's pack - and the one the author explicitly flags with ⚠️.
Why you'd reach for it
Contour detection spits out dozens of blobs and most of them are garbage - a stray highlight, a speck of noise, a shape that's the wrong aspect ratio. Filter Contour replaces "sort through all these by eye" with a scored query. Want the biggest blob? cv.contourArea(c). The roundest? equi_diameter(c) compared across candidates. The blob that best matches a reference shape? That's the pack's headline example: cv.matchShapes(c,a,1,0.0), which scores how closely contour c resembles your auxiliary contour a.
It's aimed at the manual CV end of the workflow: locating a subject in a frame, finding the most rectangle-ish region for a crop, isolating the dominant object before a mask step. If you're doing collage or preprocessing, this is the node that makes "keep the interesting blob" programmable.
How it works
You write an expression in the fitness box. The available variables: c (the contour being evaluated), i (the optional input image), a (the optional auxiliary contour). Function namespaces: m = math, cv = OpenCV, np = numpy. Plus a set of un-prefixed helpers that the pack caches so repeated calls don't cost you: aspect_ratio, extent, solidity, equi_diameter, center, contour_mask, mean_color, mean_intensity, extreme_points, intercepts_mask, and cached boundingRect, contourArea, arcLength, minEnclosingRect/minEnclosingCircle, fitEllipse, convexHull.
The select dropdown decides what the expression is for:
- MAX / MIN - expression must return a number; you get the single best/worst contour.
- FILTER - expression must return a boolean; you get all contours that pass.
- MODE - returns the contour whose score is the median of all scores (the "typical" shape).
The expression must be a single line - no multi-statement logic. If that feels limiting, it's intentional: the node evaluates this code at runtime.
The ⚠️ and why it's there
This node evaluates your text as code, which is why the README paints it as potentially dangerous. The author shipped a mitigation (simpleeval sandbox + a 120s timeout, added in response to a GitHub security issue) so it's not raw eval(), and the risk is mostly "your own expression hangs." Still: don't run filter expressions pasted from strangers without reading them, and keep expressions simple.
Install
It's OpenCV + simpleeval heavy, so install the pack with requirements:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_bmad_nodes
pip install -r requirements.txt
then restart ComfyUI. Manager users search "comfyui_bmad_nodes". Missing OpenCV → CV nodes won't load.
Common issues
- Empty contour list. It prints "Contour list is empty" and returns empties - check your contour source, not this node.
- Expression errors. Single line only, correct variable names, functions exist. The error message points at the failing expression.
- Hung execution. A pathological expression (huge loop, heavy per-contour work) can run up to the timeout. Downscale your image or simplify the fitness.
- MAX vs FILTER confusion. MAX gives one contour; FILTER gives a list. Check which output socket you're reading - the node has both a single
CV_CONTOURand a listCV_CONTOURSoutput.
It's a fiddly node with a learning curve, but it's the difference between "there are 40 blobs, I want the one that looks like the reference" being a manual task and being a node.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| contours | CV_CONTOURS | — | |
| fitness | STRING | # Contour Fitness Function | — |
| select | COMBO | MAX | 4 options: MAX, MIN, MODE, FILTER |
| imageopt | IMAGE | — | |
| aux_contouropt | CV_CONTOUR | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| CV_CONTOUR | CV_CONTOUR | — |
| CV_CONTOURS | CV_CONTOURS | — |