Skip to content

Commit e588c3b

Browse files
Add README for python wrapper g2opy
1 parent 9d4dbf8 commit e588c3b

File tree

2 files changed

+228
-16
lines changed

2 files changed

+228
-16
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "scikit_build_core.build"
66
name = "g2opy"
77
version = "2.2.0"
88
description="g2o: A General Framework for Graph Optimization"
9-
readme = "README.md"
9+
readme = "python/README.md"
1010
authors = [
1111
{ name = "Rainer Kuemmerle", email = "rainer.kuemmerle@gmail.com" },
1212
]

python/README.md

Lines changed: 227 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,233 @@
1-
# g2opy
2-
This is a python binding of [g2o](https://github.com/RainerKuemmerle/g2o).
1+
# g2opy - Python Bindings for g2o
32

4-
The code here is based on https://github.com/uoip/g2opy.git by qihang@outlook.com
3+
This is a Python binding of [g2o](https://github.com/RainerKuemmerle/g2o), a C++ library for graph-based optimization.
54

6-
Currently, this project doesn't support writing user-defined types in python,
7-
but the predefined types are enough to implement the most common algorithms,
8-
say **PnP, ICP, Bundle Adjustment and Pose Graph Optimization** in 2d or 3d
9-
scenarios. g2o's visualization part is not wrapped, if you want to visualize
10-
point clouds or graph, you can give
11-
[pangolin](https://github.com/uoip/pangolin) a try, it's a python binding of
12-
C++ library [Pangolin](http://github.com/stevenlovegrove/Pangolin).
5+
## Features
136

14-
For convenience, some frequently used Eigen types (Quaternion, Rotation2d,
15-
Isometry3d, Isometry2d, AngleAxis) are packed into this library.
7+
g2opy provides high-level Python bindings for most common g2o use cases:
168

17-
## Requirements
18-
* ([pybind11](https://github.com/pybind/pybind11)
9+
- **Optimization Algorithms**: Gauss-Newton, Levenberg-Marquardt, Dogleg
10+
- **Linear Solvers**: Dense, Eigen, PCG, CSparse, CHOLMOD
11+
- **SLAM Types**:
12+
- **2D SLAM**: SE2 poses, XY points, pose-to-pose/point constraints
13+
- **3D SLAM**: SE3 poses, XYZ points, pose-to-pose/point constraints
14+
- **SLAM Priors**: Pose priors, point priors, offset constraints
15+
- **Bundle Adjustment (SBA)**: Multiple camera models and projection edges
16+
- **SIM3 Optimization**: Similarity transforms with scale
17+
- **ICP**: Generalized Iterative Closest Point (GiCP)
18+
- **Sensor Calibration**: SCLAM2D and multi-sensor calibration
19+
20+
## Usage
21+
22+
### Basic Optimization Example
23+
24+
```python
25+
import g2opy
26+
27+
# Create optimizer
28+
optimizer = g2opy.SparseOptimizer()
29+
solver = g2opy.BlockSolverSE2(g2opy.LinearSolverCholmodSE2())
30+
algorithm = g2opy.OptimizationAlgorithmLevenberg(solver)
31+
optimizer.set_algorithm(algorithm)
32+
33+
# Add vertices and edges
34+
v1 = g2opy.VertexSE2()
35+
v1.set_id(0)
36+
v1.set_estimate(g2opy.SE2(0, 0, 0))
37+
optimizer.add_vertex(v1)
38+
39+
# ... add more vertices and edges ...
40+
41+
# Optimize
42+
optimizer.initialize_optimization()
43+
optimizer.optimize(10)
44+
```
45+
46+
### Creating Types by Factory
47+
48+
You can dynamically create vertices and edges using the Factory pattern:
49+
50+
```python
51+
factory = g2opy.Factory()
52+
53+
# List all available types
54+
all_types = factory.known_types()
55+
print("Available types:", all_types)
56+
57+
# Create edge by type name
58+
edge = factory.construct("EDGE_SE2") # Creates EdgeSE2
59+
```
60+
61+
You can also obtain information about a type:
62+
63+
```python
64+
factory = g2opy.Factory()
65+
info = factory.type_info("EDGE_SE2")
66+
print(f"Dimension: {info.dimension}")
67+
print(f"Error dimension: {info.error_dimension}")
68+
```
69+
70+
### User-Defined Types
71+
72+
For dynamic optimization variables, you can use `VectorXVertex` and `VariableVectorXEdge`:
73+
74+
```python
75+
import g2opy
76+
import numpy as np
77+
78+
# Create a dynamic vertex
79+
vertex = g2opy.VectorXVertex()
80+
vertex.set_id(0)
81+
vertex.set_dimension(3) # 3-dimensional
82+
vertex.set_estimate(np.array([1.0, 2.0, 3.0]))
83+
84+
# Create a dynamic edge
85+
edge = g2opy.VariableVectorXEdge()
86+
edge.resize(1) # number of vertices
87+
edge.set_dimension(1) # dimension of the error function
88+
edge.set_vertex(0, vertex)
89+
edge.set_measurement(np.array([1.5, 2.5, 3.5]))
90+
edge.set_information(np.eye(3))
91+
92+
# Subclass for custom behavior
93+
class CustomEdge(g2opy.VariableVectorXEdge):
94+
def __init__(self) -> None:
95+
super().__init__()
96+
self.set_dimension(1) # dimension of the error function
97+
self.information()
98+
self.resize(1) # number of vertices
99+
self.set_measurement([0, 0]) # initial measurement
100+
101+
def compute_error(self):
102+
# Custom error computation
103+
v = self.vertex(0).estimate()
104+
measurement = self.measurement()
105+
self.error = v - measurement
106+
107+
def linearize_oplus(self):
108+
# Custom linearization
109+
self.set_jacobian(0, -np.eye(len(self.vertex(0).estimate())))
110+
```
111+
112+
## Core Classes
113+
114+
### Optimizer
115+
116+
- `SparseOptimizer`: Main optimization framework
117+
- `OptimizationAlgorithm`: Base class for optimization algorithms
118+
- `OptimizationAlgorithmGaussNewton`
119+
- `OptimizationAlgorithmLevenberg`
120+
- `OptimizationAlgorithmDogleg`
121+
122+
### Solvers
123+
124+
- `BlockSolver`: Base template for block solvers
125+
- `BlockSolverSE2`, `BlockSolverSE3`, `BlockSolverSim3`
126+
- `LinearSolver`: Base class for linear solvers
127+
- `LinearSolverDense`, `LinearSolverEigen`
128+
- `LinearSolverPCG`, `LinearSolverCSparse`, `LinearSolverCholmod`
129+
130+
### Graph Elements
131+
132+
- `HyperGraph`: Graph structure
133+
- `OptimizableGraph`: Base graph with vertices and edges
134+
- `VertexContainer`: Base vertex class
135+
- `EdgeContainer`: Base edge class
136+
137+
### Eigen Types
138+
139+
- `Quaternion`: Double-precision quaternion
140+
- `Isometry2d`, `Isometry3d`: Rigid transformations
141+
- `Rotation2d`: 2D rotation
142+
- `AngleAxis`: Angle-axis representation
143+
- `SE2`, `SE3Quat`: Special Euclidean groups
144+
145+
### Factory
146+
147+
- `Factory`: Dynamic type creation and registration
148+
- `construct(tag)`: Create vertex/edge by registered name
149+
- `known_types()`: List all registered types
150+
- `type_info(tag)`: Get dimension and structure information
151+
152+
### Parameters
153+
154+
- `Parameter`: Global optimization parameters
155+
- `ParameterContainer`: Parameter storage
156+
- Support for calibration parameters (camera intrinsics, SE2/SE3 offsets)
157+
158+
## Type Groups
159+
160+
Types are organized by category:
161+
162+
- **SLAM 2D**: `VertexSE2`, `VertexPointXY`, `EdgeSE2`, `EdgeSE2PointXY`, etc.
163+
- **SLAM 3D**: `VertexSE3`, `VertexPointXYZ`, `EdgeSE3`, `EdgeSE3PointXYZ`, etc.
164+
- **Bundle Adjustment**: `EdgeProjectXYZ2UV`, `EdgeStereoSE3ProjectXYZ`, etc.
165+
- **SIM3**: `VertexSim3Expmap`, `EdgeSim3`, `EdgeSim3ProjectXYZ`
166+
- **ICP**: `VertexStereoCamera`, `EdgeGiCP`, `EdgeStereoCamera`
167+
- **SCLAM2D**: `VertexOdomDifferentialParams`, `EdgeSE2SensorCalib`
168+
169+
## Requirements & Building
170+
171+
Requirements:
172+
173+
- Python 3.11+
174+
- Eigen3
175+
- pybind11 (included via CMake FetchContent)
176+
- g2o (from this repository)
177+
178+
## Building
179+
180+
The Python bindings are built as part of the main g2o CMake build:
181+
182+
```bash
183+
cd g2o/build
184+
cmake .. -DBUILD_PYTHON_BINDINGS=ON
185+
make -j4
186+
```
187+
188+
The compiled module will be in `build/lib/g2opy.*.so`.
189+
190+
## Performance Notes
191+
192+
### Threading
193+
194+
g2o operations that can take significant time release the Python GIL:
195+
- `optimizer.optimize()` - Main optimization loop
196+
- `optimizer.initialize_optimization()` - Graph initialization
197+
- `optimizer.compute_marginals()` - Covariance computation
198+
- `optimizer.compute_active_errors()` - Error evaluation
199+
200+
This allows other Python threads to run while optimization is in progress.
201+
202+
### Memory Management
203+
204+
The binding uses modern C++ memory management:
205+
- Smart pointers for ownership clarity
206+
- Automatic cleanup of resources
207+
- Minimal copying of Eigen matrices
208+
209+
### Type Registration
210+
211+
All g2o types are automatically registered when the module loads.
212+
The `Factory` class provides access to this registry for dynamic creation.
213+
214+
## References
215+
216+
- [Examples](examples)
217+
- [g2o Repository](https://github.com/RainerKuemmerle/g2o)
218+
- [g2o Paper](http://ais.informatik.uni-freiburg.de/publications/papers/kuemmerle11icra.pdf)
219+
- [pybind11 Documentation](https://pybind11.readthedocs.io/)
220+
221+
## Contributing
222+
223+
Improvements and bug reports are welcome! Please report issues to the
224+
[g2o project](https://github.com/RainerKuemmerle/g2o).
19225

20226
## License
21-
* The binding code and python example code is licensed under BSD License.
227+
228+
The binding code and Python examples are licensed under the BSD License.
229+
The g2o library itself is licensed under BSD and LGPL (see main repository).
230+
231+
## Acknowledgments
232+
233+
The binding code is originally based on [g2opy](https://github.com/uoip/g2opy.git) by qihang@outlook.com.

0 commit comments

Comments
 (0)