Nodes/ComfyUI CV/CV Draw Rays
ComfyUI Node

CV Draw Rays

Bearings out of a shared origin, drawn over the evidence

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
CV Draw Rays
  • source
  • points
  • labels
  • image
◄origin_x0.00►
◄origin_y0.00►
◄thickness2►
◄color(0, 255, 255)►

Why you'd reach for this

Anything that measures angle-from-a-point produces bearings, and a bearing is one number that means nothing until it's drawn from its centre: a clock hand, a direction of arrival, a disk's radial tick marks, a laser scan line. You compute the endpoints from angles, then join each endpoint to a shared origin, and the picture is instantly assessable - you can see at a glance whether the hands point at the numerals or between them.

That's the whole node, and its intended use is the one the author states: render the final detected bearings on top of the raw evidence. The angle computation happens upstream; this node draws.

How it works

For each row in points it draws one anti-aliased line from (origin_x, origin_y) to that point. The origin is a pair of floats, not a socket, and it's shared by every ray in one call - which is what makes it a ray drawing rather than a segment drawing. (Segments are CV Draw Segments; arrows between two matched sets are CV Draw Flow Vectors.)

Building the endpoints from angles is the upstream half, and it's CV Polar To Points: cartesian in, (r, theta) out and back. So the canonical chain for a dial reader is: pixels → find the centre → CV Polar To Points to convert, or its inverse to turn a detected angle into an endpoint → this node to draw it over the original photo → compare.

The labels input gives one colour per ray cluster from the same deterministic, colour-vision-deficiency-safe palette as CV Draw Points, and connecting it overrides the flat colour exactly as it does in the sibling nodes. That's how you group rays - by detected class, by confidence band, by which stage of the pipeline found them - and it keeps the colour a ray gets consistent with the colour its point gets elsewhere in the graph.

None or an empty point set passes the image through unchanged. Unlike the siblings that draw a marker per point, this one iterates every row and hands the coordinates straight to cv2, so don't feed it NaN entries to mean "no ray here" - filter the array first.

Inputs and outputs that matter

  • points - Nx1x2 ray endpoints, not angles. The angles were converted upstream.
  • origin_x / origin_y - the shared origin as floats. Pixel coordinates, same frame as the image you're drawing on.
  • thickness - default 2. Thin rays over a busier overlay read better than thick ones.
  • color - a bare number or a BGR tuple; ignored when labels is connected, and on a MASK only the blue component survives, so use a single value there.
  • labels (optional) - per-cluster colours.
  • image - the only output. There's no count on this node, so if you need "how many rays", count the array upstream.

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, a current ComfyUI (this pack uses the V3 node API), or install ComfyUI CV from ComfyUI Manager. CPU-only cv2 drawing.

Common issues

  • Rays converge somewhere other than the feature. The origin is in a different coordinate frame - usually because the image was resized or cropped and the origin wasn't transformed with it.
  • Rays point in mirrored directions. Pixel rows grow downward, so a bearing measured with y-up comes out vertically flipped. Negate y (or draw on a canvas that already went through the same axis convention) - the same trap CV Draw Plot Frame's y_axis control exists to prevent.
  • Nothing drawn. Empty point array, or points given as angles instead of x,y endpoints. This node wants endpoints.
  • Invisible on a MASK. BGR tuple, one channel, blue only. Use '255'.
  • Contrib wheels. This pack depends on opencv-contrib-python-headless; installing a plain opencv-python over it empties the shared contrib submodules and contrib-backed nodes disappear. tools/repair_opencv_contrib.py --check, then --apply.
Categoryimage/CV/points

Inputs (7)

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 ray endpoints.
origin_xFLOAT0.00-1000000–1000000X pixel coordinate of the reference origin (e.g. the dial center, anchor, or ray start).
origin_yFLOAT0.00-1000000–1000000Y pixel coordinate of the reference origin (e.g. the dial center, anchor, or ray start).
thicknessINT21–64Ray line width in pixels.
colorSTRING(0, 255, 255)Color as a single value (broadcast to all channels) or BGR tuple, e.g. '255' or '(0, 255, 255)'. Shorter tuples are zero-padded; longer tuples are truncated. Ignored when labels are connected.
labelsoptNPARRAY(N,) integer labels: one color per cluster.

Outputs (1)

NameTypeDescription
imageCOMFY_MATCHTYPE_V3Same format as the image input.