cv2.fillConvexPoly
Turn four points into a mask (mind the LINE_AA default)
- source
- points
- result
Drawing a filled polygon is how you go from "these corner coordinates" to "a region I can mask, cut, or inpaint". It's the primitive behind every quad-based tool you've used - select four corners, get a surface. cv2.fillConvexPoly is the raw version of that, and two of its defaults are quietly wrong for mask work.
What it does, and the constraint in the name
You hand it a canvas, a point array, and a colour, and it fills the polygon formed by those points. The scanline fill means the whole interior is covered in one call, no per-pixel loop.
Convex isn't decoration. The function makes no attempt to detect or handle a concave outline; feed it one and you get a fill that crosses over itself - a plausible-looking shape, entirely wrong, with no error anywhere. If your region isn't convex, don't triangulate it by hand: this pack's CV Draw Contours fills contours and handles arbitrary outlines properly.
Inputs
source- the canvas, accepting an IMAGE, a MASK or an NPARRAY. It's required, so you always need an existing picture or mask to draw into; there's no "make me an empty canvas" behaviour. For a blank start, this pack hasCV Constant Like, which builds a constant array shaped like another one - that's your white or black sheet.points- NPARRAY only, the polygon vertices,N x 2. FromCV Pointsif you're typing corners, fromCV Image Cornersfor the four corners of the frame, or from a contour-approximation chain if you're deriving it.color- a string literal:"(0, 255, 0)"BGR on colour images, or a bare number, which broadcasts across components. Here's the trap for masks: on a single-channel canvas only the first component is used, and the default"(0, 0, 0, 0)"therefore fills with 0. On a mask that means "black", which is not a visible change to anything. If you want the region marked in a mask, pass255.lineType- defaultLINE_AA. Anti-aliased, i.e. the boundary pixels are blended and your fill has a soft gradient edge. For a hard binary mask you wantLINE_8; for a mask you'll feather anyway,LINE_AAis a gift.shift- fractional bits in the vertex coordinates.0means integer pixels; a non-zero value lets you specify vertices at subpixel precision. Leave it at 0 unless you have subpixel coordinates and know the scaling.
The single output, result, echoes the source's format - MASK in / MASK out, IMAGE in / IMAGE out, so this drops into a mask chain without a bridge. The drawing happens on a copy; your input array isn't modified.
Where it fits
Geometry-driven masking. Selecting a quadrilateral region to crop or warp; blocking out a sign or a logo; seeding an inpaint by covering exactly the area you want the model to redo; building a rough mask from corner coordinates instead of painting, when the region is a plane in the photo. The pack's own annotated-GrabCut and quad-warp demos are this family of node: a shape drawn as data, then fed to segmentation or a warp.
It's the honest counterpart to automating detection. A detector gives you a region when you can describe the object; four points give you one when you can't, and for a person blocking out a wall, a poster or a screen, corners are faster and more truthful than any model. For the paste-back half of the job - masks getting generous overlap and blur so the composite doesn't look pasted - inpainting.md is the short version of the actual advice.
Installing it
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
ComfyUI Manager: search comfyui_cv, install, restart. Python ≥ 3.12 and a recent V3-API ComfyUI. Node path: image/CV/low-level/cv2 F.
Traps
Concave outlines, as above - that's the one that silently produces garbage. The LINE_AA default producing soft edges when you wanted binary, and the colour literal's first-component rule meaning your mask fill was a no-op. Points must be an N x 2 array, not a flat list; a malformed point array is the most common hard error. And if the fill lands somewhere unexpected, suspect the coordinate frame - a polygon specified in the original 1024-pixel space drawn onto a 512-resized canvas looks almost like a bug in the node.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| source | COMFY_MATCHTYPE_V3 | The image output(s) echo this input's format. 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 | Polygon vertices. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. | |
| color | STRING | (0, 0, 0, 0) | Polygon color. cv2 Scalar as a literal, e.g. "(0, 255, 0)" (BGR) or "(0, 255, 0, 64)" (BGRA). A bare number broadcasts to every component, so "255" means (255, 255, 255, 255). Components past the target's channel count are ignored by OpenCV. |
| lineTypeopt | COMBO | LINE_AA | Type of the polygon boundaries. See #LineTypes |
| shiftopt | INT | 0-2147483648–2147483647 | Number of fractional bits in the vertex coordinates. Preset to the OpenCV default (0). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| result | COMFY_MATCHTYPE_V3 | Echoes the 'source' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY. |