ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
FillInLinearSystemImpl.h
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 
8 #pragma once
9 
10 #include <FileSystem.h>
11 
12 #include <fstream>
13 
17 
18 namespace cloudViewer {
19 namespace t {
20 namespace pipelines {
21 namespace slac {
22 
24 using core::Tensor;
26 
27 // Reads pointcloud from filename, and loads on the device as
28 // Tensor PointCloud of Float32 dtype.
30  const std::string& fname,
31  const core::Device& device = core::Device("CPU:0")) {
32  std::shared_ptr<cloudViewer::geometry::PointCloud> pcd =
34  return PointCloud::FromLegacy(*pcd, core::Float32, device);
35 }
36 
38  Tensor& Atb,
39  Tensor& residual,
40  PointCloud& tpcd_i,
41  PointCloud& tpcd_j,
42  const Tensor& Ti,
43  const Tensor& Tj,
44  const int i,
45  const int j,
46  const float threshold) {
47  tpcd_i.Transform(Ti);
48  tpcd_j.Transform(Tj);
49 
50  kernel::FillInRigidAlignmentTerm(AtA, Atb, residual,
51  tpcd_i.GetPointPositions(),
52  tpcd_j.GetPointPositions(),
53  tpcd_i.GetPointNormals(), i, j, threshold);
54 }
55 
57  Tensor& Atb,
58  Tensor& residual,
59  const std::vector<std::string>& fnames,
60  const PoseGraph& pose_graph,
62  const SLACDebugOption& debug_option) {
63  core::Device device(params.device_);
64 
65  // Enumerate pose graph edges
66  for (auto& edge : pose_graph.edges_) {
67  int i = edge.source_node_id_;
68  int j = edge.target_node_id_;
69 
70  std::string corres_fname = fmt::format("{}/{:03d}_{:03d}.npy",
71  params.GetSubfolderName(), i, j);
72  if (!utility::filesystem::FileExists(corres_fname)) {
73  utility::LogWarning("Correspondence {} {} skipped!", i, j);
74  continue;
75  }
76  Tensor corres_ij = Tensor::Load(corres_fname).To(device);
77  PointCloud tpcd_i = CreateTPCDFromFile(fnames[i], device);
78  PointCloud tpcd_j = CreateTPCDFromFile(fnames[j], device);
79 
80  PointCloud tpcd_i_indexed(
81  tpcd_i.GetPointPositions().IndexGet({corres_ij.T()[0]}));
82  tpcd_i_indexed.SetPointNormals(
83  tpcd_i.GetPointNormals().IndexGet({corres_ij.T()[0]}));
84  PointCloud tpcd_j_indexed(
85  tpcd_j.GetPointPositions().IndexGet({corres_ij.T()[1]}));
86 
87  Tensor Ti = EigenMatrixToTensor(pose_graph.nodes_[i].pose_)
88  .To(device, core::Float32);
89  Tensor Tj = EigenMatrixToTensor(pose_graph.nodes_[j].pose_)
90  .To(device, core::Float32);
91 
92  FillInRigidAlignmentTerm(AtA, Atb, residual, tpcd_i_indexed,
93  tpcd_j_indexed, Ti, Tj, i, j,
94  params.distance_threshold_);
95 
96  if (debug_option.debug_ && i >= debug_option.debug_start_node_idx_) {
97  VisualizePointCloudCorrespondences(tpcd_i, tpcd_j, corres_ij,
98  Tj.Inverse().Matmul(Ti));
99  }
100  }
101 }
102 
104  Tensor& Atb,
105  Tensor& residual,
106  ControlGrid& ctr_grid,
107  const PointCloud& tpcd_param_i,
108  const PointCloud& tpcd_param_j,
109  const Tensor& Ti,
110  const Tensor& Tj,
111  const int i,
112  const int j,
113  const int n_fragments,
114  const float threshold) {
115  // Parameterize: setup point cloud -> cgrid correspondences
116  Tensor cgrid_index_ps =
118  Tensor cgrid_ratio_ps =
120 
121  Tensor cgrid_index_qs =
123  Tensor cgrid_ratio_qs =
125 
126  // Deform with control grids
127  PointCloud tpcd_nonrigid_i = ctr_grid.Deform(tpcd_param_i);
128  PointCloud tpcd_nonrigid_j = ctr_grid.Deform(tpcd_param_j);
129 
130  Tensor Cps = tpcd_nonrigid_i.GetPointPositions();
131  Tensor Cqs = tpcd_nonrigid_j.GetPointPositions();
132  Tensor Cnormal_ps = tpcd_nonrigid_i.GetPointNormals();
133 
134  Tensor Ri = Ti.Slice(0, 0, 3).Slice(1, 0, 3);
135  Tensor ti = Ti.Slice(0, 0, 3).Slice(1, 3, 4);
136 
137  Tensor Rj = Tj.Slice(0, 0, 3).Slice(1, 0, 3);
138  Tensor tj = Tj.Slice(0, 0, 3).Slice(1, 3, 4);
139 
140  // Transform for required entries
141  Tensor Ti_Cps = (Ri.Matmul(Cps.T())).Add_(ti).T().Contiguous();
142  Tensor Tj_Cqs = (Rj.Matmul(Cqs.T())).Add_(tj).T().Contiguous();
143  Tensor Ri_Cnormal_ps = (Ri.Matmul(Cnormal_ps.T())).T().Contiguous();
144  Tensor RjT_Ri_Cnormal_ps =
145  (Rj.T().Matmul(Ri_Cnormal_ps.T())).T().Contiguous();
146 
148  AtA, Atb, residual, Ti_Cps, Tj_Cqs, Cnormal_ps, Ri_Cnormal_ps,
149  RjT_Ri_Cnormal_ps, cgrid_index_ps, cgrid_index_qs, cgrid_ratio_ps,
150  cgrid_ratio_qs, i, j, n_fragments, threshold);
151 }
152 
154  Tensor& Atb,
155  Tensor& residual,
156  ControlGrid& ctr_grid,
157  const std::vector<std::string>& fnames,
158  const PoseGraph& pose_graph,
160  const SLACDebugOption& debug_option) {
161  core::Device device(params.device_);
162  int n_frags = pose_graph.nodes_.size();
163 
164  // Enumerate pose graph edges.
165  for (auto& edge : pose_graph.edges_) {
166  int i = edge.source_node_id_;
167  int j = edge.target_node_id_;
168 
169  std::string corres_fname = fmt::format("{}/{:03d}_{:03d}.npy",
170  params.GetSubfolderName(), i, j);
171  if (!utility::filesystem::FileExists(corres_fname)) {
172  utility::LogWarning("Correspondence {} {} skipped!", i, j);
173  continue;
174  }
175  Tensor corres_ij = Tensor::Load(corres_fname).To(device);
176 
177  PointCloud tpcd_i = CreateTPCDFromFile(fnames[i], device);
178  PointCloud tpcd_j = CreateTPCDFromFile(fnames[j], device);
179 
180  PointCloud tpcd_i_indexed(
181  tpcd_i.GetPointPositions().IndexGet({corres_ij.T()[0]}));
182  tpcd_i_indexed.SetPointNormals(
183  tpcd_i.GetPointNormals().IndexGet({corres_ij.T()[0]}));
184 
185  PointCloud tpcd_j_indexed(
186  tpcd_j.GetPointPositions().IndexGet({corres_ij.T()[1]}));
187  tpcd_j_indexed.SetPointNormals(
188  tpcd_j.GetPointNormals().IndexGet({corres_ij.T()[1]}));
189 
190  // Parameterize points in the control grid.
191  PointCloud tpcd_param_i = ctr_grid.Parameterize(tpcd_i_indexed);
192  PointCloud tpcd_param_j = ctr_grid.Parameterize(tpcd_j_indexed);
193 
194  // Load poses.
195  auto Ti = EigenMatrixToTensor(pose_graph.nodes_[i].pose_)
196  .To(device, core::Float32);
197  auto Tj = EigenMatrixToTensor(pose_graph.nodes_[j].pose_)
198  .To(device, core::Float32);
199  auto Tij = EigenMatrixToTensor(edge.transformation_)
200  .To(device, core::Float32);
201 
202  // Fill In.
203  FillInSLACAlignmentTerm(AtA, Atb, residual, ctr_grid, tpcd_param_i,
204  tpcd_param_j, Ti, Tj, i, j, n_frags,
205  params.distance_threshold_);
206 
207  if (debug_option.debug_ && i >= debug_option.debug_start_node_idx_) {
208  VisualizePointCloudCorrespondences(tpcd_i, tpcd_j, corres_ij,
209  Tj.Inverse().Matmul(Ti));
210  VisualizePointCloudEmbedding(tpcd_param_i, ctr_grid);
211  VisualizePointCloudDeformation(tpcd_param_i, ctr_grid);
212  }
213  }
214 }
215 
217  Tensor& Atb,
218  Tensor& residual,
219  ControlGrid& ctr_grid,
220  int n_frags,
222  const SLACDebugOption& debug_option) {
223  Tensor active_buf_indices, nb_buf_indices, nb_masks;
224  std::tie(active_buf_indices, nb_buf_indices, nb_masks) =
225  ctr_grid.GetNeighborGridMap();
226 
227  Tensor positions_init = ctr_grid.GetInitPositions();
228  Tensor positions_curr = ctr_grid.GetCurrPositions();
229  kernel::FillInSLACRegularizerTerm(AtA, Atb, residual, active_buf_indices,
230  nb_buf_indices, nb_masks, positions_init,
231  positions_curr,
232  n_frags * params.regularizer_weight_,
233  n_frags, ctr_grid.GetAnchorIdx());
234  if (debug_option.debug_) {
235  VisualizeGridDeformation(ctr_grid);
236  }
237 }
238 
239 } // namespace slac
240 } // namespace pipelines
241 } // namespace t
242 } // namespace cloudViewer
filament::Texture::InternalFormat format
cmdLineReadable * params[]
Tensor Contiguous() const
Definition: Tensor.cpp:772
Tensor Matmul(const Tensor &rhs) const
Definition: Tensor.cpp:1919
Tensor Inverse() const
Definition: Tensor.cpp:1982
static Tensor Load(const std::string &file_name)
Load tensor from numpy's npy format.
Definition: Tensor.cpp:1881
Tensor IndexGet(const std::vector< Tensor > &index_tensors) const
Advanced indexing getter. This will always allocate a new Tensor.
Definition: Tensor.cpp:905
Tensor Add_(const Tensor &value)
Definition: Tensor.cpp:1117
Tensor T() const
Expects input to be <= 2-D Tensor by swapping dimension 0 and 1.
Definition: Tensor.cpp:1079
Tensor Slice(int64_t dim, int64_t start, int64_t stop, int64_t step=1) const
Definition: Tensor.cpp:857
Tensor To(Dtype dtype, bool copy=false) const
Definition: Tensor.cpp:739
Data structure defining the pose graph.
Definition: PoseGraph.h:96
std::vector< PoseGraphNode > nodes_
List of PoseGraphNode.
Definition: PoseGraph.h:108
std::vector< PoseGraphEdge > edges_
List of PoseGraphEdge.
Definition: PoseGraph.h:111
A point cloud contains a list of 3D points.
Definition: PointCloud.h:82
void SetPointNormals(const core::Tensor &value)
Set the value of the "normals" attribute. Convenience function.
Definition: PointCloud.h:198
core::Tensor & GetPointNormals()
Get the value of the "normals" attribute. Convenience function.
Definition: PointCloud.h:130
static PointCloud FromLegacy(const cloudViewer::geometry::PointCloud &pcd_legacy, core::Dtype dtype=core::Float32, const core::Device &device=core::Device("CPU:0"))
Create a PointCloud from a legacy CloudViewer PointCloud.
core::Tensor & GetPointPositions()
Get the value of the "positions" attribute. Convenience function.
Definition: PointCloud.h:124
const TensorMap & GetPointAttr() const
Getter for point_attr_ TensorMap. Used in Pybind.
Definition: PointCloud.h:111
PointCloud & Transform(const core::Tensor &transformation)
Transforms the PointPositions and PointNormals (if exist) of the PointCloud.
Definition: PointCloud.cpp:171
static const std::string kGrid8NbVertexInterpRatios
8 neighbor grid interpolation ratio for vertex per point.
Definition: ControlGrid.h:36
static const std::string kGrid8NbIndices
Definition: ControlGrid.h:34
geometry::PointCloud Deform(const geometry::PointCloud &pcd)
Non-rigidly deform a point cloud using the control grid.
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()
geometry::PointCloud Parameterize(const geometry::PointCloud &pcd)
#define LogWarning(...)
Definition: Logging.h:72
core::Tensor EigenMatrixToTensor(const Eigen::MatrixBase< Derived > &matrix)
Converts a eigen matrix of shape (M, N) with alignment A and type T to a tensor.
const Dtype Float32
Definition: Dtype.cpp:42
::ccPointCloud PointCloud
Definition: PointCloud.h:19
std::shared_ptr< ccPointCloud > CreatePointCloudFromFile(const std::string &filename, const std::string &format, bool print_progress)
void FillInRigidAlignmentTerm(core::Tensor &AtA, core::Tensor &Atb, core::Tensor &residual, const core::Tensor &Ti_ps, const core::Tensor &Tj_qs, const core::Tensor &Ri_normal_ps, int i, int j, float threshold)
void FillInSLACRegularizerTerm(core::Tensor &AtA, core::Tensor &Atb, core::Tensor &residual, const core::Tensor &grid_idx, const core::Tensor &grid_nbs_idx, const core::Tensor &grid_nbs_mask, const core::Tensor &positions_init, const core::Tensor &positions_curr, float weight, int n, int anchor_idx)
void FillInSLACAlignmentTerm(core::Tensor &AtA, core::Tensor &Atb, core::Tensor &residual, const core::Tensor &Ti_ps, const core::Tensor &Tj_qs, const core::Tensor &normal_ps, const core::Tensor &Ri_normal_ps, const core::Tensor &RjT_Ri_normal_ps, const core::Tensor &cgrid_idx_ps, const core::Tensor &cgrid_idx_qs, const core::Tensor &cgrid_ratio_qs, const core::Tensor &cgrid_ratio_ps, int i, int j, int n, float threshold)
void VisualizePointCloudEmbedding(t::geometry::PointCloud &tpcd_param, ControlGrid &ctr_grid, bool show_lines)
static PointCloud CreateTPCDFromFile(const std::string &fname, const core::Device &device=core::Device("CPU:0"))
void VisualizePointCloudCorrespondences(const t::geometry::PointCloud &tpcd_i, const t::geometry::PointCloud &tpcd_j, const core::Tensor correspondences, const core::Tensor &T_ij)
Visualize pairs with correspondences.
static void FillInSLACAlignmentTerm(Tensor &AtA, Tensor &Atb, Tensor &residual, ControlGrid &ctr_grid, const PointCloud &tpcd_param_i, const PointCloud &tpcd_param_j, const Tensor &Ti, const Tensor &Tj, const int i, const int j, const int n_fragments, const float threshold)
void VisualizeGridDeformation(ControlGrid &cgrid)
void VisualizePointCloudDeformation(const geometry::PointCloud &tpcd_param, ControlGrid &ctr_grid)
void FillInSLACRegularizerTerm(Tensor &AtA, Tensor &Atb, Tensor &residual, ControlGrid &ctr_grid, int n_frags, const SLACOptimizerParams &params, const SLACDebugOption &debug_option)
static void FillInRigidAlignmentTerm(Tensor &AtA, Tensor &Atb, Tensor &residual, PointCloud &tpcd_i, PointCloud &tpcd_j, const Tensor &Ti, const Tensor &Tj, const int i, const int j, const float threshold)
bool FileExists(const std::string &filename)
Definition: FileSystem.cpp:524
Generic file read and write utility for python interface.