Nodes/ComfyUI CV/CV Draw Points
ComfyUI Node

CV Draw Points

Markers, cluster colours, and why shape beats hue

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
CV Draw Points
  • source
  • points
  • labels
  • image
◄marker_radius5►
◄color(0, 255, 0)►
◄marker_shapefilled circle►

Why you'd reach for this

You have coordinates - corners, keypoints, a cluster centroid set, back-projected 3D points flattened to a plane - and you want to see where they land on the picture. That's it. This is the base case of the pack's visualization family, and the node the other point drawing nodes are variations on.

It earns its keep beyond "put dots on image" in two ways: label-driven cluster colours, and marker shapes. Both are there because colour alone is a failure-prone channel, and the author is unusually consistent about designing around that.

How it works

Every point in the array gets a marker at its coordinates. marker_shape picks from filled/open circle, filled/open square, cross, star, diamond, triangle - all drawn anti-aliased. Points with a non-finite coordinate are skipped rather than throwing (int(NaN) raises, and one hidden point shouldn't take down an overlay); that's the pack's standard convention that NaN means "no position", not "error". None or an empty array passes the image through untouched - cv2.goodFeaturesToTrack returning None is a normal outcome, not a failure.

The interesting input is labels: an (N,) integer per point, one colour per cluster. The mapping from label to colour is deterministic and stable per channel count, so the same cluster always gets the same colour across nodes - and it comes from a colour-vision-deficiency-safe categorical palette rather than a rainbow. On a single-channel canvas where hue can't exist at all, it falls back to spaced grey levels instead of averaging the palette colours; averaging them collapses every cluster to nearly the same grey, which would defeat the entire purpose. Small detail, correct one. Labels must match the point count or the node raises with both numbers.

Where the shape matters: two point sets drawn on one image in two colours are the same picture to a dichromat, in greyscale, or over a busy photo. Give the second set a different marker shape or radius and the distinction survives all three. That's not decoration, it's the reason the parameter exists - and it's the advice the node's own description gives you.

Inputs and outputs that matter

  • source - IMAGE, MASK or NPARRAY; output comes back in the same format, so MASK pipelines stay single-channel throughout.
  • points - Nx1x2, or None.
  • marker_radius - default 5. Two sets on one canvas: give them different radii and shapes.
  • color - a bare number (broadcast to all channels) or a BGR tuple. Ignored when labels is connected.
  • labels (optional) - per-cluster colours.
  • marker_shape (optional) - default filled circle.
  • image - the only output; no count on this one.

A typical graph: CV Filter Points By Distance → CV Draw Points for a look, with the filtered array also feeding whatever consumes it. The drawing branch is a leaf you delete before shipping; keep the data path clean.

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, ComfyUI with the V3 node API, or search ComfyUI CV in ComfyUI Manager. No model, no VRAM - plain cv2 drawing.

Common issues

  • Nothing visible. Empty point array (pass-through), points off-canvas, or a BGR tuple on a one-channel MASK where only blue survives. Use '255' on masks.
  • Points drawn in the wrong place. You drew on a resized copy while the coordinates came from the original. Same resolution, both sides.
  • Clusters indistinguishable. Too many labels for the palette, or you're looking at a MASK (grey levels only carry so many classes). Use shapes as well.
  • Length mismatch error. labels rows ≠ point rows.
  • Contrib wheels. This pack needs the contrib build of OpenCV; installing plain opencv-python over it empties the contrib submodules and contrib nodes stop appearing. tools/repair_opencv_contrib.py --check / --apply.
Categoryimage/CV/points

Inputs (6)

NameTypeDefaultDescription
sourceCOMFY_MATCHTYPE_V3Image 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.
pointsNPARRAYNx1x2 points to mark (or None -> passthrough).
marker_radiusINT51–128Radius of each filled circle marker, in pixels.
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. Ignored when labels are connected.
labelsoptNPARRAY(N,) integer labels: one color per cluster.
marker_shapeoptCOMBOfilled circleMarker shape. Two point sets drawn on one image in two colours are the same picture to a colour-blind viewer - give the second set a different shape (or radius) and the distinction survives. 'filled circle' is the original marker.

Outputs (1)

NameTypeDescription
imageCOMFY_MATCHTYPE_V3Same format as the image input.