SLAM · Registration · Rust
mapr: a Rust library for 3D mapping and reconstruction
Reusable building blocks for turning depth measurements into a map: camera models, alignment, motion estimation, and surface reconstruction. Developed independently and used in the scanner reconstruction engine.
Geometry an application can use
Reconstruction work keeps returning to the same ideas: interpreting a depth image, aligning two observations, correcting a trajectory, and combining measurements into a surface. I built mapr so those operations could be used and tested independently.
The library is under active development. The scanner reconstruction engine provides a concrete application for its interfaces, while recorded datasets and controlled experiments let individual algorithms be examined in isolation.
Leaving scheduling with the application
Each tracking or reconstruction stage reads the model, computes without borrowing it, then writes its result back. A caller can run those phases directly or arrange them across threads.
The scanner's development engine uses that interface to run tracking and backend optimization separately, releasing the shared model lock during computation. The library owns no threads, locks, or channels; the application controls scheduling and buffering.
Making changes measurable
Benchmarks distinguish data preparation, a single registration iteration, and a complete solve. Recorded depth frames exercise missing pixels and surface boundaries; synthetic scenes provide controlled geometry. Resolution, search radius, and iteration budget are explicit inputs.
Surface evaluation reports distance distributions together with coverage, so a small error on a small surviving portion of a surface remains visible. Trajectory checks compare estimates with reference poses after a specified alignment. Regression tests and release-mode CI exercise these components as the APIs evolve.
A pose-graph example
Small motion errors accumulate as a camera moves. Recognizing a place it has visited before adds a constraint between distant parts of the path, allowing the solver to correct the drift.
In this controlled experiment, mapr reduces trajectory error from 217 mm to 14 mm. The camera path comes from a recorded benchmark; the odometry and loop-closure errors are deliberately injected to exercise the optimizer.
How the example is measured
The saved run uses 272 sampled poses from TUM RGB-D's freiburg1_room sequence and 664 loop-closure constraints. The optimizer takes six Levenberg–Marquardt iterations.
| Translation error · best-fit rigid alignment | Before | After |
|---|---|---|
| Root mean square | 216.9 mm | 14.3 mm |
The alignment removes a global rotation and translation before measuring position error. Both odometry and closure measurements contain Gaussian noise: translation standard deviations are 16 mm and 20 mm respectively; rotation standard deviations are 0.65° and 0.8°.
Closure selection spreads constraints across the path and adds links for keyframes left uncovered by thinning. In the recorded comparison, 664 distributed closures reached 14.3 mm error; a denser set of 1,482 reached 13.6 mm. Reducing the count further to 259 raised the error to 21.5 mm. The experiment makes that accuracy-versus-work tradeoff inspectable.
Numerical implementation
Pose-graph optimization carries measurement uncertainty between coordinate frames using the SE(3) adjoint. Bundle adjustment exploits sparse block structure through a Schur complement. Robust losses progressively tighten the treatment of outliers, and surface fusion weights measurements by their uncertainty.
CPU and GPU computation share Rust kernel source, with GPU kernels compiled to SPIR-V. These choices sit beneath the application-facing operations, where they can be benchmarked and changed without making the caller manage the solver's internals.