Camera Calibration
Guess a camera's roll, pitch, and FOV from one image (no checkerboard required)
- image
- roll
- pitch
- vfov
- focal_length
- focal_length_mm
- calibration_info
The name is a lie, and that's fine. You're not calibrating a lens rig or waving a checkerboard - this node answers one dumb-sounding question: how is the camera tilted, and how wide is it looking? If that sounds trivial, remember the whole point is to hand those three numbers to its sibling, Perspective to Panorama, so a flat video frame can be re-projected into a proper 360° equirectangular image. Get the roll, pitch, and vertical field of view even slightly wrong and your panorama comes out tilted, off-center, or warped at the edges. This node does that measurement for you, automatically, from a single frame.
It's part of ComfyUI-PanoTools, an open re-implementation of the perspective-to-panorama method hybridworkflow posted to r/StableDiffusion in late 2025 - the one that became the community's standard first step for turning ordinary footage into VR-ready panoramas before a model outpaints the missing sky and ground.
How it works
Four calibration methods, all in one node:
- geocalib_auto - the one you should use first. It's a deep network called GeoCalib (ECCV 2024, ETH Zurich) that predicts gravity direction and field of view straight from the image content. No horizon needed, works on any scene. The code is vendored inside the pack, and the model weights (~110–220 MB) download automatically from GitHub on your first run.
- horizon_detection - classic computer vision: edge detection plus a Hough transform to find the horizon line in a region of interest. Roll comes from the line's slope, pitch from where it sits vertically. Great for ocean/sky shots, but the README is candid that this path is "mostly untested."
- vertical_lines - the architectural twin. Finds near-vertical lines (building edges) via Hough and uses their deviation from true vertical to estimate roll.
- manual - skips all the guessing and just passes through your
manual_roll,manual_pitch, andmanual_vfovvalues, which the output wiring then feeds downstream. Handy when you know the lens.
For anything that isn't a clean horizon or a block of buildings, geocalib_auto wins. The geometric methods are the "I want zero extra downloads" fallback, not the recommendation.
Inputs and outputs that matter
You only need image and calibration_method. Everything else is optional, and only manual_roll, manual_pitch, and manual_vfov are used unless you pick manual. horizon_roi_top/horizon_roi_bottom (0–1 fractions of image height) narrow where the horizon search happens; min_line_length and angle_threshold tune how picky vertical-line detection is. Most people never touch them.
The outputs are the payoff, and they wire straight into Perspective to Panorama:
roll,pitch,vfov- the three numbers you care about.focal_length(in pixels) andfocal_length_mm(35mm-equivalent) - informative extras; Perspective to Panorama can take the pixel focal length directly.calibration_info- a text string describing what the node detected, handy for debugging.
Typical workflow: load your video, pull frame 0, calibrate it, and pipe the outputs into Perspective to Panorama while it processes the full clip. One calibration for the whole video - no need to run it per frame.
Installation
cd ComfyUI/custom_nodes
git clone https://github.com/9nate-drake/ComfyUI-PanoTools.git
cd ComfyUI-PanoTools
pip install -r requirements.txt
Then restart ComfyUI and look under Add Node > PanoTools. The requirements are light - opencv-python, kornia, matplotlib - and numpy/torch/torchvision are already in any ComfyUI install. ComfyUI Manager support is listed as "coming soon" in the README, so the git route is the reliable one for now.
Common issues
- "ERROR: GeoCalib failed to load" - a dependency is missing or the first-run weight download (from GitHub, so it needs network access) didn't finish. Run
pip install -r requirements.txt, restart, retry. - "WARNING: No horizon/lines detected" - the geometric method came up empty. That's not a bug in your setup; just switch to
geocalib_auto, or widen the ROI / lowermin_line_length. - Calibration seems off - GeoCalib's estimate is good but not gospel, especially on heavily cropped or very unusual frames. Nudge
roll/pitch/vfovmanually in Perspective to Panorama afterward; that's the "manual control" the pack advertises.
The honest take: this is a one-trick node, but it's the trick that makes the whole pack work. Feed it the first frame, and it saves you from the slow, frustrating process of eyeballing roll and pitch until the panorama stops looking drunk.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | Single image or first frame to analyze for camera calibration parameters | |
| calibration_method | COMBO | Calibration method: 'geocalib_auto' (AI-based, works for all scenes - recommended), 'horizon_detection' (for outdoor/ocean scenes), 'vertical_lines' (for architecture/buildings), or 'manual' (specify values manually) | |
| manual_rollopt | FLOAT | 0.00-180–180 | Camera roll (rotation around viewing axis) in degrees. Positive = clockwise tilt. Only used when method is 'manual'. |
| manual_pitchopt | FLOAT | 0.00-180–180 | Camera pitch (up/down angle) in degrees. Positive = tilted up, negative = tilted down. Only used when method is 'manual'. |
| manual_vfovopt | FLOAT | 60.010–170 | Vertical field of view in degrees. Typical values: 40-60° (standard lens), 70-90° (wide angle), 10-30° (telephoto). Used when method is 'manual' or as fallback for geometric methods. |
| horizon_roi_topopt | FLOAT | 0.300–1 | Top boundary of search region for horizon (0.0 = image top, 1.0 = image bottom). Adjust to focus on area where horizon is expected. Only for 'horizon_detection' method. |
| horizon_roi_bottomopt | FLOAT | 0.700–1 | Bottom boundary of search region for horizon (0.0 = image top, 1.0 = image bottom). Should be below the horizon line. Only for 'horizon_detection' method. |
| min_line_lengthopt | INT | 10020–500 | Minimum length (in pixels) for lines to be detected. Increase for images with noise or small details. Only for 'vertical_lines' method. |
| angle_thresholdopt | FLOAT | 5.00.1–15 | Maximum angle deviation from perfectly vertical (in degrees). Lower = stricter vertical alignment. Increase if camera has significant roll. Only for 'vertical_lines' method. |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| roll | FLOAT | Camera roll rotation in degrees |
| pitch | FLOAT | Camera pitch rotation in degrees |
| vfov | FLOAT | Vertical field of view in degrees |
| focal_length | FLOAT | Focal length in pixels (used for projection calculations) |
| focal_length_mm | FLOAT | 35mm equivalent focal length (e.g., 24mm wide, 50mm standard, 85mm portrait). Useful for comparing with real camera lenses. |
| calibration_info | STRING | Diagnostic information about the calibration method used and detected parameters |