Nodes/ComfyUI CV/CV Stereo Calibration From CSV
ComfyUI Node

CV Stereo Calibration From CSV

Already Have Calibration in a CSV? Skip the Chessboard Entirely

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
CV Stereo Calibration From CSV
    • K_left
    • dist_left
    • K_right
    • dist_right
    • R
    • T
    • found
    ◄csv_path_left—►
    ◄csv_path_right—►
    ◄image_name—►
    ◄image_width640►
    ◄image_height480►

    Most stereo pipelines on the internet assume you shot your own calibration board. Some sets - StereoGeo-CARLA being the pack's own example - ship the calibration as a per-image table instead: camera intrinsics and the rig's rotation/translation, one row per frame. This node reads those rows and hands you the same six arrays a chessboard calibration would, with no board, no waving, and no corner detection.

    That last part is the real pitch. Everything downstream - cv2_stereoRectify, then CV Stereo Disparity (SGBM) - cares about K_left, dist_left, K_right, dist_right, R, T. Where they came from is nobody's business. If a dataset gives you those numbers already, calibrating is wasted work.

    What it reads, and how it builds K

    Two CSVs, left and right, both keyed on image_name. The left file carries image_name, width, height, roll, pitch, vfov. The right file has the same columns plus the nine rotation entries R_00..R_22 and the translation t_0..t_2.

    The intrinsics are a plain pinhole built from the vertical FOV: fy = (height/2) / tan(vfov/2), with fx = fy and the principal point dropped at the image centre (cx = width/2, cy = height/2). Both distortion vectors come back as five zeros, because this model has no distortion term at all. In other words it trusts the source: if your CSVs came from a real physical camera with a fisheye-ish lens, the whole panorama of that distortion is invisible to the node, and rectification will be approximate.

    Note which width and height are actually used. The node has its own image_width / image_height widgets (640 × 480 by default) and it's those that set the principal point and the focal length. The width/height columns in the CSV are read as part of the row but don't drive the K. If your frames aren't 640 × 480, change the widgets - this is the one setting people forget.

    What you actually set

    csv_path_left and csv_path_right: a bare filename resolves against ComfyUI/input/, and absolute paths pass straight through. So left_images.csv and right_images.csv just work once they're in your input folder - the pack's 01_install_example_inputs.json copies exactly those two files, along with the matching stereo_scene_L_000000.png / ..._R_000000.png frames.

    image_name is the lookup key, e.g. 000000.png. It has to be present in both CSVs.

    image_width and image_height are your frame size. See above.

    Outputs are K_left, dist_left, K_right, dist_right, R, T - and found.

    Install

    ComfyUI Manager → search ComfyUI CV (publisher bmad4ever), or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/bmad4ever/comfyui_cv
    pip install "opencv-contrib-python-headless~=5.0.0.93"
    

    Restart after. Python ≥ 3.12 and a recent V3-API ComfyUI. Keep the contrib wheel - a plain opencv-python install overwrites the shared site-packages/cv2 and silently empties the contrib submodules. tools/repair_opencv_contrib.py --check diagnoses it.

    Where it bites

    found=false is the whole failure mode, and it's quiet: if image_name isn't in both CSVs you get found=false along with identity matrices and a zero translation. Wire that flag into your branching, because a zero baseline downstream produces a perfectly plausible-looking depth map with completely wrong scale - the worst kind of wrong.

    Second: the CSV's roll and pitch columns are in the format but the node only reads vfov to build K; there's no camera-tilt term in the intrinsics it produces. That's fine for these datasets, surprising if you assumed otherwise.

    And the general pack caveat applies here more than anywhere: bmad4ever's README says outright that the stereo workflows are tuned to StereoGeo-CARLA and aren't production-grade. This node is the reason that's worth saying out loud - it's built for a specific dataset's CSV dialect. If your columns are named differently, no amount of fiddling in the graph will fix it.

    Categoryimage/CV/features

    Inputs (5)

    NameTypeDefaultDescription
    csv_path_leftSTRINGLeft camera CSV. Bare filename resolves against ComfyUI/input/; absolute paths pass through.
    csv_path_rightSTRINGRight camera CSV. Bare filename resolves against ComfyUI/input/; absolute paths pass through.
    image_nameSTRINGImage filename to look up (e.g. '000000.png').
    image_widthINT640Image width in pixels (used for cx = width/2).
    image_heightINT480Image height in pixels (used for cy = height/2).

    Outputs (7)

    NameTypeDescription
    K_leftNPARRAY3x3 intrinsic matrix for the left camera.
    dist_leftNPARRAY1x5 distortion coefficients (zeros for pinhole).
    K_rightNPARRAY3x3 intrinsic matrix for the right camera.
    dist_rightNPARRAY1x5 distortion coefficients (zeros for pinhole).
    RNPARRAY3x3 rotation matrix from left to right camera.
    TNPARRAY3x1 translation vector from left to right camera.
    foundBOOLEAN—