cv2.drawMarker
Mark a point so you can actually see it
- source
- position
- result
Keypoints, corners, centroids, detections - half the nodes in an OpenCV-flavoured pack produce coordinates, and coordinates are invisible. drawMarker puts a small glyph at one: a crosshair, a star, a diamond, a filled triangle. It's the "where exactly did the detector think the eye was" node, and it's the difference between debugging and guessing.
The one thing that makes people think it's broken
color defaults to the literal "(0, 0, 0, 0)" - black, fully transparent-ish, i.e. invisible on the black image most people test with. You run the node, the preview comes back identical, and you conclude it does nothing. It's drawing. It's just drawing in black.
Type a real Scalar literal: "(0, 255, 0)" is green, and the format is BGR, so red is "(0, 0, 255)". A bare number broadcasts to every component, so "255" means white. Components past the target's channel count are ignored by OpenCV, per the tooltip.
The inputs
source is what you draw on and, as with every drawing wrapper here, you can hand it an IMAGE, a MASK or an NPARRAY - the result output echoes the same format back, so an IMAGE batch stays an IMAGE batch (each frame gets its own marker drawn and the results restack).
position is a CV_TUPLE of two components, (x, y), default (0, 0) - top-left corner, which is also why a marker you "can't see" sometimes is there, half off-frame. It travels as a unit, so you can type it or wire it from CV Tuple/its split components; it can't arrive half-connected.
color as above. These three are the required ones.
Then the glyph, which is the fun part:
markerTypeis a dropdown of OpenCV's wholeMARKER_*family, defaulting toMARKER_CROSS- a plain crosshair.MARKER_TILTED_CROSSis an X,MARKER_STARa six-point asterisk, and there are filled shapes (MARKER_DIAMOND,MARKER_SQUARE,MARKER_TRIANGLE_UP) for something that reads at a glance.markerSizeis the axis length in pixels, default 20.thicknessdefault 1. Push it to 2 or 3 if the marker is going onto a busy photograph.line_typedefaults toLINE_AA- anti-aliased, which is why your marker looks slightly soft if you zoom in.LINE_8gives you hard pixels.
Where it fits
Anywhere you've got points and want eyes on them. The pack's detector nodes - blobs, keypoints, chessboard corners, feature matches - all hand back arrays; drawMarker is the cheap overlay for one of them. It's also the honest way to check that a transform did what you think: mark where a point lands after a warp, before and after.
Against alternatives: OpenCV's own drawKeypoints exists as a wrapper in this pack too, but it draws the detector's whole keypoint set with its own idea of colour and size. drawMarker is the one you use when you want to annotate specific coordinates you chose - a click point, a centroid, a known landmark - rather than everything the algorithm found. For a batch of points, the pack's CV Draw Path (ordered) draws sequences where direction matters.
Being a drawing primitive, it's also in the family the pack treats carefully: cv2 drawing functions mutate their target image in place, so the wrapper passes a private copy of every array across the call boundary - your upstream cached IMAGE doesn't get scribbled on because a downstream node drew a crosshair. Nothing to configure, just a thing that would otherwise be a very confusing bug.
Installing comfyui_cv
Part of bmad4ever/comfyui_cv: roughly 470 auto-generated raw cv2.* wrappers plus curated nodes, a GPL-3.0 fork of Gerold Meisinger's opencv-comfyui, curated against OpenCV 5.0.0.93. Manager: search ComfyUI CV. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
Restart after. Python ≥ 3.12 and a recent ComfyUI on the V3 node API; the only dependency is opencv-contrib-python-headless~=5.0.0.93. Install the contrib wheel specifically - all four OpenCV distributions share one site-packages/cv2 and the last one installed wins, so a plain opencv-python quietly empties the contrib submodules and their nodes (tools/repair_opencv_contrib.py --check / --apply).
Common issues
Nothing visible. Almost always the black default color, or a position that's off-frame. Both are one widget away from fixed.
Marker in the wrong place. Remember the frame is (x, y) with y increasing downward, and position is the marker's centre, not its top-left.
Marker looks blurred. LINE_AA. Switch to LINE_8 for crisp pixels, or accept the softness - anti-aliased is usually what you want when you're compositing on top of a photo.
Same marker on every frame. That's the design, not a bug: the node draws one marker at one position. Loop the position values yourself, or use a node that takes a point list.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| source | COMFY_MATCHTYPE_V3 | The image output(s) echo this input's format. 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. | |
| position | CV_TUPLE | 0,0 | The point where the crosshair is positioned. One value with 2 components (x, y) - it travels as a whole, so it cannot arrive half-connected. Wire it from 'CV Tuple' or type the components in place. |
| color | STRING | (0, 0, 0, 0) | Line color. cv2 Scalar as a literal, e.g. "(0, 255, 0)" (BGR) or "(0, 255, 0, 64)" (BGRA). A bare number broadcasts to every component, so "255" means (255, 255, 255, 255). Components past the target's channel count are ignored by OpenCV. |
| markerTypeopt | COMBO | MARKER_CROSS | The specific type of marker you want to use, see #MarkerTypes |
| markerSizeopt | INT | 20-2147483648–2147483647 | The length of the marker axis [default = 20 pixels] Preset to the OpenCV default (20). |
| thicknessopt | INT | 1-2147483648–2147483647 | Line thickness. Preset to the OpenCV default (1). |
| line_typeopt | COMBO | LINE_AA | Type of the line, See #LineTypes |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| result | COMFY_MATCHTYPE_V3 | Echoes the 'source' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY. |