CV Draw Polygon
Outlines, filled quads, and masks from rotated boxes
- source
- points
- image
Why you'd reach for this
Two jobs in one node. The obvious one: draw an outline through a point list - a projected object outline, a document quadrilateral after rectification, a rotated detector's quads. The less obvious, more useful one: set thickness to 0 and it fills instead, which turns a polygon into a mask. Rotated text quads, a quadrilateral you found with CV Find Quadrilateral, any N-corner region - filled into a MASK primitive, no thresholding involved.
That's the mask-creation path in this pack: geometry in, filled region out. It's a deterministic alternative to painting or segmenting a region by hand.
How it works
(N, 2) input means one polyline or polygon through N points. (N, M, 2) means N separate M-point polygons - which is exactly the shape CV EAST Text Detect emits for its rotated text quads, so one node draws a whole page of text boxes.
closed connects the last point back to the first. When thickness = 0, filling happens via cv2.fillPoly and both closed and line_style are ignored (a filled polygon is always closed). The fill value is taken from the blue component on a single-channel canvas, since that's the only channel a MASK has.
Non-solid line_style values - dashed, dotted, dash-dot - go through the pack's own dash walker, because cv2 has no stroke pattern at all: segments are walked by arc length and stamped as short solid pieces, with the positions kept in float until each piece is placed so the pattern doesn't drift along a long edge. Same tool as the contour and path nodes, same reason for existing: colour alone can't separate two overlaid line sets for a colour-blind viewer or in greyscale, so two outlines on one image should differ in style, not just in hue.
One more trick from the node's own description, and it's a good one: to draw conditionally - only when CV Find Homography reports found = true, say - select between this node's output and the untouched image with a control-flow node such as Basic Data Handling's if/else. Its lazy inputs skip the drawing branch entirely when it isn't taken, so nothing runs and nothing is drawn.
Under 2 points raises: you can't draw a line through one point, and the error names the array shape you passed.
Inputs and outputs that matter
- points -
(N,2)for one polygon,(N,M,2)for many. This is the input to get right; everything else is cosmetic. - thickness - pixels, or 0 for filled. The mask-making switch.
- closed - closed polygon vs open polyline. Ignored when filling.
- color - single value or BGR tuple. On a MASK canvas use a single value;
'(0, 0, 255)'keeps only the blue component. - line_style (optional) - the dash patterns, ignored when filled.
- image - the only output, same format as the source.
Install
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 recent ComfyUI (V3 node API), or install ComfyUI CV via ComfyUI Manager. Pure CPU cv2; no model, no GPU.
Common issues
- "Need at least 2 points" - the array came out with fewer than two rows, usually because an upstream detector found nothing and the filtering pipeline emptied it. Guard it with the thing's
foundflag. - Filled output is black/white with no outline. That's
thickness = 0doing what it says: filled, no stroke. If you want both, run the node twice. - Only one of several polygons drawn. Your array is
(N,2)when you meant(N,M,2)- the node flattens and draws one polyline through everything. Nested shapes can't be expressed in two dimensions plus a count; the three-dimensional form is the one you want. - Outline invisible on a MASK. BGR tuple on a single channel. Use
'255'. - Contrib build. Installing a non-contrib OpenCV wheel over the contrib one empties the shared
site-packages/cv2contrib submodules; nodes backed by contrib APIs then vanish from the pack.tools/repair_opencv_contrib.py --check/--apply.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| source | COMFY_MATCHTYPE_V3 | Image or mask to draw on (a copy is made). Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size. | |
| points | NPARRAY | (N,2) for a single polyline/polygon, or (N,M,2) for N separate M-point polygons (e.g. rotated quads from EAST text detection). | |
| color | STRING | (0, 0, 255) | Color as a single value (broadcast to all channels) or BGR tuple, e.g. '255' or '(0, 0, 255)'. Shorter tuples are zero-padded; longer tuples are truncated. |
| thickness | INT | 30–64 | Outline width in pixels. 0 = filled polygons (cv2.fillPoly) - useful for creating masks. |
| closed | BOOLEAN | true | Connect the last point back to the first (closed polygon) vs leave it open (polyline). Ignored when thickness=0 (always filled). |
| line_styleopt | COMBO | solid | Stroke pattern. Colour alone cannot separate two overlaid line sets for a colour-blind viewer or in greyscale - give the second set a different style and the picture reads without the palette. 'solid' is cv2's own line. Ignored when the polygons are filled (thickness=0, or a MASK canvas). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | COMFY_MATCHTYPE_V3 | Same format as the image input. |