Views
No views yet

1git clone https://github.com/javrtg/AnyCalib.git && cd AnyCalib
2pip install -e .xformers can also be installed for better efficiency by running the following instead of pip install -e .:pip install -e .[eff]1import numpy as np
2import torch
3from PIL import Image # the library of choice to load images
4
5from anycalib import AnyCalib
6
7
8dev = torch.device("cuda")
9
10# load input image and convert it to a (3, H, W) tensor with RGB values in [0, 1]
11image = np.array(Image.open("path/to/image.jpg").convert("RGB"))
12image = torch.tensor(image, dtype=torch.float32, device=dev).permute(2, 0, 1) / 255
13
14# instantiate AnyCalib according to the desired model_id. Options:
15# "anycalib_pinhole": model trained with *only* perspective (pinhole) images,
16# "anycalib_gen": trained with perspective, distorted and strongly distorted images,
17# "anycalib_dist": trained with distorted and strongly distorted images,
18# "anycalib_edit": Trained on edited (stretched and cropped) perspective images.
19model = AnyCalib(model_id="anycalib_pinhole").to(dev)
20
21# Alternatively, the weights can be loaded from the huggingface hub as follows:
22# NOTE: huggingface_hub (https://pypi.org/project/huggingface-hub/) needs to be installed
23# model = AnyCalib().from_pretrained(model_id=<model_id>).to(dev)
24
25# predict according to the desired camera model. Implemented camera models are detailed further below.
26output = model.predict(image, cam_id="pinhole")
27# output is a dictionary with the following key-value pairs:
28# {
29# "intrinsics": (D,) tensor with the estimated intrinsics for the selected camera model,
30# "fov_field": (N, 2) tensor with the regressed FoV field by the network. N≈320^2 (resolution close to the one seen during training),
31# "tangent_coords": alias for "fov_field",
32# "rays": (N, 3) tensor with the corresponding (via the exponential map) ray directions in the camera frame (x right, y down, z forward),
33# "pred_size": (H, W) tuple with the image size used by the network. It can be used e.g. for resizing the FoV/ray fields to the original image size.
34# }model_id, if not already downloaded, will be automatically downloaded to the:torch.hub.get_dir()) if AnyCalib(model_id=<model_id>) is used, orAnyCalib().from_pretrained(model_id=<model_id>) is used.AnyCalib:help(AnyCalib) 1 """AnyCalib class.
2
3 Args for instantiation:
4 model_id: one of {'anycalib_pinhole', 'anycalib_gen', 'anycalib_dist', 'anycalib_edit'}.
5 Each model differes in the type of images they seen during training:
6 * 'anycalib_pinhole': Perspective (pinhole) images,
7 * 'anycalib_gen': General images, including perspective, distorted and
8 strongly distorted images, and
9 * 'anycalib_dist': Distorted images using the Brown-Conrady camera model
10 and strongly distorted images, using the EUCM camera model,
11 * 'anycalib_edit': Trained on edited (stretched and cropped) perspective
12 images.
13 Default: 'anycalib_pinhole'.
14 nonlin_opt_method: nonlinear optimization method: 'gauss_newton' or 'lev_mar'.
15 Default: 'gauss_newton'
16 nonlin_opt_conf: nonlinear optimization configuration.
17 This config can be used to control the number of iterations and the space
18 where the residuals are minimized. See the classes `GaussNewtonCalib` or
19 `LevMarCalib` under anycalib/optim for details. Default: None.
20 init_with_sac: use RANSAC instead of nonminimal fit for initializating the
21 intrinsics. Default: False.
22 fallback_to_sac: use RANSAC if nonminimal fit fails. Default: True.
23 ransac_conf: RANSAC configuration. This config can be used to control e.g. the
24 inlier threshold or the number of minimal samples to try. See the class
25 `RANSAC` in anycalib/ransac.py for details. Default: None.
26 rm_borders: border size of the dense FoV fields to ignore during fitting.
27 Default: 0.
28 sample_size: approximate number of 2D-3D correspondences to use for fitting the
29 intrinsics. Negative value -> no subsampling. Default: -1.
30 """1images = ... # (B, 3, H, W)
2# NOTE: if cam_ids is a list, then len(cam_ids) must be equal to B
3cam_ids = ["pinhole", "radial:1", "kb:4"] # different camera models for each image
4cam_ids = "pinhole" # same camera model across images
5output = model.predict(images, cam_id=cam_ids)
6# corresponding batched output dictionary:
7# {
8# "intrinsics": List[(D_i,) tensors] for each camera model "i",
9# "fov_field": (B, N, 2) tensor,
10# "tangent_coords": alias for "fov_field",
11# "rays": (B, N, 3) tensor,
12# "pred_size": (H, W).
13# }cam_id represents the camera model identifier(s) that can be used in the predict method. D corresponds to the number of intrinsics of the camera model. It determines the length of each intrinsics tensor in the output dictionary.cam_id | Description | D | Intrinsics |
|---|---|---|---|
pinhole | Pinhole camera model | 4 | $f_x,~f_y,~c_x,~c_y$ |
simple_pinhole | pinhole with one focal length | 3 | $f,~c_x,~c_y$ |
radial:k | Radial (Brown-Conrady) [1] camera model with k $\in$ [1, 4] distortion coefficients | 4+k | $f_x,~f_y,~c_x,~c_y$ $k_1[,~k_2[,~k_3[,~k_4]]]$ |
simple_radial:k | radial:k with one focal length | 3+k | $f,~c_x,~c_y$ $k_1[,~k_2[,~k_3[,~k_4]]]$ |
kb:k | Kannala-Brandt [2] camera model with k $\in$ [1, 4] distortion coefficients | 4+k | $f_x,~f_y,~c_x,~c_y$ $k_1[,~k_2[,~k_3[,~k_4]]]$ |
simple_kb:k | kb:k with one focal length | 3+k | $f,~c_x,~c_y$ $k_1[,~k_2[,~k_3[,~k_4]]]$ |
ucm | Unified Camera Model [3] | 5 | $f_x,~f_y,~c_x,~c_y$ $k$ |
simple_ucm | ucm with one focal length | 4 | $f,~c_x,~c_y$ $k$ |
eucm | Enhanced Unified Camera Model [4] | 6 | $f_x,~f_y,~c_x,~c_y$ $k_1,~k_2$ |
simple_eucm | eucm with one focal length | 5 | $f,~c_x,~c_y$ $k_1,~k_2$ |
division:k | Division camera model [5] with k $\in$ [1, 4] distortion coefficients | 4+k | $f_x,~f_y,~c_x,~c_y$ $k_1[,~k_2[,~k_3[,~k_4]]]$ |
simple_division:k | division:k with one focal length | 3+k | $f,~c_x,~c_y$ $k_1[,~k_2[,~k_3[,~k_4]]]$ |
siclib library from GeoCalib, which can be installed as:pip install -e sicliboutputs/results/.data/lamar2k which will take around 400 MB of disk space.python -m siclib.eval.lamar2k_rays --conf anycalib_pretrained --tag anycalib_p --overwritepython -m siclib.eval.lamar2k_rays --conf anycalib_pretrained --tag anycalib_g --overwrite model.model_id=anycalib_gendata/megadepth2k which will take around 2 GB of disk space.python -m siclib.eval.megadepth2k_rays --conf anycalib_pretrained --tag anycalib_p --overwritepython -m siclib.eval.megadepth2k_rays --conf anycalib_pretrained --tag anycalib_g --overwrite model.model_id=anycalib_gendata/tartanair which will take around 1.7 GB of disk space.python -m siclib.eval.tartanair_rays --conf anycalib_pretrained --tag anycalib_p --overwritepython -m siclib.eval.tartanair_rays --conf anycalib_pretrained --tag anycalib_g --overwrite model.model_id=anycalib_gendata/stanford2d3d which will take around 844 MB of disk space.python -m siclib.eval.stanford2d3d_rays --conf anycalib_pretrained --tag anycalib_p --overwritepython -m siclib.eval.stanford2d3d_rays --conf anycalib_pretrained --tag anycalib_g --overwrite model.model_id=anycalib_gendata/megadepth2k-radial which will take around 1.4 GB of disk space.python -m siclib.eval.megadepth2k_radial_rays --conf anycalib_pretrained --tag anycalib_g --overwrite model.model_id=anycalib_gendata/monovo2k which will take around 445 MB of disk space.python -m siclib.eval.monovo2k_rays --conf anycalib_pretrained --tag anycalib_d --overwrite model.model_id=anycalib_dist data.cam_id=ucmpython -m siclib.eval.monovo2k_rays --conf anycalib_pretrained --tag anycalib_g --overwrite model.model_id=anycalib_gen data.cam_id=ucmdata/scannetpp2k which will take around 760 MB of disk space.python -m siclib.eval.scannetpp2k_rays --conf anycalib_pretrained --tag anycalib_d --overwrite model.model_id=anycalib_dist scannetpp_root=<path_to_scannetpp>python -m siclib.eval.scannetpp2k_rays --conf anycalib_pretrained --tag anycalib_g --overwrite model.model_id=anycalib_gen scannetpp_root=<path_to_scannetpp>data/lamar2k_edit which will take around 224 MB of disk space.python -m siclib.eval.lamar2k_rays --conf anycalib_pretrained --tag anycalib_e --overwrite model.model_id=anycalib_edit eval.eval_on_edit=Truedata/tartanair_edit which will take around 488 MB of disk space.python -m siclib.eval.tartanair_rays --conf anycalib_pretrained --tag anycalib_e --overwrite model.model_id=anycalib_edit eval.eval_on_edit=Truedata/stanford2d3d_edit which will take around 420 MB of disk space.python -m siclib.eval.stanford2d3d_rays --conf anycalib_pretrained --tag anycalib_e --overwrite model.model_id=anycalib_edit eval.eval_on_edit=Truedata/indoorDatasetCalibrated. Then, tonemap the HDR images using the following command:python -m siclib.datasets.utils.tonemapping --hdr_dir data/indoorDatasetCalibrated --out_dir data/laval-tonemapdata/openpano_v2/panoramas/{split}, execute:python -m siclib.datasets.utils.download_openpano --name openpano_v2 --laval_dir data/laval-tonemapdevice=cuda as this significantly speeds up the creation of the datasets, but if no GPU is available, the flag can be omitted.data/openpano_v2/openpano_v2):python -m siclib.datasets.create_dataset_from_pano --config-name openpano_v2 device=cudadata/openpano_v2/openpano_v2_gen):python -m siclib.datasets.create_dataset_from_pano_rays --config-name openpano_v2_gen device=cudadata/openpano_v2/openpano_v2_radial):python -m siclib.datasets.create_dataset_from_pano_rays --config-name openpano_v2_radial device=cudadata/openpano_v2/openpano_v2_dist):python -m siclib.datasets.create_dataset_from_pano_rays --config-name openpano_v2_dist device=cudasiclib library from GeoCalib. Here we adapt their instructions to AnyCalib. siclib can be installed executing:pip install -e siclibopenpano_v2) has been downloaded and prepared, we can train AnyCalib with it.python -m siclib.train anycalib_op_p --conf anycalib --distributedoutputs/training/. The default batch size is 24 which requires at least 1 NVIDIA Tesla V100 GPU with 32GB of VRAM. If only one GPU is used, the flag --distributed can be omitted. Configurations are managed by Hydra and can be overwritten from the command line.python -m siclib.train anycalib_op_g --conf anycalib --distributed data.dataset_dir='data/openpano_v2/openpano_v2_gen'python -m siclib.train anycalib_op_d --conf anycalib --distributed data.dataset_dir='data/openpano_v2/openpano_v2_dist'python -m siclib.train anycalib_op_r --conf anycalib --distributed data.dataset_dir='data/openpano_v2/openpano_v2_radial'1python -m siclib.train anycalib_op_e --conf anycalib --distributed \
2data.dataset_dir='data/openpano_v2/openpano_v2' \
3data.im_geom_transform.change_pixel_ar=true \
4data.im_geom_transform.crop=0.5 python -m siclib.eval.<benchmark> --checkpoint <experiment_name> --tag <experiment_tag> --conf anycalibsiclib which we use as the base of our evaluation and training code. 1@InProceedings{tirado2025anycalib,
2 author={Javier Tirado-Gar{\'\i}n and Javier Civera},
3 title={{AnyCalib: On-Manifold Learning for Model-Agnostic Single-View Camera Calibration}},
4 booktitle={ICCV},
5 year={2025}
6}