Python binding of OctoMap, the 3D occupancy mapping library.
OctoMap builds a probabilistic 3D occupancy map (an octree) from point clouds:
you stream in sensor measurements and query whether any point in space is
occupied, free, or still unknown. This package exposes that C++ library to
Python with NumPy arrays as the interchange format, so point clouds and queries
are plain np.ndarrays.
pip install octomap-pythonOr with uv:
uv add octomap-pythonBinary wheels are published for Linux (x86_64, aarch64), macOS (Apple Silicon), and Windows (AMD64), CPython 3.10-3.14. Other platforms build from the sdist and need a C++ compiler.
import numpy as np
import octomap
# Resolution is the smallest voxel edge length, in meters.
octree = octomap.OcTree(0.1)
# Insert a point cloud measured from a sensor at `origin`.
points = np.random.uniform(-1, 1, size=(1000, 3))
octree.insertPointCloud(
pointcloud=points,
origin=np.array([0.0, 0.0, 0.0]),
)
# Query a coordinate: occupied / free / unknown (never observed).
node = octree.search(points[0])
try:
print("occupied" if octree.isNodeOccupied(node) else "free")
except octomap.NullPointerException:
print("unknown")
# Bounding box of everything mapped so far.
print(octree.getMetricMin(), octree.getMetricMax())
# Persist to / restore from the OctoMap binary format.
octree.writeBinary("tree.bt")
restored = octomap.OcTree(0.1)
restored.readBinary("tree.bt")ColorOcTree adds a per-voxel RGB color on top of the same occupancy API:
octree = octomap.ColorOcTree(0.1)
point = np.array([1.0, 2.0, 3.0])
octree.updateNode(point, True)
octree.setNodeColor(point, 255, 0, 0)
octree.updateInnerOccupancy()
print(octree.search(point).getColor()) # (255, 0, 0)
# Color is preserved by the full map format (.ot), not the binary format (.bt).
octree.write("tree.ot")
restored = octomap.ColorOcTree.read("tree.ot")Runnable demos live in examples/. pointcloud_to_octree.py
shows the four views from the teaser above (pointcloud / occupied / occupied
(color) / empty) in a single window, with the cameras synchronized so dragging
one view rotates all four together:
git clone --recursive https://github.com/wkentaro/octomap-python.git
cd octomap-python
uv sync --group examples
cd examples
uv run python pointcloud_to_octree.pyIt builds both an OcTree and a ColorOcTree so the same scan renders as a
red occupancy grid and in its measured RGB color side by side. The viewer
itself (the synced 2x2 window) lives in examples/viewer.py, so the example
reads as a concise walk through the octomap API.
Releases are published to PyPI by the publish workflow, which fires when a
GitHub Release is published. It builds the wheel matrix + sdist and uploads via
PyPI Trusted Publishing (OIDC, no
stored token).
To cut a release:
- Bump
versioninpyproject.tomlto match the new tag and commit it. - Create a GitHub Release with tag
vX.Y.Z(e.g.v1.8.0.13). - The
publishworkflow runs and uploads the built distributions to PyPI.
This is a fork of neka-nat/python-octomap.
BSD-3-Clause (LICENSE)
