23 namespace registration {
25 template <
class TransformationEstimationBase = TransformationEstimation>
28 using TransformationEstimationBase::TransformationEstimationBase;
31 TransformationEstimationBase,
void);
36 PYBIND11_OVERLOAD_PURE(
double, TransformationEstimationBase, source,
37 target, correspondences);
43 const std::size_t iteration)
const {
44 PYBIND11_OVERLOAD_PURE(
core::Tensor, TransformationEstimationBase,
45 source, target, correspondences,
46 current_transform, iteration);
51 static const std::unordered_map<std::string, std::string>
54 "Tensor of type Int64 containing indices of corresponding "
55 "target points, where the value is the target index and the "
56 "index of the value itself is the source index. It contains "
57 "-1 as value at index with no correspondence."},
58 {
"criteria",
"Convergence criteria"},
60 "List of Convergence criteria for each scale of multi-scale "
63 "Estimation method. One of "
64 "(``TransformationEstimationPointToPoint``, "
65 "``TransformationEstimationPointToPlane``, "
66 "``TransformationEstimationForColoredICP``, "
67 "``TransformationEstimationForGeneralizedICP``)"},
68 {
"init_source_to_target",
"Initial transformation estimation"},
69 {
"max_correspondence_distance",
70 "Maximum correspondence points-pair distance."},
71 {
"max_correspondence_distances",
72 "o3d.utility.DoubleVector of maximum correspondence "
73 "points-pair distances for multi-scale icp."},
74 {
"option",
"Registration option"},
75 {
"source",
"The source point cloud."},
76 {
"target",
"The target point cloud."},
78 "The 4x4 transformation matrix of type Float64 "
79 "to transform ``source`` to ``target``"},
81 "The input pointclouds will be down-sampled to this "
82 "`voxel_size` scale. If `voxel_size` < 0, original scale will "
83 "be used. However it is highly recommended to down-sample the "
84 "point-cloud for performance. By default original scale of "
85 "the point-cloud will be used."},
87 "o3d.utility.DoubleVector of voxel sizes in strictly "
88 "decreasing order, for multi-scale icp."},
89 {
"callback_after_iteration",
90 "Optional lambda function, saves string to tensor map of "
91 "attributes such as iteration_index, scale_index, "
92 "scale_iteration_index, inlier_rmse, fitness, transformation, "
93 "on CPU device, updated after each iteration."}};
95 py::class_<ICPConvergenceCriteria> convergence_criteria(
96 m_registration,
"ICPConvergenceCriteria",
97 "Convergence criteria of ICP. "
98 "ICP algorithm stops if the relative change of fitness and rmse "
99 "hit ``relative_fitness`` and ``relative_rmse`` individually, "
100 "or the iteration number exceeds ``max_iteration``.");
101 py::class_<RegistrationResult> registration_result(
102 m_registration,
"RegistrationResult",
"Registration results.");
105 te(m_registration,
"TransformationEstimation",
106 "Base class that estimates a transformation between two "
107 "point clouds. The virtual function ComputeTransformation() "
108 "must be implemented in subclasses.");
112 te_p2p(m_registration,
"TransformationEstimationPointToPoint",
113 "Class to estimate a transformation for point to "
118 te_p2l(m_registration,
"TransformationEstimationPointToPlane",
119 "Class to estimate a transformation for point to "
125 te_col(m_registration,
"TransformationEstimationForColoredICP",
126 "Class to estimate a transformation between two point "
127 "clouds using color information");
132 te_dop(m_registration,
"TransformationEstimationForDopplerICP",
133 "Class to estimate a transformation between two point "
134 "clouds using color information");
136 py::detail::bind_copy_functions<ICPConvergenceCriteria>(
137 convergence_criteria);
139 .def(py::init<double, double, int>(),
"relative_fitness"_a = 1e-6,
140 "relative_rmse"_a = 1e-6,
"max_iteration"_a = 30)
144 "If relative change (difference) of fitness score is lower "
145 "than ``relative_fitness``, the iteration stops.")
148 "If relative change (difference) of inlier RMSE score is "
149 "lower than ``relative_rmse``, the iteration stops.")
150 .def_readwrite(
"max_iteration",
152 "Maximum iteration before iteration stops.")
155 "ICPConvergenceCriteria[relative_fitness_={:e}, "
156 "relative_rmse={:e}, max_iteration_={:d}].",
162 py::detail::bind_default_constructor<RegistrationResult>(
163 registration_result);
164 py::detail::bind_copy_functions<RegistrationResult>(registration_result);
166 .def_readwrite(
"transformation",
168 "``4 x 4`` float64 tensor on CPU: The estimated "
169 "transformation matrix.")
170 .def_readwrite(
"correspondence_set",
172 "Tensor of type Int64 containing indices of "
173 "corresponding target points, where the value is "
174 "the target index and the index of the value itself "
175 "is the source index. It contains -1 as value at "
176 "index with no correspondence.")
178 "float: RMSE of all inlier correspondences. Lower "
181 "float: The overlapping area (# of inlier "
183 "/ # of points in source). Higher is better.")
186 "bool: Specifies whether the algorithm converged or not.")
189 "int: Number of iterations the algorithm took to converge.")
192 "RegistrationResult["
194 ", num_iteration={:d}"
197 ", correspondences={:d}]."
198 "\nAccess transformation to get result.",
205 "target"_a,
"correspondences"_a,
206 "Compute RMSE between source and target points cloud given "
208 te.def(
"compute_transformation",
210 "target"_a,
"correspondences"_a,
211 "current_transform"_a =
214 "Compute transformation from source to target point cloud given "
218 {{
"source",
"Source point cloud."},
219 {
"target",
"Target point cloud."},
221 "Tensor of type Int64 containing "
222 "indices of corresponding target "
223 "points, where the value is the "
224 "target index and the index of "
225 "the value itself is the source "
226 "index. It contains -1 as value "
227 "at index with no correspondence."}});
229 m_registration,
"TransformationEstimation",
230 "compute_transformation",
231 {{
"source",
"Source point cloud."},
232 {
"target",
"Target point cloud."},
234 "Tensor of type Int64 containing indices of corresponding target "
235 "points, where the value is the target index and the index of "
236 "the value itself is the source index. It contains -1 as value "
237 "at index with no correspondence."},
238 {
"current_transform",
"The current pose estimate of ICP."},
240 "The current iteration number of the ICP algorithm."}});
244 py::detail::bind_copy_functions<TransformationEstimationPointToPoint>(
246 te_p2p.def(py::init())
249 return std::string(
"TransformationEstimationPointToPoint");
254 py::detail::bind_default_constructor<TransformationEstimationPointToPlane>(
256 py::detail::bind_copy_functions<TransformationEstimationPointToPlane>(
264 return std::string(
"TransformationEstimationPointToPlane");
266 .def_readwrite(
"kernel",
268 "Robust Kernel used in the Optimization");
272 py::detail::bind_default_constructor<TransformationEstimationForColoredICP>(
274 py::detail::bind_copy_functions<TransformationEstimationForColoredICP>(
276 te_col.def(py::init([](
double lambda_geometric,
RobustKernel &kernel) {
278 lambda_geometric, kernel);
280 "lambda_geometric"_a,
"kernel"_a)
281 .def(py::init([](
const double lambda_geometric) {
285 "lambda_geometric"_a)
295 "TransformationEstimationForColoredICP "
296 "with lambda_geometric: ") +
303 .def_readwrite(
"kernel",
305 "Robust Kernel used in the Optimization");
309 py::detail::bind_default_constructor<TransformationEstimationForDopplerICP>(
311 py::detail::bind_copy_functions<TransformationEstimationForDopplerICP>(
313 te_dop.def(py::init([](
double period,
double lambda_doppler,
314 bool reject_dynamic_outliers,
315 double doppler_outlier_threshold,
316 std::size_t outlier_rejection_min_iteration,
317 std::size_t geometric_robust_loss_min_iteration,
318 std::size_t doppler_robust_loss_min_iteration,
323 period, lambda_doppler, reject_dynamic_outliers,
324 doppler_outlier_threshold,
325 outlier_rejection_min_iteration,
326 geometric_robust_loss_min_iteration,
327 doppler_robust_loss_min_iteration, geometric_kernel,
328 doppler_kernel, transform_vehicle_to_sensor);
330 "period"_a,
"lambda_doppler"_a,
"reject_dynamic_outliers"_a,
331 "doppler_outlier_threshold"_a,
332 "outlier_rejection_min_iteration"_a,
333 "geometric_robust_loss_min_iteration"_a,
334 "doppler_robust_loss_min_iteration"_a,
"goemetric_kernel"_a,
335 "doppler_kernel"_a,
"transform_vehicle_to_sensor"_a)
336 .def(py::init([](
const double lambda_doppler) {
341 .def(
"compute_transformation",
347 ComputeTransformation,
349 "Compute transformation from source to target point cloud "
350 "given correspondences")
354 "TransformationEstimationForDopplerICP "
355 "with lambda_doppler: ") +
358 .def_readwrite(
"period",
360 "Time period (in seconds) between the source and "
361 "the target point clouds.")
365 "`λ ∈ [0, 1]` in the overall energy `(1−λ)EG + λED`. Refer "
366 "the documentation of DopplerICP for more information.")
367 .def_readwrite(
"reject_dynamic_outliers",
369 reject_dynamic_outliers_,
370 "Whether or not to reject dynamic point outlier "
372 .def_readwrite(
"doppler_outlier_threshold",
374 doppler_outlier_threshold_,
375 "Correspondences with Doppler error greater than "
376 "this threshold are rejected from optimization.")
377 .def_readwrite(
"outlier_rejection_min_iteration",
379 outlier_rejection_min_iteration_,
380 "Number of iterations of ICP after which outlier "
381 "rejection is enabled.")
382 .def_readwrite(
"geometric_robust_loss_min_iteration",
384 geometric_robust_loss_min_iteration_,
385 "Minimum iterations after which Robust Kernel is "
386 "used for the Geometric error")
387 .def_readwrite(
"doppler_robust_loss_min_iteration",
389 doppler_robust_loss_min_iteration_,
390 "Minimum iterations after which Robust Kernel is "
391 "used for the Doppler error")
395 "Robust Kernel used in the Geometric Error Optimization")
399 "Robust Kernel used in the Doppler Error Optimization")
400 .def_readwrite(
"transform_vehicle_to_sensor",
402 transform_vehicle_to_sensor_,
403 "The 4x4 extrinsic transformation matrix between "
404 "the vehicle and the sensor frames.");
407 py::call_guard<py::gil_scoped_release>(),
408 "Function for evaluating registration between point clouds",
409 "source"_a,
"target"_a,
"max_correspondence_distance"_a,
415 "icp", &
ICP, py::call_guard<py::gil_scoped_release>(),
416 "Function for ICP registration",
"source"_a,
"target"_a,
417 "max_correspondence_distance"_a,
418 "init_source_to_target"_a =
422 "callback_after_iteration"_a = py::none());
428 py::call_guard<py::gil_scoped_release>(),
429 "Function for Multi-Scale ICP registration",
"source"_a,
"target"_a,
430 "voxel_sizes"_a,
"criteria_list"_a,
431 "max_correspondence_distances"_a,
432 "init_source_to_target"_a =
435 "callback_after_iteration"_a = py::none());
441 py::call_guard<py::gil_scoped_release>(),
442 "Function for computing information matrix from transformation "
443 "matrix. Information matrix is tensor of shape {6, 6}, dtype "
446 "source"_a,
"target"_a,
"max_correspondence_distance"_a,
453 py::module m_registration = m.def_submodule(
454 "registration",
"Tensor-based registration pipeline.");
filament::Texture::InternalFormat format
int64_t GetLength() const
static Tensor Eye(int64_t n, Dtype dtype, const Device &device)
Create an identity matrix of size n x n.
A point cloud contains a list of 3D points.
Class that defines the convergence criteria of ICP.
int max_iteration_
Maximum iteration before iteration stops.
core::Tensor transformation_
The estimated transformation matrix of dtype Float64 on CPU device.
core::Tensor correspondences_
bool converged_
Specifies whether the algorithm converged or not.
size_t num_iterations_
Number of iterations the algorithm took to converge.
double inlier_rmse_
RMSE of all inlier correspondences. Lower is better.
void ClassMethodDocInject(py::module &pybind_module, const std::string &class_name, const std::string &function_name, const std::unordered_map< std::string, std::string > &map_parameter_body_docs)
void FunctionDocInject(py::module &pybind_module, const std::string &function_name, const std::unordered_map< std::string, std::string > &map_parameter_body_docs)
core::Tensor GetInformationMatrix(const geometry::PointCloud &source, const geometry::PointCloud &target, const double max_correspondence_distance, const core::Tensor &transformation)
Computes Information Matrix, from the transfromation between source and target pointcloud....
RegistrationResult ICP(const geometry::PointCloud &source, const geometry::PointCloud &target, const double max_correspondence_distance, const core::Tensor &init_source_to_target, const TransformationEstimation &estimation, const ICPConvergenceCriteria &criteria, const double voxel_size, const std::function< void(const std::unordered_map< std::string, core::Tensor > &)> &callback_after_iteration)
Functions for ICP registration.
RegistrationResult EvaluateRegistration(const geometry::PointCloud &source, const geometry::PointCloud &target, double max_correspondence_distance, const core::Tensor &transformation)
Function for evaluating registration between point clouds.
static const std::unordered_map< std::string, std::string > map_shared_argument_docstrings
TransformationEstimationType
void pybind_registration(py::module &m)
RegistrationResult MultiScaleICP(const geometry::PointCloud &source, const geometry::PointCloud &target, const std::vector< double > &voxel_sizes, const std::vector< ICPConvergenceCriteria > &criterias, const std::vector< double > &max_correspondence_distances, const core::Tensor &init_source_to_target, const TransformationEstimation &estimation, const std::function< void(const std::unordered_map< std::string, core::Tensor > &)> &callback_after_iteration)
Functions for Multi-Scale ICP registration. It will run ICP on different voxel level,...
void pybind_registration_class(py::module &m_registration)
void pybind_robust_kernels(py::module &m)
void pybind_feature(py::module &m_registration)
Generic file read and write utility for python interface.
std::string to_string(const T &n)