CV Draw Path (ordered)
Showing which end a trajectory started from
- source
- points
- gap_mask
- image
- count
Why you'd reach for this
A plain polyline shows you the shape of a path - a camera trajectory, a tracked point, a contour - but not its direction. That's usually the one thing you need. Did the drone fly the loop clockwise? Is this track going forward in time or backward? Which end is the start?
This node draws an ordered sequence and makes its direction and its ends readable, with three redundant cues on purpose: a colour (or thickness) ramp from first point to last, a different marker shape at each end, and optional heading arrows along the way. Redundant because greyscale, colour blindness and a busy background each kill one cue, and the pack's author is explicitly designing against that - he says so in several of these nodes' own descriptions.
It's the right node for any ordered 2D sequence. For a metric path, the intended chain is CV Project To Plane → CV Fit Points To Box to get pixels, then this, with CV Draw Plot Frame underneath for the axes.
How it works
Points are drawn in order, segment by segment. progress is the direction cue:
- colormap along path (default) walks a sequential ramp from start to end. VIRIDIS by default, and the tooltip's warning is worth repeating: keep a sequential map (VIRIDIS, MAGMA, PLASMA). A rainbow like JET isn't monotone in brightness, so it invents features that aren't in the data and prints as mush. On a 1- or 2-channel canvas the ramp degrades into a luminance ramp, which is the point - it still reads.
- thicken along path grows the stroke instead, for when the colour is already carrying something else.
- solid leaves the line flat and leans entirely on the end markers.
The heading arrows are more careful than they look. arrow_every = N draws one every N points, but the arrow spans a fixed arc length back along the polyline rather than to the previous sample - because consecutive trajectory samples can be a fraction of a pixel apart, and an arrowhead drawn between two near-identical points is invisible. Fixed arc length gives every arrow the same readable size regardless of speed. Arrows over a stretch that isn't moving are skipped: an arrow there would point nowhere.
gap_mask is the honesty feature. (N,) of 0/1, where 0 means this point was held rather than measured - found_mask from CV Visual Odometry (Sequence) is the canonical source. Held points get a small x marker and their segment is drawn dotted, so a stretch the estimator gave up on can't be mistaken for real data. Note the reasoning in the tooltip: a held point sits exactly on its predecessor, so the segment has no length to hang a dash pattern on - the marker is what carries the information.
line_style (dashed, dotted, dash-dot) is implemented by walking the segment and stamping short solid pieces, since cv2 has no stroke pattern. Two caveats the author flags himself: the pattern restarts at every segment, so on a densely sampled path (one sample per video frame, a pixel apart) a dashed line renders solid - lean on progress and the markers instead.
Inputs and outputs that matter
- points -
Nx2orNx1x2, in order. NaN points are skipped so a gated sequence keeps its indexing; none/empty is a pass-through. - progress + progress_colormap - the direction cue and its ramp.
- start_marker / end_marker - default a filled square and an up triangle. Make them different shapes; that's half the "which end is which" answer and it survives greyscale.
- marker_radius - default 6. A single-point path still gets marked.
- arrow_every (optional) - 0 means none. 10–20 is usually plenty.
- label_ends (optional) - text at the two ends with a contrast halo: none,
start/end, or the actual indices, which is what you want when the path is a frame sequence. - gap_mask (optional) - as above.
- image and count.
countis points drawn.
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 ComfyUI recent enough for the V3 node API, or install ComfyUI CV from Manager. No model - pure CPU drawing.
Common issues
- Dashed line looks solid. Dense sampling, as described above: the pattern restarts each segment. Use
progressand the end markers. - Two paths on one canvas are indistinguishable. You varied only the colour. Give the second one a different
line_styleand different end markers - that's the design intent. - Arrows absent.
arrow_everyis 0, or the path is standing still in those stretches. - Output invisible on a MASK. A BGR tuple keeps only its blue component on a one-channel canvas. Use a single value.
- You want axes and units underneath. That's
CV Draw Plot Frame, drawn first, fed the same world points and margin asCV Fit Points To Box. - Contrib wheels. This pack needs the contrib OpenCV build; a plain
opencv-pythonover it empties the contrib submodules.tools/repair_opencv_contrib.py --check/--apply.
Inputs (13)
| 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. | |
| points | NPARRAY | Nx2 or Nx1x2 points IN ORDER (first = start). Non-finite points are skipped, so a gated sequence keeps its indexing. None/empty -> passthrough. | |
| color | STRING | (0, 255, 0) | Colour as a single value (broadcast to all channels) or a BGR tuple, e.g. '255' or '(0, 255, 0)'. Used for the markers and labels always, and for the line itself unless progress = 'colormap along path'. |
| progress | COMBO | colormap along path | How the direction of travel is shown along the line. 'colormap along path' walks a sequential ramp from start to end (the clearest, and it survives greyscale because the ramp is monotone in luminance). 'thicken along path' grows the stroke instead - use it when the colour is already carrying something else. 'solid' leaves the line flat and relies on the end markers. |
| progress_colormap | COMBO | COLORMAP_VIRIDIS | Ramp for 'colormap along path'. Keep a SEQUENTIAL map (VIRIDIS, MAGMA, PLASMA): a rainbow like JET is not monotone in brightness, so it invents features that are not in the data and prints as mush. |
| thickness | INT | 21–64 | Line thickness in pixels (the maximum, for 'thicken along path'). |
| line_style | COMBO | solid | Stroke 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. Note that the pattern restarts at every segment, so on a DENSELY sampled path (one sample per video frame, a pixel apart) a dashed line renders solid - there lean on 'progress' and the end markers instead. |
| start_marker | COMBO | filled square | Marker at the FIRST point. Marker 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. |
| end_marker | COMBO | triangle up | Marker at the LAST point - make it a different shape from start_marker, that is what tells the two apart. |
| marker_radius | INT | 61–128 | Radius of the two end markers, in pixels. 0-length paths still get their single point marked. |
| arrow_everyopt | INT | 00–100000 | Draw a heading arrow every N points (0 = none). The arrow spans a fixed arc length back along the path, so it stays readable where samples are dense. |
| label_endsopt | COMBO | none | Text at the two ends, drawn with a contrast halo so it survives any background. 'first / last index' stamps the actual indices, which is what you want when the path is a frame sequence. |
| gap_maskopt | NPARRAY | (N,) 0/1 per point. A 0 means that point was HELD rather than measured (e.g. 'found_mask' from 'OpenCV Visual Odometry (Sequence)'). Those points get a small x and their segment is drawn dotted, so a stretch the estimator gave up on cannot pass for real data. The marker is what carries it: a held point sits exactly on its predecessor, so the segment has no length to draw a style with. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | COMFY_MATCHTYPE_V3 | Same format as the image input. |
| count | INT | How many points were drawn. |