GeoCalib: single-image camera calibration with geometric optimization
GeoCalib: Learning Single-image Calibration with Geometric Optimization (ECCV 2024)
At a glance
- What is it?
- GeoCalib estimates camera intrinsics and gravity from one image by combining a learned model with a differentiable geometric solver. Here is how the Python package installs, what the camera models actually cover, and where it falls short.
- Who is it for?
- Adopt GeoCalib if you have images from one camera and no calibration target, or if you want to refine intrinsics you already partly know through the priors argument. Skip it if your images come from a camera with strong distortion and you need a model beyond pinhole, simple_radial, radial or simple_divisional, since the README states the principal point is fixed at the image center and is not optimized.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 46 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The calibration problem GeoCalib targets
Calibrating a camera normally means photographing a checkerboard or another target with known geometry, then solving for focal length and distortion from those correspondences. That works when you control the capture. It does not work when you are handed a photo and need to know what camera produced it. GeoCalib addresses that second case: a single image, no target, no second view. The README states that it estimates camera intrinsics and gravity direction from a single image only, and describes the result as more flexible and accurate than previous approaches because it combines geometric optimization with deep learning. The intended user is someone working with images of unknown provenance, or someone who wants a cheap initial estimate before a more careful calibration. The repository ships inference code, evaluation code, training code and the OpenPano training set, so it serves both people who just want predictions and people who want to retrain or benchmark.
How the learned model and the geometric solver interact
The architecture is a two-stage loop rather than a single regression. A network predicts intermediate quantities from the image, and a geometric optimizer fits camera parameters to those predictions. The README is explicit about which intermediates those are: the interactive demo can display an estimated horizon line, estimated up-vectors, an estimated latitude heatmap and a confidence heatmap for the up-vectors and latitudes. Those are the observations the solver consumes. Up-vectors and latitudes are geometric constraints on where the gravity direction and the camera orientation must lie; the confidence map tells the solver which pixels to trust. The optimizer then fits intrinsics and gravity so that the predicted constraints are consistent with a camera model. That is why the camera model is a runtime parameter rather than something baked into the weights: the network proposes, the geometry disposes. The practical consequence is that you can swap the camera model at inference time, and the README shows exactly that with camera_model="simple_radial" while loading the distorted weights.
Installing geocalib and running a first calibration
The inference package is called geocalib and the README states it needs only minimal dependencies and Python >= 3.9. Clone the repository and install it in editable mode. The alternative one-liner installs straight from GitHub without cloning first.
git clone https://github.com/cvg/GeoCalib.git && cd GeoCalib
python -m pip install -e .
# OR
python -m pip install -e "git+https://github.com/cvg/GeoCalib#egg=geocalib"With the package installed, the minimal example loads an image as a tensor in the range [0, 1] with shape [C, H, W], moves the model to a CUDA device when one is available, and calls calibrate. The result dictionary carries a camera entry and a gravity entry.
import torch
from geocalib import GeoCalib
device = "cuda" if torch.cuda.is_available() else "cpu"
model = GeoCalib().to(device)
image = model.load_image("path/to/image.jpg").to(device)
result = model.calibrate(image)
print("camera:", result["camera"])
print("gravity:", result["gravity"])If you would rather not install anything, the README links a Colab notebook and a Hugging Face demo. The repository also exposes a torch hub entry point, which loads the same model without a local clone.
model = torch.hub.load("cvg/GeoCalib", "GeoCalib", trust_repo=True)For a live check, the webcam demo opens a window with the camera feed and the calibration overlays. Passing --camera_id 0 selects the first local camera; without it, the demo asks for the IP address of a droidcam camera. Keys h, u, l, c, d, g and b toggle the horizon line, up-vectors, latitude heatmap, confidence heatmap, undistorted image, virtual grid and virtual box, while 1, 2 and 3 switch between pinhole, simple radial and simple divisional models.
python -m geocalib.interactive_demo --camera_id 0Camera models, priors and multi-image batches
Four camera models are documented. pinhole is the default and models focal lengths fx and fy with no distortion. simple_radial adds one polynomial distortion parameter k1 for weak distortion. radial adds k1 and k2 for stronger distortion. simple_divisional uses a single k1 for strong fisheye distortion, following Fitzgibbon's CVPR 2001 formulation. The default weights are trained for pinhole images, so distorted inputs need weights="distorted" plus a matching camera_model argument. The README also states plainly that the principal point is assumed to be at the center of the image and is not optimized. That is a real constraint, not a footnote: any camera whose optical axis is offset from the sensor center will be mis-modeled, and no amount of extra data fixes it through this API. The README notes that additional models can be implemented by extending the Camera object in geocalib/camera.py, so the limitation is structural rather than permanent. Partial calibration is supported through a priors dictionary: pass a focal length tensor when intrinsics are known, or a gravity direction tensor when gravity is known. For multiple images from one camera, calibrate accepts a list of tensors and shared_intrinsics=True solves for a single set. For rigid multi-camera rigs, camera_R_rig gives the rotation from the rig frame to each camera and the model estimates one shared gravity direction for the whole rig.
Where GeoCalib is the wrong tool
The centered principal point is the first hard boundary. If you are calibrating a camera whose sensor and lens are deliberately offset, GeoCalib will fit focal length and distortion around a principal point it refuses to move, and the residual error will be absorbed into the other parameters. The second boundary is the camera model list. If your lens is not well described by pinhole, a radial polynomial up to k2, or a single divisional parameter, the README offers no path except writing a new Camera subclass yourself. The third is the evaluation setup: the LaMAR evaluation command downloads roughly 400 MB into data/lamar2k, so anyone reproducing the reported numbers needs that disk space and a working dataset download. Finally, the release history is thin. There is a single release, v1.0, dated 2024-09-08. The last push to the repository was on 2026-08-16, so the code has moved since that release even though the version number has not. If you install from PyPI or from the v1.0 tag you are not getting whatever landed in the repository afterwards.
How GeoCalib differs from DeepCalib and AnyCalib
DeepCalib is the closest point of comparison, and the repository treats it as one: the evaluation section documents a command to evaluate DeepCalib trained on the OpenPano dataset, which means the maintainers ran both methods on the same data. The difference in approach is that DeepCalib is a direct regression model, while GeoCalib places a geometric optimizer on top of the network's intermediate predictions. That is the whole argument of the paper, and it explains why GeoCalib can accept priors and swap camera models at inference time: the solver is a separate component with its own inputs, not a fixed output layer. AnyCalib appears in the search data around this project, but the README does not mention it, so there is nothing here to compare against. The repository also ships siclib, the single-image calibration library that holds the evaluation and training code, installed separately with pip install -e siclib. If you only need predictions, geocalib is the smaller dependency; siclib is for reproducing or extending the benchmarks.
Licence, maintenance and what an upgrade costs
GeoCalib is Apache-2.0, declared both in the repository LICENSE file and in the pyproject.toml classifier. That is a permissive licence, and the pyproject metadata points the license field at the LICENSE file rather than restating terms, so the file itself is the reference. The package declares Python >= 3.9 and pulls its runtime dependencies from requirements.txt: torch, torchvision, opencv-python, kornia and matplotlib. There is a dev extra pinning black==23.9.1 and isort==5.12.0 alongside flake8, which tells you the formatting baseline the maintainers use. Because dependencies are dynamic and unpinned in requirements.txt, a fresh install resolves whatever torch and torchvision are current, and those are the packages most likely to break a working environment. The last push was on 2026-08-16, so the repository has seen changes after the v1.0 release on 2024-09-08. There is no documented upgrade procedure in the README, and no changelog entry beyond the initial release, so the practical upgrade path is to pin the commit you installed and diff before moving.
Editorial conclusion
Adopt GeoCalib if you have images from one camera and no calibration target, or if you want to refine intrinsics you already partly know through the priors argument. Skip it if your images come from a camera with strong distortion and you need a model beyond pinhole, simple_radial, radial or simple_divisional, since the README states the principal point is fixed at the image center and is not optimized. Before committing, verify the camera model you need is supported and check that the 2024-09-08 v1.0 release is the version you are installing.
Frequently asked questions
What is GeoCalib and what does it estimate?
GeoCalib is an algorithm for single-image calibration: it estimates the camera intrinsics and gravity direction from a single image by combining geometric optimization with deep learning. The repository hosts the inference, evaluation and training code plus the OpenPano training set.
How do I install GeoCalib?
The README gives two options: clone the repository and run python -m pip install -e ., or install directly from GitHub with python -m pip install -e "git+https://github.com/cvg/GeoCalib#egg=geocalib". The inference package requires Python >= 3.9.
Which camera models does GeoCalib support?
Four are documented: pinhole (the default, focal lengths only), simple_radial (one distortion parameter k1), radial (k1 and k2), and simple_divisional (a single k1 for strong fisheye distortion). Distorted images need weights="distorted" and a matching camera_model argument.
Can I use GeoCalib when the focal length is already known?
Yes. The README documents a priors dictionary: pass priors={"focal": focal_length_tensor} when intrinsics are known, or priors={"gravity": gravity_direction_tensor} when gravity is known.
What is a geometric camera model and how is it used in computer vision?
In GeoCalib the camera model is a runtime parameter that the geometric optimizer fits against the network's predicted up-vectors and latitudes. The README lists pinhole, simple_radial, radial and simple_divisional, and notes that the principal point is assumed to be at the image center and is not optimized.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/cvg-geocalib)