Nodes/ComfyUI CV/cv2.approxPolyN
ComfyUI Node

cv2.approxPolyN

\"give me a hexagon\", not \"give me fewer points\"

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
cv2.approxPolyN
  • curve
  • nparray
◄nsides0►
◄epsilon_percentage-1.0000►
◄ensure_convextrue►

approxPolyDP answers "how few points can describe this shape". approxPolyN answers a different question: "fit me an N-gon to it". Set nsides = 6 and you get six vertices, whatever the tolerance would have produced.

That's the node to reach for when you already know the shape family - a sticker is a rounded pentagon, a tag is a quad, a board is a rectangle - and you want the canonical polygon, not the one the point count happens to allow.

How it works

OpenCV fits the best N-sided polygon to the input curve by minimising the area difference, so the result is a genuine fit rather than a decimation. Two optional knobs shape that search:

  • epsilon_percentage is a budget, expressed as a fraction of the contour's area. When adding another vertex would grow the approximation's area by more than that percentage of the contour area, the algorithm stops and returns what it had - which means it can return fewer than nsides vertices. The default is -1, meaning "don't use this at all".
  • ensure_convex defaults to True, which takes the convex hull of your input before fitting. That's a safety net, because OpenCV's implementation assumes a convex input: with it off and a concave shape, you get a fit to something that isn't your shape.

The output is a point array - NPARRAY - not an image. Draw it (CV Draw Polygon), or feed it to cv2_isContourConvex, cv2_contourArea, or back into CV Points To Contour.

Inputs and outputs

  • curve (NPARRAY) - a point set, not pixels; the author's tooltip notes the points must be float or integer, so a uint8 array is not what this wants. The pack's CV Contour To Points is the bridge from CV Find Contours.
  • nsides (INT) - how many sides you want.
  • epsilon_percentage (optional FLOAT, default −1) - area budget, or leave it off to fit exactly N sides.
  • ensure_convex (optional BOOLEAN, default True) - hull the input first.
  • nparray - the fitted polygon.

Where it's useful

  • Regularising a noisy contour. You found the edge of a panel; you want the panel's polygon, not the edge's jitter. nsides = 4 on the convex hull gives you a clean quad to warp from.
  • Counting sides as a classifier. Run it at 3, 4, 5, 6, 8 and compare the resulting areas against the contour's own cv2_contourArea. Whichever fits with the smallest error is your shape family. Cheap, deterministic, and it works.
  • Polygon IoU and overlap checks. The pack's CV Polygon IoU (convex) subgraph is built on the convex-polygon assumption that this node enforces.
  • Sticker, marker and label detection, where the target is a regular polygon by construction.

If your shape is genuinely concave - a wrench, a letter, a star - use approxPolyDP instead. A convex fit cannot follow a notch, and that's not a bug.

Install

ComfyUI Manager → comfyui_cv (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 and a recent V3-API ComfyUI; behaviour is curated against OpenCV 5.0.0.93. The contrib wheel matters - installing a plain opencv-python over it silently strips the contrib submodules.

Where people get burned

Expecting exactly N. With epsilon_percentage set, a tight budget returns a smaller polygon on purpose. Set it to −1 while you're calibrating.

ensure_convex off on a concave curve. cv2 assumes convexity and will produce a fit that looks nothing like your shape. Leave it on unless you've already verified convexity (cv2_isContourConvex).

uint8 or integer point arrays. The tooltip is explicit that points must be float or integer - and the shape still has to be a point chain OpenCV can read. Use CV Cast Array / CV Reshape Array if you assembled points yourself.

A two-vertex result. A degenerate or nearly-collinear contour can't be fit; garbage in, two points out.

Confusing the epsilon semantics with approxPolyDP. Here it's a percentage of area, in the other node it's pixels of distance. Same word, different units - an easy way to spend twenty minutes tuning the wrong thing.

Categoryimage/CV/low-level/cv2 A

Inputs (4)

NameTypeDefaultDescription
curveNPARRAYInput vector of a 2D points stored in std::vector or Mat, points must be float or integer. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
nsidesINT0-2147483648–2147483647The parameter defines the number of sides of the result polygon.
epsilon_percentageoptFLOAT-1.0000-1e+38–1e+38defines the percentage of the maximum of additional area. If it equals -1, it is not used. Otherwise algorithm stops if additional area is greater than contourArea(_curve) * percentage. If additional area exceeds the limit, algorithm returns as many vertices as there were at the moment the limit was exceeded. Preset to the OpenCV default (-1.0).
ensure_convexoptBOOLEANtrueIf it is true, algorithm creates a convex hull of input contour. Otherwise input vector should be convex. Preset to the OpenCV default (True).

Outputs (1)

NameTypeDescription
nparrayNPARRAY—