cv2.findChessboardCorners
Cv2.findChessboardCorners in ComfyUI
- image
- patternSize
- bool
- nparray
This is the node you land on when you decide to calibrate a camera inside ComfyUI instead of in a Python script. It's the classic OpenCV chessboard detector - the one every calibration tutorial has used for fifteen years - wrapped raw, with the flag dropdown built in and nothing hidden.
Worth knowing up front: it's also the detector I'd consider the legacy path now. cv2.findChessboardCornersSB is more robust and returns better corners. But this one is cheaper, it's what most tutorials assume, and when it works it works. Start here if you're following along with something, move to SB when it starts failing on your photos.
The thing everyone gets wrong first
patternSize is the number of inner corners, not squares. A printed board with 10 squares across and 7 down has 9×6 = 54 inner corners, which is why the shipped 49_chessboard_playground.json example counts 54 of them. Order is (columns, rows) - points per row first, then points per column - matching OpenCV's Size(points_per_row, points_per_column). Get that backwards and you get false every time with no explanation whatsoever.
It's a two-component Size value, so in the graph you either type the two numbers into the widget or wire them from CV Tuple - the components travel as one value, which is the pack's way of making a half-connected Size impossible.
Inputs and outputs
image wants an 8-bit grayscale or colour view. The socket takes IMAGE, MASK or NPARRAY; an IMAGE becomes uint8 BGR frame 0, which is precisely the format wanted here, so Load Image → detector is a legal, working wire. (That's not true of every input in this pack - data params like camera matrices refuse images.)
flags renders as a dropdown with one toggle per OpenCV flag, and the default is CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE because that's cv2's own default. CALIB_CB_FAST_CHECK is the one worth switching on when you're triaging a folder of views: it bails immediately on frames with no board, instead of grinding through the full detector. CALIB_CB_FILTER_QUADS prunes false quads by shape, useful on cluttered backgrounds.
Outputs are bool and nparray. The boolean is the whole story: true only if the board was found and ordered correctly, row by row, left to right. False means nothing at all came back - there's no partial result to salvage. The array is Nx1x2, in that same row-major order, which is exactly the order CV Grid Points generates its planar object points in, so the two pair up without reinterpretation.
Where to wire it
Three destinations. cv2_drawChessboardCorners to see the grid overlaid - do this before trusting any calibration number. CV Grid Points plus cv2_solvePnP to get the board's pose in the camera; you need a camera matrix for that, which CV Camera Matrix builds from fx/fy/cx/cy. Or the curated CV Calibrate Camera (Chessboard), which takes a whole IMAGE batch of views and does detection, refinement and calibration in one box - if that's what you want, skip this node entirely.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Or install "ComfyUI CV" from ComfyUI Manager and restart. Python ≥ 3.12 and a V3-API ComfyUI are required; the pack will not load on an old core.
Common issues
Always false. In order of likelihood: you swapped columns and rows in patternSize; the board doesn't have a white margin around it (the detector needs the full pattern boundary visible); the print is under glass or on glossy paper and half the frame is a specular sheet; or the board is too small in the frame or too steeply angled. Boards stuck right into the image corners are a known weak spot.
Detection works but the corners are visibly a pixel or two off. That's expected - the detector's coordinates are approximate by OpenCV's own documentation, and it refines them internally with cornerSubPix. When that isn't good enough, cv2_find4QuadCornerSubpix or cv2_cornerSubPix refine further.
The node vanished from the menu. Contrib submodules went empty, which happens when a non-contrib opencv-python/opencv-python-headless wheel overwrote the contrib one in the shared site-packages/cv2. It's a common ComfyUI injury - version and wheel fights between custom nodes are routine. tools/repair_opencv_contrib.py --check diagnoses it; --apply fixes it.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| image | NPARRAY,IMAGE,MASK | Source chessboard view. It must be an 8-bit grayscale or color image. 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. | |
| patternSize | CV_TUPLE | 0,0 | Number of inner corners per a chessboard row and column ( patternSize = cv::Size(points_per_row,points_per_column) = cv::Size(columns,rows) ). One value with 2 components (w, h) - it travels as a whole, so it cannot arrive half-connected. Wire it from 'CV Tuple' or type the components in place. |
| flagsopt | STRING | CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE | Various operation flags that can be zero or a combination of the following values: - Use adaptive thresholding to convert the image to black and white, rather than a fixed threshold level (computed from the average image brightness). - Normalize the image gamma with equalizeHist before applying fixed or adaptive thresholding. - Use additional criteria (like contour area, perimeter, square-like shape) to filter out false quads extracted at the contour retrieval stage. - Run a fast check on the image that looks for chessboard corners, and shortcut the call if none is found. This can drastically speed up the call in the degenerate condition when no chessboard is observed. - All other flags are ignored. The input image is taken as is. No image processing is done to improve to find the checkerboard. This has the effect of speeding up the execution of the function but could lead to not recognizing the checkerboard if the image is not previously binarized in the appropriate manner. cv2.findChessboardCorners flags: one of none (0) plus any of CALIB_CB_ADAPTIVE_THRESH, CALIB_CB_NORMALIZE_IMAGE, CALIB_CB_FAST_CHECK, CALIB_CB_FILTER_QUADS, pipe-joined (e.g. "none (0) | CALIB_CB_ADAPTIVE_THRESH"). In the UI this renders as a dropdown with one toggle per flag. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| bool | BOOLEAN | — |
| nparray | NPARRAY | — |