Add Normal Distributions Transform (NDT) registration - #7517
Conversation
5e0123d to
cc0e43c
Compare
|
Hi @Xiang-Zeng thanks for submitting this great new feature! |
|
Hi @ssheorey , |
b9f2576 to
131ebe5
Compare
There was a problem hiding this comment.
Pull request overview
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Adds a legacy CPU 3D Normal Distributions Transform (NDT) registration pipeline to Open3D, including C++/Python APIs, docs, examples, and tests.
Changes:
- Implement
NormalDistributionsTransformOptionandRegistrationNDTin C++, and expose them via Python bindings (registration_ndt). - Add C++ and Python unit tests validating option constraints and known-transform recovery.
- Add documentation/tutorial page and a runnable Python example for NDT registration.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| python/test/pipelines/test_normal_distributions_transform.py | Adds Python tests for the new NDT option + binding + correctness/validation. |
| examples/python/pipelines/ndt_registration.py | Adds a runnable Python example demonstrating NDT registration usage. |
| docs/tutorial/reference.rst | Adds NDT-related references used by the new tutorial page. |
| docs/tutorial/pipelines/ndt_registration.rst | Adds a new tutorial page describing NDT and linking to the example. |
| docs/tutorial/pipelines/index.rst | Adds the NDT tutorial page to the pipelines toctree. |
| cpp/tests/pipelines/registration/NormalDistributionsTransform.cpp | Adds C++ unit tests for option validation and registration behavior. |
| cpp/tests/pipelines/CMakeLists.txt | Registers the new NDT C++ test file in the test target. |
| cpp/pybind/pipelines/registration/registration.cpp | Adds Python bindings for NDT option and registration_ndt. |
| cpp/open3d/pipelines/registration/NormalDistributionsTransform.h | Declares the new NDT option type and registration entrypoint. |
| cpp/open3d/pipelines/registration/NormalDistributionsTransform.cpp | Implements voxel-Gaussian construction, Gauss-Newton solve, and result evaluation for NDT. |
| cpp/open3d/pipelines/CMakeLists.txt | Adds the NDT implementation source to the pipelines library build. |
| cpp/open3d/Open3D.h.in | Exposes the new NDT header in the umbrella Open3D header. |
| CHANGELOG.md | Documents the addition of NDT registration in the changelog. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Type
Motivation and Context
Open3D provides ICP, Colored ICP, Generalized ICP, RANSAC, and FGR registration
pipelines, but does not currently expose a 3D Normal Distributions Transform
(NDT) registration method. NDT is a common LiDAR / point-cloud registration
method that optimizes a source-to-target rigid transform against voxelized
Gaussian target distributions instead of nearest-neighbor point
correspondences.
Upstream check:
cpp,python,docs, andexamplesfound noexisting NDT registration implementation.
total_count: 0on 2026-07-08.Checklist:
python util/check_style.py --applyto apply Open3D code styleto my code.
updated accordingly.
results (e.g. screenshots or numbers) here.
Description
This PR adds a legacy CPU registration API:
NormalDistributionsTransformOptionRegistrationNDTopen3d.pipelines.registration.registration_ndtThe implementation builds a target voxel Gaussian map once per registration
call, accepts either center-voxel or six-neighbor voxel residuals, regularizes
small covariance eigenvalues, rejects residuals by squared Mahalanobis distance,
and solves the rigid update using Open3D's existing Eigen SE(3) utilities.
The returned
RegistrationResultincludes fitness, Euclidean RMSE over the returned representative target-point correspondences, the estimated transform, and representative target-pointindices for accepted voxel residuals.
This implementation is based on the Normal Distributions Transform (NDT) registration algorithm originally proposed by Biber and Straßer [1]. The concrete implementation follows the open‑source reference code by Gao [2], while being adapted to Open3D's registration API and coding style.
[1] P. Biber and W. Straßer, "The Normal Distributions Transform: A New Approach to Laser Scan Matching," Proceedings of the 2003 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS 2003), vol. 3, pp. 2743–2748, IEEE, 2003.
[2] Xiang Gao, SLAM Technology in Autonomous Driving and Robotics: From Theory to Practice (in Chinese), Publishing House of Electronics Industry, 2023. Code available at: https://github.com/gaoxiang12/slam_in_autonomous_driving/blob/master/src/ch7/ndt_3d.cc
Added:
and improvement over initial alignment.
invalid option validation.
examples/python/pipelines/ndt_registration.pydocs/tutorial/pipelines/ndt_registration.rstLocal verification:
Real-data validation: examples/python/pipelines/ndt_registration.py
The Python test was run against the local build package via
PYTHONPATH; noglobal Open3D package was installed or overwritten.