Nodes/ComfyUI CV/CV Find Quadrilateral
ComfyUI Node

CV Find Quadrilateral

The four corners of your document, without a model

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
CV Find Quadrilateral
  • image
  • contours
  • corners
  • found
  • area_fraction
◄epsilon_ratio0.020►
◄min_area_fraction0.05►

You have a photo of a page, a whiteboard, a poster or a business card, shot at an angle, with a coffee cup in frame. You want the four corners of the paper so you can straighten it. That's this node - and it does it with edges and geometry, no segmentation model, no GPU, in milliseconds.

CV Find Quadrilateral lives in bmad4ever's ComfyUI CV (a fork of Gerold Meisinger's opencv-comfyui): ~470 auto-generated cv2.* wrappers plus curated nodes, all classical CV. Worth having in a world where SAM is the default answer to "find the thing in the image": for this job - one big quadrilateral on a contrasting background - a corner detector is cheaper, deterministic, and doesn't need 2 GB of weights. Load one of those models when the shape is arbitrary. Load this when it's rectangular.

How it works

It doesn't look at pixels directly. You hand it the contour set, so the pipeline in front of it is the classic one: grayscale, a blur to kill texture, Canny, a morphological close to bridge gaps in the page border, then CV Find Contours. Contours go in, four corners come out.

Two passes, and the second one is why it works on real photos:

  1. Strict pass. Each contour, largest first, is simplified with cv2.approxPolyDP at a tolerance of epsilon_ratio × perimeter. The first contour that simplifies to exactly 4 convex corners and covers at least min_area_fraction of the frame wins.
  2. Fallback pass. If nothing qualifies, it re-simplifies each contour's convex hull and sweeps the tolerance upward until 4 corners remain. The hull absorbs the things that break pass one - a curled page corner, a shadow notch, a border chopped into a zigzag by print texture - and the fitted quad has to actually fit the hull, not just have four corners (which is also what stops a circle's hull from passing).

epsilon_ratio (default 0.02) is the knob you'll touch: raise it and wobbly edges collapse into straight lines more aggressively, which is what you want on a textured border and what over-simplifies a genuine 5-sided box. min_area_fraction (0.05) is your "don't hand me a stamp" filter.

Outputs

  • corners - 4x1x2, ordered top-left, top-right, bottom-right, bottom-left. That ordering is the whole point: hand arbitrary corners to a perspective transform and you get a twisted result.
  • found - boolean. Branch on it.
  • area_fraction - how much of the frame the quad covers.

Wire corners into CV Quad To Rectangle, which gives you the target rectangle with the true aspect ratio recovered from the corner geometry, then into cv2.getPerspectiveTransform and cv2_warpPerspective for the rectified page. When found is false the node returns the full image corners, so an unguarded warp is a harmless no-op - but branch anyway, or your batch quietly outputs unrectified photos that look fine in a thumbnail.

Install

ComfyUI Manager, search ComfyUI CV, 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 and a ComfyUI new enough for the V3 node API.

The example workflows load their sample photos from the pack's example_inputs/, which are not in ComfyUI/input. Run workflows/01_install_example_inputs.json once (a single node, nothing to wire), then reload the page - Load Image builds its dropdown when node definitions are fetched, so files copied mid-session don't show up until you refresh.

Common issues

Nothing found on a clean photo. Usually the contour feeding it isn't closed - Canny alone leaves a border full of gaps. That's why the example workflow blurs, then closes with a 5×5 rectangular kernel, before finding contours. Copy that chain rather than feeding raw Canny edges in.

It found the wrong rectangle. min_area_fraction too low (a book cover beat the page), or the contour list contains something genuinely larger. Sorting and thresholds happen inside, so the fix is upstream: threshold the edge map harder, or pre-filter contours.

Found in one frame, lost in the next. Video: this node sees frame 0 when you feed it a ComfyUI IMAGE batch. Feed frames one at a time through a loop if you're tracking a page across a clip, or use the homography path once you have tracking points.

Corners look right, warp looks torn. Check the ordering assumption holds - a quad detected as a rotated document still comes out TL/TR/BR/BL in image space, so if you expect portrait and the page is on its side, you'll need a rotate step. CV Quad To Rectangle recovers the aspect ratio, not the orientation.

Start from workflows/exercise_document_perspective.json: load, edges, contours, quad, rectified preview, and an inspect node printing the ordered corners and the area fraction.

Categoryimage/CV/contours

Inputs (4)

NameTypeDefaultDescription
imageNPARRAY,IMAGE,MASKThe photographed image - used for the area reference and the not-found fallback corners. 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.
contoursCV_CONTOURSFrom 'CV Find Contours'.
epsilon_ratioFLOAT0.0200.001–0.5approxPolyDP tolerance as a fraction of the contour perimeter. Higher merges wobbly edges into straight lines more aggressively.
min_area_fractionFLOAT0.050–1Smallest acceptable quad area as a fraction of the image area - rejects small rectangles that are not the document.

Outputs (3)

NameTypeDescription
cornersNPARRAY4x1x2 float32, ordered TL/TR/BR/BL (full image corners if not found).
foundBOOLEAN—
area_fractionFLOATArea of the detected quad relative to the image (0.0 if not found).