Nodes/ComfyUI CV/cv2.minEnclosingTriangle
ComfyUI Node

cv2.minEnclosingTriangle

Three corners that contain everything, plus the area it cost

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.minEnclosingTriangle
  • points
  • float
  • nparray

The smallest triangle that contains your point set. Out comes the area the triangle needed and its three vertices - and unlike cv2.minAreaRect, there's no angle convention to fight, because a triangle is just three points.

Where's it useful? Three-point fits, mostly. A rough region for a soft mask, a "spread" measure for a point cloud (the triangle's area grows with how dispersed the points are, and unlike a variance it's indifferent to direction), a bounded region for a light or gradient pass. It's also the natural shape for anything genuinely tripod-ish: three contact points, three fingertips, three markers. And it's a nice sanity overlay when you're building contour-based logic - dropping the triangle on top of the mask tells you immediately whether your points are where you think they are.

It's the specialised cousin of cv2.minEnclosingConvexPolygon (which fits any k) and of the circle/rect fits. In OpenCV 3 and 4 it was the only "fit exactly this shape" option, which is part of why it exists at all.

The sockets

points - NPARRAY only, a data array rather than a picture. Same route as the rest of this family: CV Find Contours → select/filter → CV Contour To Points. If what you have is a mask, cv2.findNonZero converts set pixels to a point list and skips the contour step entirely.

Two outputs. The FLOAT is the area of the fitted triangle - OpenCV documents that return honestly, and it's genuinely handy as a dispersion score. The NPARRAY is the triangle's three vertices as (3,2) points.

To see it, draw it rather than stare at the array: cv2.fillConvexPoly takes a points array and paints the convex polygon in one call, which is exactly the shape you have. Three cv2.line calls with the vertices split out works too, and CV Annotate Points will drop visible markers on the vertex coordinates if you want to check the corner positions individually.

Installing the pack

ComfyUI CV (bmad4ever/comfyui_cv) - ComfyUI 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"

Restart ComfyUI. Python ≥ 3.12, V3-API ComfyUI build, that one pinned contrib OpenCV wheel, no downloads. Core OpenCV, cheap, runs in microseconds.

Where people get burned

An IMAGE in the points socket. It's an array-only socket by design. Convert first.

One outlier point at the extreme of your mask. The triangle is pinned by its farthest points, so a single speck at the edge of a mask inflates it dramatically. Median-blur the mask or filter contours before fitting - the same discipline as the circle node, for the same reason.

Fewer than three points. Degenerate, obviously, but it arrives as a weird value rather than an explicit error if the shapes happen to work out. Guard it if you're iterating over many contours.

Reading the area as a bounding measure. A triangle's area is not a bounding box; two quite different point clouds can give the same area from different orientations. For a proper "how big is this" use contourArea or the minimum-area rect's dimensions.

Contrib nodes missing from the menu. The pack-wide one, worth knowing because it never announces itself: all four opencv-* wheels share one site-packages/cv2, so a non-contrib opencv-python installed over the contrib wheel empties the contrib submodules and the contrib-backed nodes simply stop registering. python tools/repair_opencv_contrib.py --check diagnoses; --apply repairs. And keep in mind the author's own note that this pack was written with heavy LLM assistance and isn't recommended for production without reviewing the source - a triangle fit is low stakes, but the advice is the author's, not mine.

Categoryimage/CV/low-level/cv2 M

Inputs (1)

NameTypeDefaultDescription
pointsNPARRAY - - - A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.

Outputs (2)

NameTypeDescription
floatFLOAT—
nparrayNPARRAY—