mrcal-calibrate-cameras - Calibrate some synchronized, stationary cameras

```
$ mrcal-calibrate-cameras
--corners-cache corners.vnl
--lensmodel LENSMODEL_OPENCV8
--focal 1700 --object-spacing 0.01 --object-width-n 10
--outdir /tmp
--pairs
'left*.png' 'right*.png'
... lots of output as the solve runs ...
Done!
RMS reprojection error: 1.9 pixels
Worst reprojection error: 7.8 pixels
Noutliers: 319 out of 17100 total points: 1.9% of the data
Wrote /tmp/camera0-0.cameramodel
Wrote /tmp/camera0-1.cameramodel
```

This tool uses the generic mrcal platform to solve a common specific problem of N-camera calibration using observations of a chessboard. Please see the mrcal documentation at http://mrcal.secretsauce.net/how-to-calibrate.html for details.

```
images A glob-per-camera for the images. Include a glob for
each camera. It is assumed that the image filenames in
each glob are of of the form xxxNNNyyy where xxx and
yyy are common to all images in the set, and NNN
varies. This NNN is a frame number, and identical
frame numbers across different globs signify a time-
synchronized observation. I.e. you can pass
'left*.jpg' and 'right*.jpg' to find images
'left0.jpg', 'left1.jpg', ..., 'right0.jpg',
'right1.jpg', ...
```

```
-h, --help show this help message and exit
--lensmodel LENSMODEL
Which lens model we're using. This is a string
"LENSMODEL_....". Required unless we have a --seed.
See L<http://mrcal.secretsauce.net/how-to-calibrate.html>
for notes about how to select a model
--focal FOCAL Initial estimate of the focal length, in pixels.
Required unless --seed is given. See
L<http://mrcal.secretsauce.net/how-to-calibrate.html> for
notes about how to estimate a focal length. This is
either a single value to use for all the cameras, or a
comma-separated whitespace-less list of values to use
for each camera. If such a list is given, it must
match the number of cameras being calibrated
--imagersize IMAGERSIZE IMAGERSIZE
Size of the imager. This is only required if we pass
--corners-cache AND if none of the image files on disk
actually exist and if we don't have a --seed. If we do
have a --seed, the --imagersize values must match the
--seed exactly
--outdir OUTDIR Directory for the output camera models
--object-spacing OBJECT_SPACING
Width of each square in the calibration board, in
meters
--object-width-n OBJECT_WIDTH_N
How many points the calibration board has per
horizontal side. If omitted we default to 10
--object-height-n OBJECT_HEIGHT_N
How many points the calibration board has per vertical
side. If omitted, we assume a square object, setting
height=width
--seed SEED A comma-separated whitespace-less list of camera model
globs to use as a seed for the intrinsics and
extrinsics. The number of models must match the number
of cameras exactly. Expanded globs are sorted
alphanumerically. This is useful to bootstrap the
solve or to validate an existing set of models, or to
recompute just the extrinsics or just the intrinsics
of a solve. If omitted, we estimate a seed. Exclusive
with --focal. If given, --imagersize is omitted or it
must match EXACTLY with whatever is in the --seed
models
--jobs JOBS, -j JOBS How much parallelization we want. Like GNU make.
Affects only the chessboard corner finder. If we are
reading a cache file, this does nothing
--corners-cache CORNERS_CACHE
Path to the corner-finder results. If this file
exists, I use the corners in this file. If it doesn't
exist, I invoke mrgingham to compute the corners, and
I write the results to that path. And THEN I compute
the calibration off those observations. This file is a
vnlog with legend "# filename x y level" (exactly what
mrgingham reports). Each rown is an observed corners.
If an image had no observations, a single row
"filename - - -" is expected. The "level" is the
decimation level used in detecting that corner. "0"
means "full-resolution", "1" means "half-resolution",
"2" means "quarter-resolution" and so on. A level of
"-" or <0 means "skip this point". This is how
incomplete board observations are specified. A file
with a missing "level" column will fill in "0" for all
corners. A non-mrgingham grid detector may be used by
running that separately, and using this option to read
the output. A detector may output weights instead of a
decimation level in the last column. Pass --corners-
cache-has-weights to interpret the data in that way
--corners-cache-has-weights
By default the corners we read in --corners-cache have
columns "filename x y level". If the last column is a
weight instead of a decimation level, pass this
option. This is useful to support non-mrgingham
chessboard detectors
--pairs By default, we are calibrating a set of N independent
cameras. If we actually have a number of stereo pairs,
pass this argument. It changes the filename format of
the models written to disk (cameraPAIR-
INDEXINPAIR.cameramodel), and will report some
uncertainties about geometry inside each pair.
Consecutive cameras in the given list are paired up,
and an even number of cameras is required
--skip-regularization
By default we apply regularization in the solver in
the final optimization. This discourages obviously-
wrong solutions, but can introduce a bias. With this
option, regularization isn't applied
--skip-outlier-rejection
By default we throw out outliers. This option turns
that off
--skip-extrinsics-solve
Keep the seeded extrinsics, if given. Allowed only if
--seed
--skip-intrinsics-solve
Keep the seeded intrinsics, if given. Allowed only if
--seed
--skip-calobject-warp-solve
By default we assume the calibration target is
slightly deformed, and we compute this deformation. If
we want to assume that it is flat, pass this option.
--valid-intrinsics-region-parameters VALID_INTRINSICS_REGION_PARAMETERS VALID_INTRINSICS_REGION_PARAMETERS VALID_INTRINSICS_REGION_PARAMETERS VALID_INTRINSICS_REGION_PARAMETERS VALID_INTRINSICS_REGION_PARAMETERS
For convenience we compute a valid-intrinsics region
to describe the results of the calibration. This is a
watered-down interpretation of the projection
uncertainty that is easy to interpret. The logic
computing this is somewhat crude, and may go away in
the future. The defaults should be reasonable, so if
in doubt, leave these alone. The intent is to produce
usable output even if we're using a lean lens model
where the computed uncertainty is always overly
optimistic. We bin the observations into a grid, and
use mrcal._report_regional_statistics() to get the
residual statistics in each bin. We then contour the
bins to produce the valid-intrinsics region. If we're
using a rich lens model (LENSMODEL_SPLINED_...), then
we only look at the uncertainty, and not at the other
statistics. This argument takes 5 parameters. The
uncertainty is computed at a range
valid_intrinsics_region_parameters[4]. If <= 0, I look
out to infinity. The default is 0. A region is valid
only if the projection uncertainty <
valid_intrinsics_region_parameters[0] *
observed_pixel_uncertainty. The default is 1. A region
is valid only if the mean-abs-residuals is <
valid_intrinsics_region_parameters[1] (only for lean
models). The default is 0.5. A region is valid only if
the residuals stdev is <
valid_intrinsics_region_parameters[2] *
observed_pixel_uncertainty (only for lean models). The
default is 1.5. A region is valid only if it contains
at least valid_intrinsics_region_parameters[3]
observations (only for lean models). The default is 3.
--verbose-solver By default the final stage of the solver doesn't say
much. This option turns on verbosity to get lots of
diagnostics. This is generally not very useful to end
users
--explore After the solve open an interactive shell to examine
the solution
```

https://www.github.com/dkogan/mrcal

Dima Kogan, `<dima@secretsauce.net>`

Copyright (c) 2017-2023 California Institute of Technology ("Caltech"). U.S. Government sponsorship acknowledged. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License"); You may obtain a copy of the License at

`http://www.apache.org/licenses/LICENSE-2.0`