ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
slac.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 #include <Logging.h>
11 
12 #include "pybind/docstring.h"
13 #include "t/geometry/PointCloud.h"
16 
17 namespace cloudViewer {
18 namespace t {
19 namespace pipelines {
20 namespace slac {
21 
22 // SLAC functions have similar arguments, sharing arg docstrings.
23 static const std::unordered_map<std::string, std::string>
25  {"fnames_processed",
26  "List of filenames (str) for pre-processed pointcloud "
27  "fragments."},
28  {"fragment_filenames",
29  "List of filenames (str) for pointcloud fragments."},
30  {"fragment_pose_graph", "PoseGraph for pointcloud fragments"},
31  {"params",
32  "slac_optimizer_params Parameters to tune in optimization."},
33  {"debug_option", "debug options."}};
34 
35 void pybind_slac(py::module &m) {
36  py::module m_slac = m.def_submodule(
37  "slac",
38  "Tensor-based Simultaneous Localisation and Calibration pipeline.");
39  py::class_<SLACOptimizerParams> slac_optimizer_params(
40  m_slac, "slac_optimizer_params",
41  "SLAC parameters to tune in optimization.");
42  py::detail::bind_copy_functions<SLACOptimizerParams>(slac_optimizer_params);
43  slac_optimizer_params
44  .def(py::init<const int, const float, const float, const float,
45  const float, const core::Device, const std::string>(),
46  "max_iterations"_a = 5, "voxel_size"_a = 0.05,
47  "distance_threshold"_a = 0.07, "fitness_threshold"_a = 0.3,
48  "regularizer_weight"_a = 1, "device"_a = core::Device("CPU:0"),
49  "slac_folder"_a = "")
50  .def_readwrite("max_iterations",
52  "Number of iterations.")
53  .def_readwrite("voxel_size", &SLACOptimizerParams::voxel_size_,
54  "Voxel size to downsample input point cloud.")
55  .def_readwrite("distance_threshold",
57  " Distance threshold to filter inconsistent "
58  "correspondences.")
59  .def_readwrite("fitness_threshold",
61  "Fitness threshold to filter inconsistent pairs.")
62  .def_readwrite("regularizer_weight",
64  "Weight of the regularizer.")
65  .def_readwrite("device", &SLACOptimizerParams::device_,
66  "Device to use.")
67  .def_readwrite("slac_folder", &SLACOptimizerParams::slac_folder_,
68  "Relative directory to store SLAC results in the "
69  "dataset folder.")
70  .def(
71  "get_subfolder_name",
72  [](const SLACOptimizerParams &slac_optimizer_params) {
73  return slac_optimizer_params.GetSubfolderName();
74  },
75  "Relative directory to store SLAC results in the dataset "
76  "folder.")
77  .def("__repr__", [](const SLACOptimizerParams &params) {
78  return fmt::format(
79  "SLACOptimizerParams(max_iterations={:d}, "
80  "voxel_size={:e}, distance_threshold={:e}, "
81  "fitness_threshold={:e}, regularizer_weight={:e}, "
82  "device=cloudViewer.core.Device(\"{}\"), "
83  "slac_folder=\"{}\")",
84  params.max_iterations_, params.voxel_size_,
85  params.distance_threshold_, params.fitness_threshold_,
86  params.regularizer_weight_, params.device_.ToString(),
87  params.slac_folder_);
88  });
89 
90  py::class_<SLACDebugOption> slac_debug_option(m_slac, "slac_debug_option",
91  "SLAC debug options.");
92  py::detail::bind_copy_functions<SLACDebugOption>(slac_debug_option);
93  slac_debug_option
94  .def(py::init<const bool, const int>(), "debug"_a = false,
95  "debug_start_node_idx"_a = 0)
96  .def(py::init<const int>(), "debug_start_node_idx"_a)
97  .def_readwrite("debug", &SLACDebugOption::debug_, "Enable debug.")
98  .def_readwrite("debug_start_node_idx",
100  "The node id to start debugging with. Smaller nodes "
101  "will be skipped for visualization.")
102  .def("__repr__", [](const SLACDebugOption &debug_option) {
103  return fmt::format(
104  "SLACDebugOption(debug={}, "
105  "debug_start_node_idx={:d})",
106  debug_option.debug_ ? "True" : "False",
107  debug_option.debug_start_node_idx_);
108  });
109  py::class_<ControlGrid> control_grid(
110  m_slac, "control_grid",
111  " ControlGrid is a spatially hashed voxel grid used for non-rigid "
112  "point cloud registration and TSDF integration. Each grid stores a "
113  "map from the initial grid location to the deformed location. You "
114  "can imagine a control grid as a jelly that is warped upon "
115  "perturbation with its overall shape preserved. "
116  "Reference: "
117  "https://github.com/qianyizh/ElasticReconstruction/blob/master/"
118  "FragmentOptimizer/OptApp.cpp "
119  "http://vladlen.info/papers/elastic-fragments.pdf. ");
120  py::detail::bind_copy_functions<ControlGrid>(control_grid);
121  control_grid.def(py::init<>())
122  .def(py::init<float, int64_t, const core::Device>(), "grid_size"_a,
123  "grid_count"_a = 1000, "device"_a = core::Device("CPU:0"))
124  .def(py::init<float, core::Tensor, core::Tensor,
125  const core::Device>(),
126  "grid_size"_a, "keys"_a, "values"_a,
127  "device"_a = core::Device("CPU:0"))
128  .def(
129  "touch",
130  [](ControlGrid &control_grid, geometry::PointCloud &pcd) {
131  control_grid.Touch(pcd);
132  },
133  "Allocate control grids in the shared camera space.",
134  "pointcloud"_a)
135  .def("compactify", &ControlGrid::Compactify,
136  "Force rehashing, so that all entries are remapped to [0, "
137  "size) and form a contiguous index map.")
138  .def("get_neighbor_grid_map", &ControlGrid::GetNeighborGridMap,
139  "Get the neighbor indices per grid to construct the "
140  "regularizer. "
141  "Returns a 6-way neighbor grid map for all the active "
142  "entries of shape (N, ). "
143  "\n - buf_indices Active indices in the buffer of shape (N, ) "
144  "\n - buf_indices_nb Neighbor indices (including "
145  "non-allocated "
146  "entries) for the active entries of shape (N, 6). "
147  "\n - masks_nb Corresponding neighbor masks of shape (N, "
148  "6). ")
149  .def(
150  "parameterize",
151  [](ControlGrid &control_grid,
152  const geometry::PointCloud &pcd) {
153  return control_grid.Parameterize(pcd);
154  },
155  "Parameterize an input point cloud by embedding each point "
156  "in the grid "
157  "with 8 corners via indexing and interpolation. "
158  "Returns: A PointCloud with parameterization attributes: "
159  "\n- neighbors: Index of 8 neighbor control grid points of "
160  "shape (8, ) in Int64. "
161  "\n- ratios: Interpolation ratios of 8 neighbor control "
162  "grid points of shape (8, ) in Float32.",
163  "pointcloud"_a)
164  .def(
165  "deform",
166  [](ControlGrid &control_grid,
167  const geometry::PointCloud &pcd) {
168  return control_grid.Deform(pcd);
169  },
170  "Non-rigidly deform a point cloud using the control grid.",
171  "pointcloud"_a)
172  .def(
173  "deform",
174  [](ControlGrid &control_grid, const geometry::Image &depth,
175  const core::Tensor &intrinsics,
176  const core::Tensor &extrinsics, float depth_scale,
177  float depth_max) {
178  return control_grid.Deform(depth, intrinsics,
179  extrinsics, depth_scale,
180  depth_max);
181  },
182  "Non-rigidly deform a depth image by "
183  "\n- unprojecting the depth image to a point cloud "
184  "\n- deform the point cloud; "
185  "\n- project the deformed point cloud back to the image. ",
186  "depth"_a, "intrinsics"_a, "extrinsics"_a, "depth_scale"_a,
187  "depth_max"_a)
188  .def(
189  "deform",
190  [](ControlGrid &control_grid,
191  const geometry::RGBDImage &rgbd,
192  const core::Tensor &intrinsics,
193  const core::Tensor &extrinsics, float depth_scale,
194  float depth_max) {
195  return control_grid.Deform(rgbd, intrinsics, extrinsics,
196  depth_scale, depth_max);
197  },
198  "Non-rigidly deform a RGBD image by "
199  "\n- unprojecting the RGBD image to a point cloud "
200  "\n- deform the point cloud; "
201  "\n- project the deformed point cloud back to the image. ",
202  "rgbd"_a, "intrinsics"_a, "extrinsics"_a, "depth_scale"_a,
203  "depth_max"_a)
204  .def("get_init_positions", &ControlGrid::GetInitPositions,
205  "Get control grid original positions directly from tensor "
206  "keys.")
207  .def("get_curr_positions", &ControlGrid::GetCurrPositions,
208  "Get control grid shifted positions from tensor values "
209  "(optimized in-place)")
210  .def(
211  "get_hashmap",
212  [](ControlGrid &control_grid) {
213  return *control_grid.GetHashMap();
214  },
215  "Get the control grid hashmap.")
216  .def("size", &ControlGrid::Size)
217  .def("get_device", &ControlGrid::GetDevice)
218  .def("get_anchor_idx", &ControlGrid::GetAnchorIdx)
219  .def("__repr__", [](ControlGrid &control_grid) {
220  return fmt::format(
221  "ControlGrid[size={:d}, "
222  "anchor_idx={:d}].",
223  control_grid.Size(), control_grid.GetAnchorIdx());
224  });
225  m_slac.def(
226  "save_correspondences_for_pointclouds",
228  py::call_guard<py::gil_scoped_release>(),
229  "Read pose graph containing loop closures and odometry to compute "
230  "correspondences. Uses aggressive pruning -- reject any suspicious "
231  "pair.",
232  "fnames_processed"_a, "fragment_pose_graph"_a,
233  "params"_a = SLACOptimizerParams(),
234  "debug_option"_a = SLACDebugOption());
235  docstring::FunctionDocInject(m_slac, "save_correspondences_for_pointclouds",
237 
238  m_slac.def(
239  "run_slac_optimizer_for_fragments", &RunSLACOptimizerForFragments,
240  "Simultaneous Localization and Calibration: Self-Calibration of "
241  "Consumer Depth Cameras, CVPR 2014 Qian-Yi Zhou and Vladlen Koltun "
242  "Estimate a shared control grid for all fragments for scene "
243  "reconstruction, implemented in "
244  "https://github.com/qianyizh/ElasticReconstruction. ",
245  "fragment_filenames"_a, "fragment_pose_graph"_a,
246  "params"_a = SLACOptimizerParams(),
247  "debug_option"_a = SLACDebugOption());
248  docstring::FunctionDocInject(m_slac, "run_slac_optimizer_for_fragments",
250 
251  m_slac.def(
252  "run_rigid_optimizer_for_fragments", &RunRigidOptimizerForFragments,
253  "Extended ICP to simultaneously align multiple point clouds with "
254  "dense pairwise point-to-plane distances.",
255  "fragment_filenames"_a, "fragment_pose_graph"_a,
256  "params"_a = SLACOptimizerParams(),
257  "debug_option"_a = SLACDebugOption());
258  docstring::FunctionDocInject(m_slac, "run_rigid_optimizer_for_fragments",
260 }
261 
262 } // namespace slac
263 } // namespace pipelines
264 } // namespace t
265 } // namespace cloudViewer
filament::Texture::InternalFormat format
cmdLineReadable * params[]
The Image class stores image with customizable rows, cols, channels, dtype and device.
Definition: Image.h:29
A point cloud contains a list of 3D points.
Definition: PointCloud.h:82
RGBDImage A pair of color and depth images.
Definition: RGBDImage.h:21
core::Tensor GetInitPositions()
Get control grid original positions directly from tensor keys.
Definition: ControlGrid.h:104
std::tuple< core::Tensor, core::Tensor, core::Tensor > GetNeighborGridMap()
void FunctionDocInject(py::module &pybind_module, const std::string &function_name, const std::unordered_map< std::string, std::string > &map_parameter_body_docs)
Definition: docstring.cpp:76
void SaveCorrespondencesForPointClouds(const std::vector< std::string > &fnames_processed, const PoseGraph &pose_graph, const SLACOptimizerParams &params, const SLACDebugOption &debug_option)
Read pose graph containing loop closures and odometry to compute putative correspondences between pai...
PoseGraph RunRigidOptimizerForFragments(const std::vector< std::string > &fnames, const PoseGraph &pose_graph, const SLACOptimizerParams &params, const SLACDebugOption &debug_option)
Extended ICP to simultaneously align multiple point clouds with dense pairwise point-to-plane distanc...
static const std::unordered_map< std::string, std::string > map_shared_argument_docstrings
Definition: slac.cpp:24
std::pair< PoseGraph, ControlGrid > RunSLACOptimizerForFragments(const std::vector< std::string > &fnames, const PoseGraph &pose_graph, const SLACOptimizerParams &params, const SLACDebugOption &debug_option)
Simultaneous Localization and Calibration: Self-Calibration of Consumer Depth Cameras,...
void pybind_slac(py::module &m)
Definition: slac.cpp:35
Generic file read and write utility for python interface.
float distance_threshold_
Distance threshold to filter inconsistent correspondences.
Definition: SLACOptimizer.h:33
float regularizer_weight_
Weight of the regularizer.
Definition: SLACOptimizer.h:39
std::string slac_folder_
Relative directory to store SLAC results in the dataset folder.
Definition: SLACOptimizer.h:45
float fitness_threshold_
Fitness threshold to filter inconsistent pairs.
Definition: SLACOptimizer.h:36