cv2.isContourConvex
The one-bit answer that stops your geometry nodes from lying to you
- contour
- bool
A surprising amount of OpenCV's geometry refuses to behave on concave shapes. intersectConvexConvex gives undefined results on them. convexityDefects is meaningless. Quad warps assume four clean corners. So "is this contour convex?" is not a trivia question - it's the guard you run before those nodes, and it's a single boolean out of one node.
cv2.isContourConvex is a raw wrapper in bmad4ever/comfyui_cv, the pack that turns cv2 into ComfyUI nodes. Input: a contour. Output: bool.
Mechanism
OpenCV implements it as a turn test. Walking the vertices in the order you gave them, it computes the turn at each vertex (a cross product) and requires that every turn goes the same way - consistently clockwise or consistently counter-clockwise. That's the textbook convexity condition for a simple polygon, and it's a local check, which is why it's cheap and why it can occasionally be fooled: a traversal that turns consistently at every vertex while crossing itself somewhere else is the shape of thing local tests miss.
Which is the thing to internalise: the answer depends on the point order, because the turn at each vertex does. CV Contour To Points - the pack's contour-to-array bridge - is where your points come from, and if the ordering of that array isn't the contour's real traversal order, this node's answer is about your array, not about your shape.
Inputs and outputs
contour- an NPARRAY of(N,1,2)or(N,2)points. Typed NPARRAY-only on purpose: a point set isn't an image, so an IMAGE or MASK link is rejected rather than silently reinterpreted.CV Contour To Pointsis the node that gets you here from a mask.bool- the output. That's a real ComfyUI BOOLEAN on the wire, so it can drivecv2_isContourConvex→ a switch, a gate, aCV Reduce Values By Label-style branch, or aPrimitiveBooleanyou inspect.
What you actually do with it
Guard the geometry nodes. Wire it ahead of cv2.intersectConvexConvex, whose contract is convex input and whose failure mode is a plausible-looking wrong number rather than an error. If the flag is false, run cv2_convexHull first (with returnPoints on, so you get points rather than indices) and intersect the hulls instead.
Validate a quad before a quad warp. The quad-rectification nodes want four corners of a convex quadrilateral. A mask whose corners are detected slightly wrong can produce a bow-tie traversal, and this node catches it before the warp turns into confetti.
Filter a batch of regions. If you're processing many masks - segmentation output, connected components, blobs - and only some of them are the clean convex shapes your downstream maths assumes, this node is the branch point.
There's a second, older way to ask the same question: take the convex hull and compare it to the original, by area (cv2_contourArea) or by point count. If hull == contour, it was convex. It's more robust in the pathological cases and more work; the pack has all the pieces if you'd rather have the belt and the braces.
Installing the pack
Manager → search comfyui_cv, or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Python ≥ 3.12 and a ComfyUI recent enough for the V3 node API; the OpenCV behaviour is curated around 5.0.0.93. This is a core OpenCV function, so it's there whenever the pack loads. No models, no downloads.
Gotchas
Point dtype and layout. (N,1,2) or (N,2), integer or float. The pack's neighbouring tooltips ask for int32 in one place and float32 in another, so check what your source node emits and cast if you're chaining into a fussy consumer.
Very small contours. Two or three points don't have much turning to check. Don't read a true there as a meaningful statement about shape - a three-point contour is convex, and also nearly useless downstream.
A false doesn't tell you why. Self-intersection, a concave notch, a duplicated point, points out of order - all report the same bit. If you need to know, preview the contour (CV Points To Contour, drawing nodes) and look at it.
It's not a hole test. A contour can be convex and enclose a hole. Nothing here knows about topology.
Standing note for this pack: the README says it's a personal, heavily LLM-assisted project, that some behaviour may be overfitted to its own test cases, and that production use needs your own review. For a one-bit predicate like this, the cheap sanity check is to feed it a square (expect true) and a crescent (expect false) and confirm both.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| contour | NPARRAY | - - - A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| bool | BOOLEAN | — |