You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Bug fix (non-breaking change which fixes an issue): Fixes #
New feature (non-breaking change which adds functionality). Resolves #
Breaking change (fix or feature that would cause existing functionality to not work as expected) Resolves #
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:
Local source search under cpp, python, docs, and examples found no
existing NDT registration implementation.
GitHub API search for active Open3D PRs matching NDT registration returned total_count: 0 on 2026-07-08.
Checklist:
I have run python util/check_style.py --apply to apply Open3D code style
to my code.
This PR changes Open3D behavior or adds new functionality.
Both C++ (Doxygen) and Python (Sphinx / Google style) documentation is
updated accordingly.
I have added or updated C++ and / or Python unit tests OR included test
results (e.g. screenshots or numbers) here.
I will follow up and update the code if CI fails.
For fork PRs, I have selected Allow edits from maintainers.
The 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 RegistrationResult includes fitness, Euclidean RMSE against the
accepted voxel means, the estimated transform, and representative target-point
indices 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:
C++ tests for invalid option validation, synthetic known-transform recovery,
and improvement over initial alignment.
Python tests for option binding, synthetic known-transform recovery, and
invalid option validation.
Hi @Xiang-Zeng thanks for submitting this great new feature!
Please take a look at the failing CI checks (please ignore if they are due to unrelated changes - the main branch is in some major refactoring at the moment).
Also please provide the citation of the paper that is implemented here (add to docs and also here in the PR).
Hi @ssheorey ,
Thank you for the positive feedback! I will go through the failing CI checks and separate issues caused by this PR.
The Codacy/Cppcheck warnings about missing #include files (e.g., <Eigen/Core>, , ) seems to be false positives.
Some remaining failures appear to be related to GitHub attestation/OIDC permissions in forked PR workflows (Run actions/attest@v4 Error: missing "id-token" permission. Please add "permissions: id-token: write" to your workflow.).
I added the paper citation to the documentation and updated the PR description.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 against theaccepted voxel means, the estimated transform, and representative target-point
indices 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.