mrcal 2.5.1 release notes
New in mrcal 2.5.1
This is yet another mostly-maintenance release. Most of the implementation of some new big features is written and committed, but it's still incomplete. The new stuff is there, but is lightly tested and documented. This will be completed eventually in mrcal 3.0:
- Cross-reprojection uncertainty, to be able to perform full calibrations with a
splined model and without a chessboard.
mrcal-show-projection-uncertainty --method cross-reprojection-rrp-Jfpis available today, and works in the usual moving-chessboard-stationary camera case. Fully boardless coming later. - More general view of uncertainty and diffs. I want to support extrinsics-only
and/or intrinsics computations-only in lots of scenarios. Uncertainty in point
solves is already available in some conditions, for instance if the points are
fixed. New
mrcal-show-stereo-pair-difftool reports an extrinsics+intrinsics diff between two calibrations of a stereo pair; experimentalanalyses/extrinsics-stability.pytool reports an extrinsics-only diff. These are in contrast to the intrinsics-only uncertainty and diffs in the existingmrcal-show-projection-diffandmrcal-show-projection-uncertaintytools. Some documentation in the uncertainty and differencing pages. - Implicit point solves, using the triangulation routines in the optimization
cost function. Should produce much more efficient structure-from-motion
solves. This is all the "triangulated-features" stuff. The cost function is
primarily built around
_mrcal_triangulated_error(). This is demoed intest/test-sfm-triangulated-points.py. And I've been using_mrcal_triangulated_error()in structure-from-motion implementations within other optimization routines.
Experimental tools
A number of new tools have been written that are very useful, but are still a bit rough, and need to be finished
- A new
analyses/mrcal-pick-featurestool is available to interactively pick matching features from a stereo pair's images, and to compute the relative extrinsics off them. This is very useful for a narrow application, and the optimal solver details are unclear, so this is not-yet released today. The assisted gui feature-picker and solver will be used for something eventually, but today it's there, waiting to be finished. - New validation tools
analyses/validate-input-noise.pyandanalyses/validate-uncertainty.pyandanalyses/validate-noncentral.pyare useful to check the various assumptions made by the mrcal processing. Used for sanity-checking a solve and for algorithm development. Documented somewhat here and here. - The mrcal library has now been used in multiple projects to align non-camera
sensors with great success:
- A geometry-only routine to align a set of cameras and a set of LIDARs is
available in the
camera-lidar-calibrationrepo. This aligns the geometry only and works for a LIDAR-only camera-less system as well. This tool assumes the camera intrinsics are perfect and it does uncertainty propagation of the output. It is decently well-tested and works well. Documentation and interfaces are still unideal, but improvements are welcome! - A routine to align a set of cameras and an IMU is available in
analyses/calibrate-camera-imu.py. This is also geometry-only and also trusts the intrinsics 100%. It's fairly simplistic, but highly usable and on-par with existing methods. If needed a full kalibr-style sensor-bias-fitting thing will probably be implemented eventually. Improvements welcome!
- A geometry-only routine to align a set of cameras and a set of LIDARs is
available in the
General fixes
- Thanks to Alan Everett, mrcal and the adjacent tooling now all build with macos. If anybody wants to see support for more OSs and distribution mechanisms (homebrew? fedora? pip?), and is willing to help with the implementation and the maintenance, please get in touch with me.
- Poseutils: more careful handling of rotations near singularities. Rotations by ~ 180deg in particular weren't implemented properly, and had bugs that are now fixed.
- Renamed "residuals" -> "measurements" to clarify the nomenclature. These are
similar except for scaling and the "measurements" may also contain
regularization.
residuals_point()->measurements_point()residuals_board()->measurements_board()show_residuals_....()functions now ask for a measurementxargument; the oldresidualsargument is still accepted for backwards compatibility
- Added
mrcal_traverse_sensor_links()in C andmrcal.traverse_sensor_links()in Python. These compute the best path through a graph of sensors, trying to maximize the common observations between each successive pair of sensors in the path. This is a part of the seeding algorithm, and is now exposed for other usages. The general min-heap implementation at the core of this computation is available inmrcal/heap.h mrcal-calibrate-camerasandmrcal.compute_chessboard_corners()have a higher minimum points-per-chessboard-observation threshold (newNpoint_observations_per_board_minkwarg in the function). We now throw out any images where a chessboard detection has fewer than2*min(gridn_width,gridn_height)points. This is irrelevant formrgingham, which produces all-or-nothing detections, but other detectors could produce barely-adequate detections that could cause problems previouslymrcal.compute_chessboard_corners()has newimage_path_prefixandimage_directorykwargs to provide more options for interpreting paths in the givencorners_cache_vnl. This is analogous to how other parts of mrcal work (for instance themrcal-show-residuals-board-observationtool).- The
mrcal-calibrate-camerasuse that function, and now has--image-path-prefixand--image-directory. Useful to make--imagersizeunnecessary and to have image overlays working with--explore. This is especially helpful if calibrating a system with different-resolution cameras. In that case--imagersizedoesn't work, and finding the images on disk is required - The
mrcal-convert-lensmodeltool has--allto write out all the models from a joint re-solve - Added new
mrcal.model_resolution__deg_pixel()function and themrcal-show-model-resolutiontool mrcal.show_distortion_off_pinhole_radial()works with all models, not just opencv ones- The image load/save functions no longer use libfreeimage, since that library
is unmaintained. I'm using libstb for image-reading and libpng and
libjpeg-turbo for image-writing. libstb can write images too, but there were
several limitations that made it necessary to use the dedicated libraries.
This means that currently I can write only
.pngand.jpgimages. This can be extended if needed. - The
mrcal-cull-cornerstool has--cull-rad-off-center-boardto throw out chessboard edges. Useful if we dont trust the chessboard shape - Added
mrcal.cameramodel.optimization_inputs_reset()andmrcal.cameramodel.valid_intrinsics_region_reset()to unset these fields in amrcal.cameramodel. - Added the
analyses/mrcal-convert-lensmodel-from-kalibr-fovtool to fit a Kalibr "fov" model into something that mrcal supports. This isn't general-enough or tested-enough to be fully distributed yet, so run it from the mrcal source tree if you need it - Added
mrcal_cameramodel_converter()"converter" function that can be used withO&conversions inPyArg_ParseTupleAndKeywords()calls. Can interpret either path strings ormrcal.cameramodelobjects asmrcal_cameramodel_VOID_tC structures. Useful for writing Python extension modules for C code that usesmrcal_cameramodel_VOID_t. Some fields in the
\begin{aligned} \mathrm{extrinsics\_rt\_fromref} & \to \mathrm{rt\_cam\_ref} \\ \mathrm{extrinsics\_Rt\_fromref} & \to \mathrm{Rt\_cam\_ref} \\ \mathrm{extrinsics\_rt\_toref} & \to \mathrm{rt\_ref\_cam} \\ \mathrm{extrinsics\_Rt\_toref} & \to \mathrm{Rt\_ref\_cam} \\ \mathrm{frames\_rt\_fromref} & \to \mathrm{rt\_frame\_ref} \\ \mathrm{frames\_Rt\_fromref} & \to \mathrm{Rt\_frame\_ref} \\ \mathrm{frames\_rt\_toref} & \to \mathrm{rt\_ref\_frame} \\ \mathrm{frames\_Rt\_toref} & \to \mathrm{Rt\_ref\_frame} \\ \end{aligned}mrcal.cameramodeltype and the saved.cameramodelfiles and theoptimization_inputsC and Python interfaces were renamed:This makes things more consistent. Compatibility logic is in place, so old code and data should keep working. New
.cameramodelfiles write both the new and old fields, so old tools can read the new files.- Transform composition functions have new arguments:
inverted0andinverted1, to make it easier to use inverted transforms. The C macrosmrcal_compose_Rt(),mrcal_compose_rt(),mrcal_compose_r()are unchanged, with new macros available to apply the inverses:...._inverted0(),...._inverted1(),...._inverted01(). The correspondingmrcal_compose_..._full()C functions have new arguments; this breaks the API and ABI. The Python functionsmrcal.compose_r()andmrcal.compose_rt()andmrcal.compose_R()have new kwargs with default values, so this API remains compatible.
Stereo
mrcal_rectified_system2()is a new flavor ofmrcal_rectified_system()to provide a newaz_edge_margin_degargument, to set the closest the rectified view is allowed to get to \(\mathrm{az}=\pm 90^\circ\). The legacy function still exists, defaulting toaz_edge_margin_deg=10.mrcal-stereocontrols this via--az-edge-margin-deg. Ifaz0_degis being auto-detected, it will be shifted to avoid looking along the baseline- Similarly the Python
mrcal.rectified_system()function now takes thisaz_edge_margin_degargument also - The C function
mrcal_rectified_system2()now supports pinhole rectification, something only the Pythonmrcal.rectified_system()call did previously. This is strictly worse than theLENSMODEL_LATLONrectification used by default, but is good to have for testing, since this is the traditional scheme used by every other tool. mrcal-stereo:--equalizationimplies--force-grayscalemrcal.stereo_range()has a better default for disparity_max to handle invalid disparities reliably in the common case where the disparity is a 16-bit signed integer
C API
- Added C implementations of Procrustes fits:
mrcal_align_procrustes_vectors_R01()andmrcal_align_procrustes_points_Rt01(). These are now the internal implementations of the Pythonmrcal.align_procrustes_vectors_R01()andmrcal.align_procrustes_points_Rt01()functions - Added
mrcal_R_aligned_to_vector()C function. This is now the internal implementation ofmrcal.R_aligned_to_vector() Added simple math operation functions to the C API:
double mrcal_point3_inner(const mrcal_point3_t a, const mrcal_point3_t b)double mrcal_point3_norm2(const mrcal_point3_t a)double mrcal_point3_mag (const mrcal_point3_t a)mrcal_point3_t mrcal_point3_add (const mrcal_point3_t a, const mrcal_point3_t b)mrcal_point3_t mrcal_point3_sub (const mrcal_point3_t a, const mrcal_point3_t b)mrcal_point3_t mrcal_point3_scale(const mrcal_point3_t a, const double s)mrcal_point3_t mrcal_point3_cross(const mrcal_point3_t a, const mrcal_point3_t b)
And similar for
mrcal_point2_t, except there's nomrcal_point2_cross()- Added simple point and pose printing utilities:
mrcal_point2_print(p)mrcal_point3_print(p)mrcal_Rt_print(Rt)mrcal_rt_print(rt)
mrcal_image_uint8_load()applies stretch equalization if given a 16-bit image. This is a reasonable default. If more specific processing is needed, callmrcal_image_uint16_load(). Applies tomrcal.load_image()also.- Added
mrcal_image_void_timage type for generic functions that aren't meant to interface with any particular image type. Themrcal_image_anytype_load()function now uses that type. - All headers have C++
extern "C"wrappers for direct#includein C++ projects - Renamed
mrcal_cameramodel_t->mrcal_cameramodel_VOID_tto clarify that the specific lensmodel type is unknown here. The legacy aliasmrcal_cameramodel_tis still available for backwards-compatibility - Added
mrcal_intrinsics_XXX_tstructures to represent camera intrinsics. These are exactly likemrcal_cameramodel_XXX_tbut without the extrinsics The C API can read models into a preallocated buffer intead of forcing allocation, as before. New functions:
bool mrcal_read_cameramodel_string_into(// out mrcal_cameramodel_VOID_t* model, // in,out int* Nintrinsics_max, // in const char* string, const int len); bool mrcal_read_cameramodel_file_into (// out mrcal_cameramodel_VOID_t* model, // in,out int* Nintrinsics_max, // in const char* filename);
Migration notes 2.4 -> 2.5
The C API got a few updates that require a few minor changes to user code:
mrcal_compose_rt_full()andmrcal_compose_Rt_full()C functions have two new arguments:inverted0,inverted1. Most callers use themrcal_..._compose()macros, so for them only the ABI has changed, and a rebuild is sufficient.mrcal_compose_rt_full()C function can returndt01_dr1anddt01_dt0. Most callers use themrcal_..._compose()macros, so for them only the ABI has changed, and a rebuild is sufficient.- The C types
mrcal_cameramodel_XXX_tno longer have a generic membermrcal_cameramodel_t m. If you need a generic alias ofmrcal_cameramodel_XXX_t* modelyou now need to(mrcal_cameramodel_VOID_t*)modelinstead of&model->m All the headers renamed to remove
mrcal-from their name. Everything is intended to be included as#include <mrcal/thing.h>
So the
mrcal-in the name was superfluous. If you were including either of:mrcal-image.hmrcal-types.h
You should now include:
mrcal/image.hmrcal/types.h
- The
mrcal_image_anytype_load()function uses themrcal_image_void_timage type. The semantics are identical, but older code might need a cast or a type change to build.
And some nomenclature changed: some fields in the mrcal.cameramodel type and
the saved .cameramodel files and the optimization_inputs C and Python
interfaces were renamed. The old naming mostly still works, but transitioning to
the new naming would be a good thing to do: