cv2.rectangle (1/2)
Draw a box from two corners, in the right colour order
- source
- pt1
- pt2
- result
What it does
Draws one axis-aligned rectangle onto an image, mask or array: cv2.rectangle(source, pt1, pt2, color, thickness, lineType, shift). Two corners in, canvas out.
Boring? Yes. Also the node that turns raw numbers into something you can look at - a detected box, a crop region, a tracking window, a debug overlay while you build a pipeline. In a graph full of arrays, a rectangle is often the only feedback you get that your math is aiming at the right part of the picture.
It's one of ~470 auto-generated raw cv2.* wrappers in the pack. There's a curated alternative (CV DrawPolygon, CV DrawContours, CV DrawLabels) when you want a loader-friendly, opinionated node; this is the thin one.
Inputs
- source - the canvas. This is a MatchType socket: an IMAGE comes back as an IMAGE, a MASK comes back as a MASK, an NPARRAY stays an NPARRAY. Drawing onto a mask is completely legitimate - that's why the socket is named "source" rather than cv2's "img". Not a LATENT socket, though - like the other drawing primitives it works on images, masks and arrays, and it handles an IMAGE batch frame by frame (so a 30-frame batch gets the same box stamped on all 30 frames).
- pt1, pt2 - CV_TUPLE corner points, defaults
(0, 0). Any two opposite corners; order doesn't matter, cv2 sorts it out. Author them with CV Tuple, or type the literal(x, y). - color - a STRING literal, default
(0, 0, 0, 0). This is where beginners get bitten. The pack's scalar convention is cv2's, which for an IMAGE canvas means BGR:(255, 0, 0)is blue,(0, 0, 255)is red. And the default is pure black with zero alpha - on a dark image you get an invisible rectangle and conclude the node is broken. The shipped example workflows use(255, 0, 0, 0)and(0, 0, 255, 0)for exactly this reason.
Optional:
- thickness - default 1. Set it to -1 to fill the rectangle instead of outlining it; that's the idiom the pack's own examples use for filled debug boxes.
- lineType -
LINE_AAby default, which is the antialiased line;LINE_8when you want hard pixel edges (the pack's Kalman-tracking example usesLINE_8). - shift - default 0. A fixed-point denominator applied to the coordinates:
shift=3means the points are in eighths of a pixel. Almost always leave it.
Output
result - the same thing you fed in, type-echoing, with your rectangle on it. Wire it to Save Image / Preview Image to see it, or downstream into more cv2 nodes. It's an image, not a data structure: nothing about the box comes out as numbers, so if you need the coordinates elsewhere, use a Primitive/CV Tuple fan-out rather than trying to read them back from the pixels.
A real wiring pattern
The reason people end up here: a crop-and-paste pipeline where you compute boxes numerically, draw them to verify, then crop with CV Crop by BBoxes. Two nodes to sanity check, one box to look at. It's also how you visualise a tracker: the pack's shape-classifier and shape-moments playground workflows draw the box they detected onto the frame, so a wrong answer is visible instead of merely wrong.
Install
Manager → search "ComfyUI CV" (bmad4ever), or:
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 ComfyUI recent enough for the V3 node API. Restart ComfyUI, then reload the browser page for the nodes to appear.
Troubleshooting
Nothing appears on the image. Nine times out of ten it's the colour (black on black), the second most common is thickness left at 1 on a 4K frame - the line is there, you just can't see one pixel of it. Third: pt1/pt2 still at (0, 0), which draws a zero-size rectangle in the corner.
The box is the wrong colour. BGR, not RGB. Swap the first and third components.
It works on one image, not on a batch. The drawing primitives are on the pack's per-frame safe list, so an IMAGE batch gets every frame annotated - but the values are the same for every frame. If you want a different box per frame you need the (2/2) variant or four wired numbers, not a stale widget.
Import errors after installing another CV pack. tools/repair_opencv_contrib.py --check diagnoses a contrib wheel that got overwritten. Drawing nodes are core cv2 and survive that, but the pack's contrib nodes won't.
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. | |
| pt1 | CV_TUPLE | 0,0 | Vertex of the rectangle. 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. |
| pt2 | CV_TUPLE | 0,0 | Vertex of the rectangle opposite to pt1 . 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) | Rectangle color or brightness (grayscale image). 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. |
| thicknessopt | INT | 1-2147483648–2147483647 | Thickness of lines that make up the rectangle. Negative values, like #FILLED, mean that the function has to draw a filled rectangle. Preset to the OpenCV default (1). |
| lineTypeopt | COMBO | LINE_AA | Type of the line. See #LineTypes |
| shiftopt | INT | 0-2147483648–2147483647 | Number of fractional bits in the point coordinates. Preset to the OpenCV default (0). |
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. |