cv2.minAreaRect
The rotated box that fits your contour, angle quirks included
- points
- rotated_rect
Axis-aligned bounding boxes are for people who never photographed a tilted object. cv2.boundingRect gives you the upright box around a contour, which is fine for a face and wrong for a credit card at 20 degrees - you end up with a box twice the area of the thing inside it, and your crop includes a load of background. cv2.minAreaRect gives you the rotated rectangle: the smallest rectangle of any orientation that contains your points.
That's the standard object-oriented-box primitive. It's what you want for deskewing a document, measuring the orientation of a subject, cropping a rotated card or book or license plate, or feeding a warp that straightens something out.
The input is points, not a picture
points is NPARRAY-only - the tooltip is explicit that this is "a data array (points / matrix), NOT an image". The usual route in is CV Find Contours → a select or filter node → CV Contour To Points, and the dtype the geometry functions want is the one the pack's tooltips keep pointing you at. A flat array won't do; these functions want an (N,2) point set, and the pack's point utilities (CV Points, CV Reshape Array) are there for exactly the case where yours isn't.
The single output is a CV_ROTATED_RECT - a composite socket carrying ((center_x, center_y), (width, height), angle in degrees). It exists so you don't have to smuggle five loose numbers between nodes, and it plugs directly into cv2.boxPoints (which turns it into the four corner points), the box variant of cv2.ellipse (draws the rotated ellipse inscribed in it), and cv2.rotatedRectangleIntersection (returns the overlap state and the intersection polygon). If you need the numbers, CV Split Tuple pulls them apart.
The one bit of composition I'd suggest every time: minAreaRect → cv2.boxPoints → CV Annotate Points or the pack's draw nodes, so you can look at the box before you build a crop on top of it.
Installing the pack
ComfyUI CV (bmad4ever/comfyui_cv) - search "comfyui_cv" in ComfyUI Manager, or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Restart ComfyUI. Python ≥ 3.12, a V3-API ComfyUI build, one pinned contrib OpenCV wheel, no models to download. minAreaRect is core OpenCV and effectively free to run.
Where people get burned
The angle convention. This is the classic. OpenCV changed how minAreaRect reports the angle back in 4.5, and the (width, height) ordering follows the angle, so a box you remember as (long side, short side) may now be the other way round - and the four corners boxPoints returns come back in an order that's defined but rarely the one you assumed. Don't hard-code "corner 0 is top-left"; sort or inspect the points. Every "my rotated crop is upside down / rotated 90°" post traces back here.
Flat point arrays. A 1×N array of coordinates is not N×2 points, and you'll get a box computed from nonsense. Check shapes with CV Array Shape.
Three points, or collinear points. Degenerate input gives you a degenerate rectangle, not an error. Filter contours by area first.
Confusing it with boundingRect. The upright box comes out of a different node, as a BOUNDING_BOX. If your crop node wants {x, y, width, height} and you've got a CV_ROTATED_RECT, you want the upright one - or you want a warp, not a crop.
Contrib nodes missing. The pack-wide one: all four opencv-* wheels share one site-packages/cv2, so a non-contrib wheel installed over the contrib one empties the contrib submodules and those nodes stop registering - no error, they're just gone from the menu. python tools/repair_opencv_contrib.py --check, then --apply.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| points | NPARRAY | - - - A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| rotated_rect | CV_ROTATED_RECT | - - - Rotated rectangle ((center_x, center_y), (width, height), angle in degrees) - wire it into cv2.ellipse's box, cv2.boxPoints or cv2.rotatedRectangleIntersection. |