mrcal 2.5 release notes
New in mrcal 2.5
This is yet another mostly-maintenance release. Most of the implementation of some new big features is committed, but not yet completed and tested. These are thus lightly tested and documented, until they're done and finally appear in mrcal 3.0:
- Cross-reprojection uncertainty, to be able to perform full calibrations with a splined model and without a chessboard
- More general view of uncertainty. I want to support extrinsics and/or intrinsics uncertainty computation, in lots of scenarios
- 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
_mrcal_triangulated_error()function is the core part of the cost function, and this is already demoed intest/test-sfm-triangulated-points.py
And other than that, there are lots and lots of smaller fixes and improvements.
General fixes
- 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. The general min-heap implementation at the core of this computation is available inheap.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 are especially helpful if calibrating a system with different-resolution cameras. In that case--imagersizedoesn't work, and finding the images on disk is required - Added
analyses/validate-input-noise.pyandanalyses/validate-uncertainty.pyandanalyses/validate-noncentral.pytools. These are very useful to check the various assumptions made by the mrcal processing - 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} & \rightarrow & \mathrm{rt\_cam\_ref} \\ &\mathrm{extrinsics\_Rt\_fromref} & \rightarrow & \mathrm{Rt\_cam\_ref} \\ &\mathrm{extrinsics\_rt\_toref} & \rightarrow & \mathrm{rt\_ref\_cam} \\ &\mathrm{extrinsics\_Rt\_toref} & \rightarrow & \mathrm{Rt\_ref\_cam} \\ &\mathrm{frames\_rt\_fromref} & \rightarrow & \mathrm{rt\_frame\_ref} \\ &\mathrm{frames\_Rt\_fromref} & \rightarrow & \mathrm{Rt\_frame\_ref} \\ &\mathrm{frames\_rt\_toref} & \rightarrow & \mathrm{rt\_ref\_frame} \\ &\mathrm{frames\_Rt\_toref} & \rightarrow & \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_system()andmrcal.rectified_system()fail if the rectified camera looks near the direction of the baseline vector. Ifaz0_degis being auto-detected, it will be shifted to avoid looking along the baselinemrcal_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- Similarly the Python
mrcal.rectified_system()function now takes thisaz_edge_margin_degargument also 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
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.