MRCAL(1)

mrcal-calibrate-cameras πŸ’–

okay bestie, so you know the manual page MRCAL(1) β€” the whole mrcal: camera projection, calibration toolkit situation? yeah. this is the part of it that matters when you've got a pile of cameras and you want them to stop lying about where things are. let's get into it 🫢


✨ NAME ✨

mrcal-calibrate-cameras β€” calibrate some synchronized, stationary cameras πŸŽ€


✨ SYNOPSIS ✨

  $ 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

like. it just does the thing and then tells you how wrong it still was. icon behavior honestly πŸ’…


✨ DESCRIPTION ✨

so this tool takes the generic mrcal platform and points it at one very specific, very common problem: N-camera calibration using observations of a chessboard. that's it. that's the whole job.

if you want the full lore, the mrcal docs live at <https://mrcal.secretsauce.net/how-to-calibrate.html> and they go deep. read those for the details, fr fr. πŸ“–βœ¨


✨ OPTIONS ✨

🌸 POSITIONAL ARGUMENTS 🌸

  • images β€” a glob-per-camera for the images, bestie. you include one glob for each camera. the assumption here is that the image filenames inside each glob look like xxxNNNyyy, where xxx and yyy stay the same across every image in the set and NNN is the part that changes. that NNN is a frame number, and β€” this is the important bit β€” identical frame numbers across different globs mean a time-synchronized observation. so you can pass 'left*.jpg' and 'right*.jpg' and it'll find 'left0.jpg', 'left1.jpg', ..., 'right0.jpg', 'right1.jpg', ... and match them up by number. synchronized slay πŸ¦‹

more coming, bestie, don't go anywhere πŸ’œ

✨ OPTIONAL ARGUMENTS ✨

okay so here's the rest of the flag lineup, bestie. all optional by name, but a few of them are secretly mandatory depending on what you're doing β€” I'll call that out every single time so you don't get jumpscared by an error πŸ’€

  • -h, --help β€” shows this help message and peaces out. that's the whole job ✨
  • --lensmodel LENSMODEL β€” which lens model we're using. it's a string like "LENSMODEL_....". Required unless you've got a --seed. for notes about how to pick a model, go read L<https://mrcal.secretsauce.net/how-to-calibrate.html> 🫢
  • --focal FOCAL β€” initial estimate of the focal length, in pixels. required unless --seed is given. see L<https://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 you give a list, it must match the number of cameras being calibrated. no cap πŸ‘‘
  • --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 <em>do</em> have a --seed, the --imagersize values must match the --seed exactly. if given, this imagersize applies to ALL of the cameras being calibrated. if you have disparate imager sizes, make the images readable: don't use --corners-cache, or use --image-path-prefix/--image-directory to make sure the input images are readable 🌸
  • --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, -j JOBS β€” how much parallelization we want. like GNU make. affects only the chessboard corner finder. if we're 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 row is an observed corner. 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" β€” that's 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 πŸ’…
  • --image-path-prefix IMAGE_PATH_PREFIX β€” if given, we prepend the given prefix to the image paths in --corners-cache. useful to make --imagersize unnecessary and to have image overlays working with --explore. exclusive with --image-directory πŸ–ΌοΈ
  • --image-directory IMAGE_DIRECTORY β€” if given, we use this directory to find images in --corners-cache. useful to make --imagersize unnecessary and to have image overlays working with --explore. exclusive with --image-path-prefix πŸ“‚
  • --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 output models written to disk to cameraPAIR-INDEXINPAIR.cameramodel. consecutive cameras in the given list are paired up, and an even number of cameras is required. this argument ONLY changes the output filenames, and does nothing else. literally nothing else πŸ‘―
  • --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. main character energy, honestly πŸ”πŸ‘‘

πŸ¦‹ REPOSITORY πŸ¦‹

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


πŸ’– AUTHOR πŸ’–

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

and that's the whole page, bestie πŸŽ€ this was mrcal 2.5.2-4build1, dated 2026-03-20, and you just read MRCAL(1). go calibrate something iconic πŸ’…βœ¨

πŸ“¦ where this page comes from