CV Draw Ellipses
Because straight-line fitting lies about round things
- source
- ellipses
- labels
- image
- count
Why you'd reach for this
An ellipse's five numbers - centre, two semi-axes, an angle - are a compact, honest description of anything roundish seen at an angle. Rims, eyes, coins on a table, the end of a cylinder. Ellipse fitting is how classic CV describes them, and it's also how the pack's Edge Drawing node reports what it found.
But five numbers per object are unreadable in a table, and an ellipse drawn slightly wrong is very visible - you instantly see whether the fit hugs the rim or floats somewhere near it. This node is that check.
How it works
It takes Nx5 rows of (cx, cy, semi_axis_a, semi_axis_b, angle_deg) and calls cv2.ellipse once per row. Nx4 is accepted too, treated as an axis-aligned ellipse with angle 0 - a convenience so you can hand it a centre-and-radii set without padding a column of zeros yourself. A circle is just a == b, so you don't need a separate node for it.
CV Edge Drawing emits exactly this row layout, which is the intended pairing: that node finds ellipses among its segments and lines, and this one draws them so you can see whether the detector's ellipses are the objects you wanted or the shadows next to them.
Like every drawing node here, -1 as thickness fills the shape, and draw_centers defaults on - a small dot at each centre. With several concentric or nested fits that dot is what keeps the render legible instead of a pile of rings.
Also like the rest of the pack: None or an empty array passes the image through unchanged with count = 0. Hough-style detectors return nothing all the time; treating that as an error would make the node unusable in a folder-wide run. And the output format follows the input, IMAGE → IMAGE, MASK → MASK, so the node slots into a mask graph without conversion.
Inputs and outputs that matter
- ellipses -
Nx5orNx4. Get the column order right; a swapped semi-axis pair gives you a plausible-looking ellipse rotated by 90°, which is exactly the kind of bug a visualizer is supposed to catch. - thickness - default 2,
-1fills. - color - a bare number (broadcast to all channels) or a BGR tuple. On a MASK, only the blue component survives, so use
'255'. - draw_centers - default true.
- labels (optional) - one colour per cluster, from the same safe categorical palette as
CV Draw Points, so an ellipse and the points it came from agree on colour. - image and count. Branch on
countwith an if/else (Basic Data Handling's, which the README names as a companion pack) if the nothing-found case needs its own path - that's the pattern the author's own tooltip suggests, and it beats letting an empty overlay pretend to be a result.
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 ComfyUI recent enough for the V3 node API, or search ComfyUI CV in ComfyUI Manager. No model, no VRAM - this is cv2.ellipse on the CPU.
Common issues
- Ellipses elsewhere on the frame than the objects. You're drawing detections computed on a resized or letterboxed copy. Fit and draw at the same resolution.
- Degenerate slivers. A near-zero semi-axis means a bad fit - probably too few inlier points. Look upstream at how many points fed the fit.
- Invisible on a mask. BGR tuple, one channel, blue-only. Use a single value.
- Angle looks 90° off.
semi_axis_aandsemi_axis_bswapped, or the angle is in radians from whatever produced the array. cv2's angle here is degrees - and the node is strict about the array: anything that isn'tNx5orNx4raises with the shape it got. - Contrib wheels. A plain
opencv-pythoninstall overopencv-contrib-python-headlessempties the shared contrib submodules and contrib-backed nodes disappear from the pack.tools/repair_opencv_contrib.py --checkthen--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. | |
| ellipses | NPARRAY | Nx5 (cx, cy, semi_axis_a, semi_axis_b, angle_deg) or Nx4 (angle assumed 0); 'OpenCV Edge Drawing' plugs in directly. | |
| thickness | INT | 2-1–64 | Outline thickness; -1 fills the ellipses. |
| color | STRING | (0, 255, 0) | Color as a single value (broadcast to all channels) or BGR tuple, e.g. '255' or '(0, 255, 0)'. Shorter tuples are zero-padded; longer tuples are truncated. Ignored when labels are connected. |
| draw_centers | BOOLEAN | true | Also mark each center with a small dot. |
| labelsopt | NPARRAY | (N,) integer labels: one color per cluster. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | COMFY_MATCHTYPE_V3 | Same format as the image input. |
| count | INT | How many ellipses were drawn - branch on it with if/else for the nothing-found case. |