mrcal 2.2 release notes

New in mrcal 2.2

This is a mostly-maintenance release. I'm using these tools myself a lot, and I'm developing some exciting (and not-yet-ready) new features. In the process, I'm cleaning things up and making infrastructural improvements. This release is a collection of many such improvements: there are a lot of medium-size fixes, but nothing huge. Exciting new features in future releases.

In the nearest term, I need some sort of "recipes" documentation section and an extension of the tour of mrcal with better calibration data. This is coming. Soon.

Stereo processing


The mrcal-convert-lensmodel tool improvements

This tool received lots of usability and robustment improvements:

  • The --viz output plot can be controlled and written to disk by passing --set, --unset, --hardcopy, etc. Same as with the mrcal-show-projection-diff tool and others.
  • The output model is written to a file on disk instead of to stdout. This is incompatible with previously behavior, but is much nicer. We're now less likely to produce an unwanted spew onto the console
  • --radius and --where work even without --sampled: they cut down on the observations being fitted
  • We can pass multiple values in --distance. This is critically important for --sampled solves: using a near and far distance together stabilizes the fitted translation. Prior to this --sampled solves often ended up unusable due to an aphysical translation.
  • --distance is used even without --sampled: this controls the diff visualization produced with --viz
  • Non-sampled solves are now run using incremental stages, just like in the mrcal-calibrate-cameras tool. This makes the non-sampled operation of this tool much more robust
  • Non-sampled solves can be limited to just the camera in question by passing --monotonic


  • Most functions in the Python API now accept non-essential arguments as keywords only. Most common usages should remain functional, but code that used too many positional arguments in calls will need to be ported. This will increase the readability of that code, and this change makes it easier to maintain API compatibility in the future
  • The variable convention used for the optimization state changed to \(\vec b\) from \(\vec p\). Previously, \(\vec p\) was used to denote both optimization state and points in space, with this ambiguity being clear from context. However, too many times we'd see a situation where this wasn't clear from context. Renaming this clears up the ambiguity. This isn't a functional change, but affects lots of documentation, comments and variable names.
  • Added mrcal.load_image() and mrcal.save_image() functions to both the Python and C APIs. These aren't special in any way, but are convenient, and allow us to avoid OpenCV, which is slow and massive. Requires libfreeimage
  • The mrcal.mrcal-triangulate() tool now has a --clahe option to apply equalization to the input images prior to processing
  • The mrcal.ref_calibration_object() function can accept different spacings in the horizontal and vertical directions
  • The mrcal.ref_calibration_object() function can broadcast over object_spacing and calobject_warp
  • The code can be cross-built, if invoked from the Debian build tools (DEB_HOST_MULTIARCH and the compiler and linker environment variables set)
  • The mrcal.compute_chessboard_corners() function API was cleaned up. Many arguments have different names, and most of them are only accepted as keywords. The weight_column_kind argument must be one of 'level' or 'weight' or None.
  • The mrcal-to-cameramodel tool was renamed to mrcal-from-cahvor to make it easier to support future format converters.
  • The mrcal-calibrate-cameras tool now reports its "RMS error" as the RMS error of the measurement vector. Each pixel observation produces 2 measurement values: the error in \(x\) and \(y\). Prior to this release I reported the RMS error treating such a pair as one value: \(\sqrt{\frac{\left\Vert \vec x \right\Vert^2}{\frac{N_\mathrm{measurement}}{2}}}\). This was in conflict with other parts of the code, so now I report this as two separate values: \(\sqrt{\frac{\left\Vert \vec x \right\Vert^2}{N_\mathrm{measurement}}}\). So now the reported RMS error is just \(\mathrm{Var} \left( \vec x \right)\)
  • mrcal-calibrate-cameras and mrcal.seed_stereographic() can accept multiple estimates for focal length: one estimate per camera. Useful in seeding calibration problems containing multiple disparate cameras
  • The mrcal-show-geometry tool and the mrcal.show_geometry() function can now display the calibration objects observed by all cameras during a calibration (previous behavior) or they can dispaly the objects observed by just the given camera. The default behavior is unchanged.

Migration notes 2.1 -> 2.2

The vast majority of existing usage remains the same, but some updates described above will require a code change:

  • Most of the Python API functions now use keyword-only arguments for the non-essential arguments. Any calls that used too many positional arguments will need to be clarified with keywords
  • mrcal.pq_from_Rt() calls must be replaced with mrcal.qt_from_Rt(), and the caller must use the qt transform representation
  • mrcal.Rt_from_pq() calls must be replaced with mrcal.Rt_from_qt(), and the caller must use the qt transform representation
  • mrcal-stereo --show-geometry is now invoked as mrcal-stereo --viz geometry
  • The mrcal-to-cameramodel tool was renamed to mrcal-from-cahvor
  • A C header was renamed: basic_geometry.h -> basic-geometry.h, requiring an #include update
  • The mrcal.compute_chessboard_corners() function API was changed. If you're using this, please see the documentation
  • The mrcal-convert-lensmodel tool writes the output model to a file on disk, not to stdout as it has previously. New usage will need to be adjusted