Direct, modular georeferencing and drift-correction of point cloud maps
Project description
Installation
pip install flexcloud
Usage
All algorithm parameters are CLI flags with reasonable defaults.
Keyframe Interpolation
flexcloud-keyframe-interpolation [OPTIONS] <positions-path> <poses-path> [out-dir]
Required positional arguments:
positions-path Reference data (auto-detected, see table above)
poses-path SLAM trajectory in GLIM format
(one row per pose: stamp xpos ypos zpos xquat yquat zquat wquat)
out-dir Output directory for poses_keyframes.txt and positions_interpolated.txt
(defaults to the current directory)
Bag input (only used when positions-path is a ROS 2 bag):
--pos-topic TEXT Topic of NavSatFix or Odometry messages (required for bags)
-t,--target-frame TEXT TF frame to transform positions into (uses /tf and /tf_static
from the bag). Optional.
--origin LAT LON ALT Custom origin for NavSatFix → local Cartesian projection.
If omitted no projection is performed.
The reference-data source is given as a single positional argument positions-path; the reader is selected automatically:
positions-path is … |
Reader |
|---|---|
a .txt file |
text-file reader (one position per line) |
a directory without any .mcap / .db3 / .sqlite3 |
per-position txt-files reader |
a .mcap / .db3 / .sqlite3 file, or a directory containing one |
ROS 2 bag reader |
Reference-data file formats:
- single
.txtfile — one position per line, whitespace-separated:stamp x y z x_stddev y_stddev z_stddev. - directory of per-position
.txtfiles — filenames<sec>_<nanosec>.txt, file contentx y z x_stddev y_stddev z_stddev(timestamp parsed from the filename). - ROS 2 bag — supports
sensor_msgs/msg/NavSatFixornav_msgs/msg/Odometrymessages.
Notes on bag input:
NavSatFixmessages are projected to local Cartesian via GeographicLib; standard deviations are taken fromposition_covariance(diagonal).Odometrymessages usepose.posedirectly; standard deviations are taken frompose.covariance(diagonal).- When
--target-frameis set, all/tfand/tf_staticmessages from the bag are pre-loaded into a TF buffer. For each message its transform to the target frame is looked using the message timestamp.
Examples:
# single txt file
flexcloud-keyframe-interpolation positions.txt poses_GLIM.txt
# ROS 2 bag with Odometry
flexcloud-keyframe-interpolation /path/to/bag.mcap poses_GLIM.txt /path/to/out \
--pos-topic /odom --target-frame base_link
The keyframe-selection algorithm itself is unchanged:
- keyframes are selected from the LiDAR trajectory based on minimum longitudinal distance (
keyframe_delta_x) or minimum angular delta (keyframe_delta_angle). - For each LiDAR keyframe, the corresponding reference position is computed in one of two ways (controlled by
interpolate):- Closest neighbor — pick the reference frame with the smallest timestamp delta.
- Spline interpolation — fit a third-order spline through neighboring reference points (selected so that consecutive supports have a minimum euclidean distance of
interp_pos_delta_xyz) and evaluate at the keyframe timestamp.
stddev_thresholdis used to drop reference frames with high covariance.
The output is designed to be compatible with the georeferencing executable.
Georeferencing
Georeference a SLAM trajectory and (optionally) a corresponding point cloud map by
aligning it to a GNSS / reference trajectory using Umeyama and rubber-sheeting.
Usage: georeferencing [OPTIONS] positions-path poses-path
Required:
positions-path TEXT:FILE REQUIRED
Path to GNSS / reference trajectory
poses-path TEXT:FILE REQUIRED
Path to SLAM trajectory in GLIM format
Options:
-h,--help Print this help message and exit
Inputs:
--pcd TEXT Optional point cloud map to transform alongside the
trajectory
--config-file TEXT:FILE Optional YAML file with index-based fine-tuning arrays
(exclude_ind, shift_ind, shift_ind_dist, fake_ind,
fake_ind_dist, fake_ind_height)
Trajectory matching:
--control-points INT [10] Number of control points for rubber-sheeting
--stddev-threshold FLOAT [0.25]
Maximum stddev of reference points for automatic
control-point selection
--square-size FLOAT FLOAT FLOAT [0.1,0.1,10] ...
Padding of enclosing square around trajectories
[x y z] (fractions)
Origin:
--origin FLOAT FLOAT FLOAT ...
Custom ENU zero point [lat lon alt]
Evaluation:
--evaluation Print trajectory-matching statistics (RMSE, mean,
median, stddev of GNSS-vs-aligned and
GNSS-vs-rubber-sheeted deviations) to the terminal
and log per-segment, deviation-colored linestrings
to the rerun viewer.
Examples:
# cartesian reference, no point cloud, default parameters
flexcloud-georeferencing positions_interpolated.txt poses_keyframes.txt
# GPS reference, custom origin, transform a point cloud as well
flexcloud-georeferencing reference.txt poses_keyframes.txt \
--pcd map.pcd --origin 48.262 11.667 0.0
# supply index-based fine-tuning arrays via YAML
flexcloud-georeferencing reference.txt poses_keyframes.txt \
--config-file georeferencing.yaml
All parameters are CLI flags with sensible defaults; the only YAML config that remains is for the index-based fine-tuning arrays (exclude_ind, shift_ind, shift_ind_dist, fake_ind, fake_ind_dist, fake_ind_height) and is supplied via --config-file.
When --pcd is provided, the effective configuration is dumped next to the input point cloud as georeferencing.yaml (alongside the transformed georef_<pcd> output). The dumped file can be edited and fed back in via --config-file for reproducible runs.
Inspect results:
- results of the rubber-sheet transformation & the resulting, transformed point cloud map are visualized in Rerun.
- by default, the rerun viewer instance of the docker container is spawned. However, if you have problems with the viewer and your graphics drivers, you can also launch your viewer locally.
- adjust the parameters if the results are unsatisfying.
- see the table below for an explanation of the individual entities.
- pass
--evaluationto additionally print quantitative matching statistics to the terminal and visualize the per-segment GNSS deviation as a jet-colormap-shaded linestring (one for the Umeyama-aligned trajectory, one for the rubber-sheeted trajectory).
| Type | Description |
|---|---|
Trajectory |
reference trajectory |
Trajectory_SLAM |
original SLAM trajectory |
Trajectory_align |
SLAM trajectory aligned to reference with Umeyama transformation |
Trajectory_RS |
SLAM trajectory after rubber-sheet-transformation |
Trajectory_align_deviation |
aligned trajectory, per-segment colored by euclidean deviation from the reference (only with --evaluation) |
Trajectory_RS_deviation |
rubber-sheeted trajectory, per-segment colored by euclidean deviation from the reference (only with --evaluation) |
control_points |
control points used for rubber-sheeting |
tetrahedra |
triangulation used for rubber-sheeting |
pcd_map |
transformed point cloud map |
Content
This project enables the georeferencing of an existing point cloud map created only from inertial sensor data (e.g. LiDAR) by the use of the corresponding GNSS data. Leveraging the concept of rubber-sheeting from cartography, the tool is also able to account for accumulated errors during map creation and thus rectify the map.
Detailed documentation of the modules can be found below.
Trajectory Matching
- calculation of transformation based on GNSS/reference and SLAM trajectories
- trajectories do not have to be time-synchronized, although time-synchronization is required to select control points automatically for rubber-sheeting
1. Projection of Global Coordinates
- global coordinates may be projected into local coordinate system using ENU-coordinates from the GeographicLib
2. Keyframe Interpolation
- Selection of keyframes and interpolation of global position frames for map creation and manual optimization - Interpolation follows a third-order spline interpolation from [Eigen](https://eigen.tuxfamily.org/dox/unsupported/group__Splines__Module.html)3. Alignment of Trajectories by Rigid Transformation
- SLAM trajectory aligned to reference using Umeyama algorithm transformation in 2D/3D
- application of calculated transformation on SLAM trajectory
- screenshot below shows results of alignment of SLAM trajectory to projected reference trajectory with Umeyama algorithm
4. Rubber-Sheet transformation
- piecewise linear rubber-sheet transformation in 2D/3D based on concept of Griffin & White
- using Delaunay triangulation from CGAL
- manual selection of control points in RVIZ (see above) possible if trajectories are not time-synchronized (parameter
auto_cp) - automatic exclusion of trajectory points as control points using thresholding for standard deviation possible
- manual exclusion of indices as controlpoints and manual displacement in xy possible, see parameter descriptions
- application of calculated transformations on target SLAM-poses and point cloud map
- the two screenshots below show selected control points on the aligned trajectories from step 2 and the results of the rubber-sheet transformation
Evaluation
- enable with the
--evaluationflag onflexcloud-georeferencing. - statistics (RMSE, mean, median, stddev, min, max) of the per-point euclidean deviation between the reference trajectory and both the Umeyama-aligned and the rubber-sheeted SLAM trajectory are printed to the terminal in a single side-by-side table.
- the same per-segment deviations are visualized in the Rerun viewer as two additional, jet-colormap-shaded linestrings:
Trajectory_align_deviationandTrajectory_RS_deviation(segment label = deviation value in meters).
Build from Source
git clone git@github.com:TUMFTM/FlexCloud.git
cd FlexCloud/
./docker/build_docker.sh
You can also download built versions of the docker images from the github container registry. E.g. to download the latest container, run:
docker pull ghcr.io/tumftm/flexcloud:latest
Run the container and mount your data by appending the directory containing your data:
./docker/run_docker.sh /your/local/directory/data
Test Data
The data was recorded by the TUM Autonomous Motorsport Team during the Abu Dhabi Autonomous Racing League 2025. The LiDAR/SLAM trajectory is created using glim. The reference trajectory presents raw data from the RTK-corrected GNSS-signal of the vehicle.
Developers
- Maximilian Leitenstern, Institute of Automotive Technology, School of Engineering and Design, Technical University of Munich, 85748 Garching, Germany
- Marko Alten (student research project)
- Christian Bolea-Schaser (student research project)
Citation
If you use this repository for any academic work, please consider citing our paper (preprint):
@misc{leitenstern2025flexcloud,
title={FlexCloud: Direct, Modular Georeferencing and Drift-Correction of Point Cloud Maps},
author={Maximilian Leitenstern and Marko Alten and Christian Bolea-Schaser and Dominik Kulmer and Marcel Weinmann and Markus Lienkamp},
year={2025},
eprint={2502.00395},
archivePrefix={arXiv},
primaryClass={cs.RO},
url={https://arxiv.org/abs/2502.00395},
}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flexcloud-1.0.1-cp312-cp312-manylinux_2_39_x86_64.whl.
File metadata
- Download URL: flexcloud-1.0.1-cp312-cp312-manylinux_2_39_x86_64.whl
- Upload date:
- Size: 92.6 MB
- Tags: CPython 3.12, manylinux: glibc 2.39+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7dd2204bf039834f05d6dea23af8e30f81b8854f0b174bd6d7fedf0aa35e8293
|
|
| MD5 |
6b83ec59946a18254f371ca60ff47c30
|
|
| BLAKE2b-256 |
85fe846a5fbc30a86112c79c4d46af573895911ee004447e2ee3c1672acba8a3
|
Provenance
The following attestation bundles were made for flexcloud-1.0.1-cp312-cp312-manylinux_2_39_x86_64.whl:
Publisher:
pypi.yml on TUMFTM/FlexCloud
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flexcloud-1.0.1-cp312-cp312-manylinux_2_39_x86_64.whl -
Subject digest:
7dd2204bf039834f05d6dea23af8e30f81b8854f0b174bd6d7fedf0aa35e8293 - Sigstore transparency entry: 1437044546
- Sigstore integration time:
-
Permalink:
TUMFTM/FlexCloud@917343587601e5a3911a63b6409942e882249fb9 -
Branch / Tag:
refs/tags/1.0.1 - Owner: https://github.com/TUMFTM
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@917343587601e5a3911a63b6409942e882249fb9 -
Trigger Event:
release
-
Statement type: