Nodes/ComfyUI CV/cv2.omnidir.initUndistortRectifyMap
ComfyUI Node

cv2.omnidir.initUndistortRectifyMap

Rectify a fisheye without the edge-pinching

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
cv2.omnidir.initUndistortRectifyMap
  • K
  • D
  • xi
  • R
  • P
  • size
  • nparray_0
  • nparray_1
◄m1type0►
◄flags0►

cv2.omnidir is OpenCV's implementation of the unified omnidirectional camera model - the one that can describe a lens or mirror with a field of view past 180°, which pinhole-plus-Brown-Conrady cannot. The pack's curated nodes call it CMei, after the Mei–Rives formulation, and if you've ever calibrated a fisheye with cv2.fisheye, this is the sibling model: an extra parameter xi (the mirror parameter) that slides between a pinhole (xi = 0) and a strongly curved mirror or fisheye (xi around 1), usually landing somewhere in the 0.5–1 range in practice.

This node is the one that builds the mapping tables. You give it a calibration and a decision about what projection you want the output in, and it hands back two NPARRAYs - unnamed, nparray_0 and nparray_1, holding what the underlying call calls map1 and map2 - which you feed to cv2_remap alongside the image. Nothing is rectified until the remap happens; these are recipes.

That split is the whole point, and it's why you'd use this rather than cv2_undistort: the maps don't depend on the image. Build them once, remap every frame of a clip with them. The pack even ships an exercise_efficient_video_remap example for the pattern.

The inputs

K, D, xi, R and P are all arrays. K is your 3×3 intrinsics; D is the omnidir distortion vector - expect four values ({k1, k2, p1, p2}), not the five-to-eight the pinhole model uses; xi is the mirror parameter and travels as an array here, which is not a typo (it's how the C++ signature reads - the sibling projectPoints takes the same quantity as a plain float, which is a nice example of why the generated layer exposes argument order rather than meaning). R is the rectification rotation - pass identity if all you want is undistortion. P is the new camera matrix of the virtual pinhole camera you're projecting onto, which is where the pack's CV Camera Matrix bridge node comes in handy (it builds a 3×3 K from fx/fy/cx/cy). Parse Matrix is the other way to get any of these into the graph from calibration text.

size is a CV_TUPLE of (w, h), and it's an input rather than something derived, so a (0, 0) here means an empty output. m1type and flags are bare integers with no dropdown: type 5 for CV_32FC1 (two float32 maps, the standard) or 11 for CV_16SC2 (a fixed-point pair, which remap runs faster), and flags picks the projection you're rectifying to. That last one is the interesting choice - perspective is the default assumption, but the module also offers cylindrical and stereographic output, and for a 180° lens stereographic is how you keep the edges from stretching into infinity. Look up the module's constants; they're not in the tooltips.

Why you'd want a non-perspective output

Stated plainly, because it's the reason to reach for omnidir over the pinhole path: a 180° fisheye forced onto a flat perspective plane has unbounded magnification at the frame edge. Peripheral pixels that occupied a few degrees get smeared across hundreds. Rectifying to stereographic (or cylindrical, for a panorama-ish strip) keeps that stretch bounded and gives you a view you can actually feed to a detector, a stitcher, or your eyes.

Install

ComfyUI Manager → search ComfyUI CV → install → restart, 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, ComfyUI on the V3 node API. cv2.omnidir is contrib-only - no contrib wheel, no node - and the pack's CV Build Information node will confirm what your installed build actually exposes. The cv2.omnidir tooltips in the UI are empty blanks; that's the generator finding no documentation in the type stubs, not a broken install.

Practical notes

  • You need a real calibration. The pack's CV Omnidir Calibrate (Chessboard) (and the 54_omnidir_calibration example) produce K, D and xi; guessing them produces a warped mess.
  • Maps are reusable, images are not. Build once per camera-and-output-size combination, then remap a whole batch. That's the performance story.
  • Plenty of people don't need this at all. As the KB's depth docs keep pointing out, the ecosystem's default answer to "get 3D out of an image" is a learned monocular model that needs no rig and no calibration. This node is for when you have the hardware and want geometry you can trust.
Categoryimage/CV/low-level/omnidir

Inputs (8)

NameTypeDefaultDescription
KNPARRAY,IMAGE,MASK - - - 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.
DNPARRAY,IMAGE,MASK - - - 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.
xiNPARRAY,IMAGE,MASK - - - 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.
RNPARRAY,IMAGE,MASK - - - 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.
PNPARRAY,IMAGE,MASK - - - 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.
sizeCV_TUPLE0,0One 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.
m1typeINT0-2147483648–2147483647 - - -
flagsINT0-2147483648–2147483647 - - -

Outputs (2)

NameTypeDescription
nparray_0NPARRAY—
nparray_1NPARRAY—