Nodes/opencv-comfyui/OpenCV undistort_0
ComfyUI Node

OpenCV undistort_0

Straighten real-camera lens distortion before it hits the sampler

By geroldmeisinger·Created about a year ago·Updated about a year ago· 35
OpenCV undistort_0
  • src
  • cameraMatrix
  • distCoeffs
  • dst
  • newCameraMatrix
  • nparray

Every real photograph from a wide-angle or cheap lens is slightly bent - straight walls bow outward, faces at the frame edge stretch. undistort is the classical fix: given a camera's intrinsic matrix and distortion coefficients, it warps the image so the distortion cancels out. In a ComfyUI graph this matters more than people expect, because lens distortion quietly sabotages image-to-image work. Run img2img on a distorted photo and the model will happily learn the barrel bend as part of the style. Undistort first, and the geometry you feed the sampler is the geometry the real world had.

This is undistort_0, the image-level version of the correction. It's the straightforward one in the undistort family: full image in, corrected full image out. (There's an undistort_1 twin from the overload expansion - same function, same behavior - and undistortPoints / undistortImagePoints for correcting points rather than pixels, covered on their own pages.)

How it works

You supply two calibration objects:

  • cameraMatrix (NPARRAY) - the 3×3 intrinsic matrix: focal lengths, principal point, skew. This is [[fx, 0, cx], [0, fy, cy], [0, 0, 1]].
  • distCoeffs (NPARRAY) - the lens distortion coefficients: radial (k1, k2, k3, ...) and tangential (p1, p2). A 1×4, 1×5, 1×8, or 1×14 array depending on the model.

The optional newCameraMatrix lets you re-project onto different optics (useful for cropping away the black curved borders that undistortion leaves behind); leave it unwired to use the input camera matrix as-is. The optional dst is an out-parameter - leave it alone. Output is one nparray.

Where do the calibration values come from? That's the rub: OpenCV computes them with a checkerboard calibration routine, and this pack doesn't wrap that flow into a comfy one. Most people either calibrate in a standalone Python script and hard-code the values, or grab them from known EXIF/rig data. It's real work, but it's a one-time cost per camera, and the payoff is geometry that img2img won't silently absorb.

Installation

Pack-wide: ComfyUI Manager (search "OpenCV" or geroldmeisinger/opencv-comfyui), or git clone https://github.com/geroldmeisinger/opencv-comfyui into ComfyUI/custom_nodes, restart. Needs opencv-contrib-python (pip install opencv-contrib-python). No models.

Common issues

The classic failure is feeding a BGR image where a grayscale one is required (error: (-215:Assertion failed) img.type() == CV_8UC1) - convert with cvtColor (code=6) first, per the README. Wrong-sized distCoeffs throws an OpenCV assertion. And the usual pack rules: NPARRAY, batch size 1 (Image2Nparray errors on a batch - split with ImageFromBatch), Nparrays2Image on the way out.

Categoryimage/OpenCV

Inputs (5)

NameTypeDefaultDescription
srcNPARRAY
cameraMatrixNPARRAY
distCoeffsNPARRAY
dstoptNPARRAY
newCameraMatrixoptNPARRAY

Outputs (1)

NameTypeDescription
nparrayNPARRAY