apex-io
High-performance file I/O for pose graphs (G2O, TORO) and bundle adjustment (BAL) with SE2/SE3 support.
Overview
This library provides parsers and writers for common SLAM (Simultaneous Localization and Mapping) and Structure-from-Motion file formats. It enables easy loading and saving of pose graph optimization problems with:
- Memory-mapped file reading for fast I/O on large files
- Parallel parsing with rayon for multi-core acceleration
- Type-safe graph representation with separate SE2/SE3 types
- Comprehensive error handling with line numbers and context
- Optional visualization support via Rerun integration
Target applications include:
- Pose graph optimization (2D and 3D SLAM)
- Bundle adjustment for Structure-from-Motion
- Visual odometry and localization
- Robotics trajectory optimization
Supported Formats
| Format | Description | Vertex Types | Edge Types | Read | Write |
|---|---|---|---|---|---|
| G2O | General Graph Optimization | SE2, SE3 | SE2, SE3 | ✓ | ✓ |
| TORO | Tree-based netwORk Optimizer | SE2 only | SE2 only | ✓ | ✓ |
| BAL | Bundle Adjustment in the Large | Cameras, Points | Observations | ✓ | - |
G2O Format
The G2O (General Graph Optimization) format is widely used in robotics for pose graph optimization. It supports both 2D (SE2) and 3D (SE3) graphs.
File Structure:
# Comments start with #
VERTEX_SE2 id x y theta
VERTEX_SE3:QUAT id x y z qx qy qz qw
EDGE_SE2 from to dx dy dtheta info_xx info_xy info_yy info_xt info_yt info_tt
EDGE_SE3:QUAT from to dx dy dz dqx dqy dqz dqw [21 information matrix values]
Example (2D):
VERTEX_SE2 0 0.0 0.0 0.0
VERTEX_SE2 1 1.0 0.0 0.0
EDGE_SE2 0 1 1.0 0.0 0.0 500 0 500 0 0 500
TORO Format
The TORO (Tree-based netwORk Optimizer) format is a legacy 2D SLAM format.
File Structure:
VERTEX2 id x y theta
EDGE2 from to dx dy dtheta info_xx info_xy info_yy info_xt info_yt info_tt
Note: TORO only supports SE2 (2D) graphs. Attempting to write SE3 data will result in an error.
BAL Format
The BAL (Bundle Adjustment in the Large) format is used for large-scale bundle adjustment benchmarks in computer vision.
File Structure:
num_cameras num_points num_observations
# Observations block (one per line)
camera_idx point_idx pixel_x pixel_y
...
# Cameras block (9 parameters per camera, one per line)
rotation_x
rotation_y
rotation_z
translation_x
translation_y
translation_z
focal_length
k1
k2
...
# Points block (3 coordinates per point, one per line)
x
y
z
...
Camera Model: Snavely's 9-parameter model from Bundler:
- 3 parameters: Axis-angle rotation (rx, ry, rz)
- 3 parameters: Translation (tx, ty, tz)
- 1 parameter: Focal length (f)
- 2 parameters: Radial distortion (k1, k2)
Installation
[]
= "0.1.0"
For visualization features (Rerun integration):
[]
= { = "0.1.0", = ["visualization"] }
Data Structures
Graph
The main container for pose graph data:
SE2 Types (2D)
VertexSE2 - 2D pose (position + orientation):
EdgeSE2 - 2D constraint between vertices:
SE3 Types (3D)
VertexSE3 - 3D pose (position + orientation):
EdgeSE3 - 3D constraint between vertices:
BAL Types
BalDataset - Complete bundle adjustment problem:
BalCamera - Snavely's 9-parameter camera model:
BalPoint - 3D landmark:
BalObservation - 2D image observation:
API Reference
GraphLoader Trait
All pose graph loaders implement this trait:
Loaders
| Loader | Formats | Description |
|---|---|---|
G2oLoader |
.g2o |
G2O format with SE2/SE3 support |
ToroLoader |
.graph |
TORO format (SE2 only) |
BalLoader |
.txt |
BAL bundle adjustment format |
Convenience Functions
/// Auto-detect format from file extension
;
Supported extensions:
.g2o→ G2oLoader.graph→ ToroLoader
Error Handling
The IoError enum provides detailed error information:
| Variant | Description |
|---|---|
Io(io::Error) |
Underlying I/O error |
Parse { line, message } |
Parse error with line number |
UnsupportedVertexType(String) |
Unknown vertex type in file |
UnsupportedEdgeType(String) |
Unknown edge type in file |
InvalidNumber { line, value } |
Failed to parse number |
MissingFields { line } |
Insufficient fields on line |
DuplicateVertex { id } |
Vertex ID already exists |
InvalidQuaternion { line, norm } |
Quaternion not unit length |
UnsupportedFormat(String) |
File extension not recognized |
FileCreationFailed { path, reason } |
Could not create output file |
All errors include context via .log() and .log_with_source() methods for tracing integration.
Usage Examples
Loading a G2O File
use ;
let graph = load?;
println!;
Auto-detect Format
use load_graph;
// Automatically detects format from extension
let graph = load_graph?;
Working with SE3 Vertices and Edges
use ;
let graph = load?;
// Iterate over SE3 vertices
for in &graph.vertices_se3
// Iterate over SE3 edges
for edge in &graph.edges_se3
Working with SE2 Vertices and Edges
use ;
let graph = load?;
// Iterate over SE2 vertices
for in &graph.vertices_se2
// Iterate over SE2 edges
for edge in &graph.edges_se2
Writing a Graph
use ;
let graph = load?;
// Write to G2O format
write?;
// Write to TORO format (SE2 only)
write?;
Loading BAL Dataset
use BalLoader;
let dataset = load?;
println!;
// Access camera parameters
for in dataset.cameras.iter.enumerate
// Access observations
for obs in &dataset.observations
Performance
Memory Mapping
All loaders use memory-mapped file I/O via memmap2 for efficient reading of large files. This avoids loading the entire file into memory and leverages the operating system's page cache.
Parallel Parsing
For files with more than 1000 lines, parsing is automatically parallelized using rayon. This significantly speeds up loading of large pose graphs and BAL datasets.
Pre-allocation
Collections are pre-allocated based on estimated file size to minimize memory reallocations during parsing.
Visualization Feature
Enable the visualization feature for Rerun integration:
= { = "0.1.0", = ["visualization"] }
This adds helper methods for converting vertices to Rerun types:
// SE2 vertices
let pos_2d: = vertex_se2.to_rerun_position_2d;
let pos_3d: Vec3 = vertex_se2.to_rerun_position_3d;
// SE3 vertices
let : = vertex_se3.to_rerun_transform;
Dependencies
| Dependency | Purpose |
|---|---|
apex-manifolds |
Lie group types (SE2, SE3) |
nalgebra |
Linear algebra (vectors, matrices) |
memmap2 |
Memory-mapped file I/O |
rayon |
Parallel parsing |
thiserror |
Error handling |
tracing |
Structured logging |
serde, serde_json |
Serialization support |
chrono |
Timestamps in file headers |
rerun |
Visualization (optional) |
References
- g2o: A General Framework for Graph Optimization
- TORO: Tree-based netwORk Optimizer
- Bundle Adjustment in the Large
- Bundler: Structure from Motion
License
Apache-2.0