Nodes/ComfyUI CV/CV Draw Contours
ComfyUI Node

CV Draw Contours

Make Find Contours stop lying to you

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
CV Draw Contours
  • source
  • contours
  • image
◄color(0, 255, 0)►
◄thickness2►
◄fillfalse►
◄max_draw0►
◄line_stylesolid►

Why you'd reach for this

Contours are a set of arrays and the arrays always look plausible. Whether they follow the shape you care about - the subject instead of the wallpaper, one blob instead of four hundred - is a visual question, and this node answers it. It's also the fastest way to tell whether the threshold upstream of CV Find Contours needs work before you start tuning anything downstream.

How it works

It slices the contour set to max_draw if you set one - and because CV Find Contours emits contours sorted by area, largest first, max_draw = 1 draws the biggest blob in the frame. That ordering is the whole reason "at most N" is a useful control rather than an arbitrary one.

fill on, or line_style = solid, and it goes through cv2.drawContours with thickness -1 or your thickness. Any other line style takes a different path: cv2 has no stroke pattern at all, so the pack walks the polyline by arc length and stamps short solid segments, keeping positions in float until each dash is placed so the pattern doesn't drift along a long edge. Same trick as the pack's other line nodes, and it exists for a reason the author states flatly - colour alone can't separate two overlaid line sets for a colour-blind viewer or in greyscale, so give the second contour set a dashed style and the picture reads without relying on the palette.

Output format mirrors the input: IMAGE in, IMAGE out; MASK in, MASK out.

Inputs and outputs that matter

  • contours - a CV_CONTOURS set, i.e. the output of CV Find Contours, or a filtered/selected set from CV Filter Contours, CV Select Contour, CV Merge Contours.
  • thickness - ignored when fill is on. -1 isn't needed here; the boolean is the switch.
  • fill - turn it on to check what a contour actually encloses. Filling a contour derived from a ring-shaped mask is the classic way to discover it has a hole you didn't expect.
  • max_draw - 0 means all. On a noisy threshold that's thousands of contours and a black canvas; set it to 10 and you can see what the shape of the top ten is.
  • color - the stroke colour, as a bare number (broadcast to all channels) or a BGR tuple. On a one-channel MASK only its blue component survives.
  • line_style (optional) - solid, dashed, dotted, dash-dot. Ignored when filling.
  • image - the only output. Draw, then look; there's no count here, so if you need "was there anything", CV Find Contours already gives you the set size.

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 (the pack is built on the V3 node API), or install ComfyUI CV via ComfyUI Manager. Pure CPU cv2 drawing; no model, no VRAM.

Common issues

  • Nothing appears on a MASK. A BGR tuple on a single-channel canvas keeps only its blue component, so the default '(0, 255, 0)' becomes 0 and draws nothing visible. Use '255'.
  • A solid black (or white) image. max_draw at 0 with a bad threshold: thousands of contours overlapped into a filled mess. Cap it and fix the threshold upstream.
  • Only the biggest blob is drawn. That's max_draw = 1 doing exactly what it says. Raise it.
  • Contours drawn thin against the actual shape. Contours sit on the boundary pixels, so a 1-pixel outline over a bright subject is genuinely hard to read; 2–3 pixels and a contrasting colour is the fix, not a code problem.
  • Contrib trap. Installing plain opencv-python over the contrib wheel silently empties the contrib submodules and takes the pack's contrib-backed nodes with it. tools/repair_opencv_contrib.py --check tells you, --apply fixes it.
Categoryimage/CV/contours

Inputs (7)

NameTypeDefaultDescription
sourceCOMFY_MATCHTYPE_V3Image or mask to draw on (a copy is made; the input is not modified). 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.
contoursCV_CONTOURSContours to draw, e.g. from 'CV Find Contours'.
colorSTRING(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 - so on a single-channel MASK canvas a BGR tuple keeps only its BLUE component ('(0, 255, 0)' becomes 0, i.e. draws nothing visible). Use a single value like '255' for a MASK.
thicknessINT21–64Outline width in pixels (ignored when 'fill' is on).
fillBOOLEANfalseFill the contours instead of outlining them.
max_drawINT00–10000Draw at most this many contours (largest first, as sorted by 'CV Find Contours'). 0 = all.
line_styleoptCOMBOsolidStroke 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 'fill' is on.

Outputs (1)

NameTypeDescription
imageCOMFY_MATCHTYPE_V3Same format as the image input.