ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
TransformationConverter.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 <cmath>
13 
19 
20 namespace cloudViewer {
21 namespace t {
22 namespace pipelines {
23 namespace kernel {
24 
26  core::AssertTensorShape(R, {3, 3});
29 
30  const core::Device device = R.GetDevice();
31  const core::Dtype dtype = R.GetDtype();
32 
33  core::AssertTensorDtype(t, dtype);
34  core::AssertTensorDevice(t, device);
35 
36  core::Tensor transformation = core::Tensor::Zeros({4, 4}, dtype, device);
37 
38  // Rotation.
39  transformation.SetItem(
41  R);
42  // Translation.
43  transformation.SetItem(
45  t.Reshape({3, 1}));
46  // Scale [assumed to be 1].
47  transformation[3][3] = 1;
48  return transformation;
49 }
50 
51 template <typename scalar_t>
53  core::Tensor &transformation,
54  const core::Tensor &pose,
55  const core::Device::DeviceType &device_type) {
56  scalar_t *transformation_ptr = transformation.GetDataPtr<scalar_t>();
57  const scalar_t *pose_ptr = pose.GetDataPtr<scalar_t>();
58 
59  if (device_type == core::Device::DeviceType::CPU) {
60  PoseToTransformationImpl<scalar_t>(transformation_ptr, pose_ptr);
61  } else if (device_type == core::Device::DeviceType::CUDA) {
62 #ifdef BUILD_CUDA_MODULE
63  core::CUDAScopedDevice scoped_device(transformation.GetDevice());
64  PoseToTransformationCUDA<scalar_t>(transformation_ptr, pose_ptr);
65 #else
66  utility::LogError("Not compiled with CUDA, but CUDA device is used.");
67 #endif
68  } else {
69  utility::LogError("Unimplemented device.");
70  }
71 }
72 
74  core::AssertTensorShape(pose, {6});
76 
77  const core::Device device = pose.GetDevice();
78  const core::Dtype dtype = pose.GetDtype();
79  core::Tensor transformation = core::Tensor::Zeros({4, 4}, dtype, device);
80  transformation = transformation.Contiguous();
81  core::Tensor pose_ = pose.Contiguous();
82 
84  core::Device::DeviceType device_type = device.GetType();
85  PoseToTransformationDevice<scalar_t>(transformation, pose_,
86  device_type);
87  });
88 
89  // Translation from pose.
90  transformation.SetItem(
92  pose_.GetItem({core::TensorKey::Slice(3, 6, 1)}).Reshape({3, 1}));
93  // Scale [assumed to be 1].
94  transformation[3][3] = 1;
95  return transformation;
96 }
97 
98 template <typename scalar_t>
100  core::Tensor &pose,
101  const core::Tensor &transformation,
102  const core::Device::DeviceType &device_type) {
103  scalar_t *pose_ptr = pose.GetDataPtr<scalar_t>();
104  const scalar_t *transformation_ptr = transformation.GetDataPtr<scalar_t>();
105 
106  if (device_type == core::Device::DeviceType::CPU) {
107  TransformationToPoseImpl<scalar_t>(pose_ptr, transformation_ptr);
108  } else if (device_type == core::Device::DeviceType::CUDA) {
109 #ifdef BUILD_CUDA_MODULE
110  TransformationToPoseCUDA<scalar_t>(pose_ptr, transformation_ptr);
111 #else
112  utility::LogError("Not compiled with CUDA, but CUDA device is used.");
113 #endif
114  } else {
115  utility::LogError("Unimplemented device.");
116  }
117 }
118 
120  core::AssertTensorShape(transformation, {4, 4});
122 
123  const core::Device device = transformation.GetDevice();
124  const core::Dtype dtype = transformation.GetDtype();
125  core::Tensor pose = core::Tensor::Zeros({6}, dtype, device);
126  pose = pose.Contiguous();
127  core::Tensor transformation_ = transformation.Contiguous();
128 
129  DISPATCH_FLOAT_DTYPE_TO_TEMPLATE(dtype, [&]() {
130  core::Device::DeviceType device_type = device.GetType();
131  TransformationToPoseDevice<scalar_t>(pose, transformation_,
132  device_type);
133  });
134 
135  // Set translation parameters in pose vector.
136  pose.SetItem(core::TensorKey::Slice(3, 6, 1),
137  transformation_
138  .GetItem({core::TensorKey::Slice(0, 3, 1),
139  core::TensorKey::Slice(3, 4, 1)})
140  .Flatten());
141 
142  return pose;
143 }
144 
145 void DecodeAndSolve6x6(const core::Tensor &A_reduction,
146  core::Tensor &delta,
147  float &inlier_residual,
148  int &inlier_count) {
149  const core::Device host(core::Device("CPU:0"));
150  core::Tensor A_1x29_host = A_reduction.To(host, core::Float64);
151  core::AssertTensorShape(A_reduction, {29});
152 
153  double *A_1x29_ptr = A_1x29_host.GetDataPtr<double>();
154 
155  core::Tensor AtA = core::Tensor::Empty({6, 6}, core::Float64, host);
157 
158  double *AtA_local_ptr = AtA.GetDataPtr<double>();
159  double *Atb_local_ptr = Atb.GetDataPtr<double>();
160 
161  for (int j = 0; j < 6; j++) {
162  Atb_local_ptr[j] = A_1x29_ptr[21 + j];
163  const int64_t reduction_idx = ((j * (j + 1)) / 2);
164  for (int k = 0; k <= j; k++) {
165  AtA_local_ptr[j * 6 + k] = A_1x29_ptr[reduction_idx + k];
166  AtA_local_ptr[k * 6 + j] = A_1x29_ptr[reduction_idx + k];
167  }
168  }
169 
170  // Solve on CPU with double to ensure precision.
171  try {
172  delta = AtA.Solve(Atb.Neg());
173  inlier_residual = A_1x29_ptr[27];
174  inlier_count = static_cast<int>(A_1x29_ptr[28]);
175  } catch (const std::runtime_error &) {
177  "Singular 6x6 linear system detected, tracking failed.");
178  delta.Fill(0);
179  inlier_residual = 0;
180  inlier_count = 0;
181  }
182 }
183 
184 } // namespace kernel
185 } // namespace pipelines
186 } // namespace t
187 } // namespace cloudViewer
Common CUDA utilities.
#define DISPATCH_FLOAT_DTYPE_TO_TEMPLATE(DTYPE,...)
Definition: Dispatch.h:78
#define AssertTensorDevice(tensor,...)
Definition: TensorCheck.h:45
#define AssertTensorDtype(tensor,...)
Definition: TensorCheck.h:21
#define AssertTensorDtypes(tensor,...)
Definition: TensorCheck.h:33
#define AssertTensorShape(tensor,...)
Definition: TensorCheck.h:61
When CUDA is not enabled, this is a dummy class.
Definition: CUDAUtils.h:214
DeviceType
Type for device.
Definition: Device.h:21
static TensorKey Slice(utility::optional< int64_t > start, utility::optional< int64_t > stop, utility::optional< int64_t > step)
Definition: TensorKey.cpp:138
Tensor Solve(const Tensor &rhs) const
Definition: Tensor.cpp:1928
Tensor Contiguous() const
Definition: Tensor.cpp:772
Dtype GetDtype() const
Definition: Tensor.h:1164
Tensor GetItem(const TensorKey &tk) const
Definition: Tensor.cpp:473
Tensor SetItem(const Tensor &value)
Set all items. Equivalent to tensor[:] = value in Python.
Definition: Tensor.cpp:564
static Tensor Zeros(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with zeros.
Definition: Tensor.cpp:406
Device GetDevice() const override
Definition: Tensor.cpp:1435
Tensor Reshape(const SizeVector &dst_shape) const
Definition: Tensor.cpp:671
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
Definition: Tensor.cpp:400
void Fill(S v)
Fill the whole Tensor with a scalar value, the scalar will be casted to the Tensor's Dtype.
Definition: Tensor.h:1400
Tensor To(Dtype dtype, bool copy=false) const
Definition: Tensor.cpp:739
#define LogError(...)
Definition: Logging.h:60
const Dtype Float64
Definition: Dtype.cpp:43
const Dtype Float32
Definition: Dtype.cpp:42
core::Tensor RtToTransformation(const core::Tensor &R, const core::Tensor &t)
Convert rotation and translation to the transformation matrix.
static void TransformationToPoseDevice(core::Tensor &pose, const core::Tensor &transformation, const core::Device::DeviceType &device_type)
void DecodeAndSolve6x6(const core::Tensor &A_reduction, core::Tensor &delta, float &inlier_residual, int &inlier_count)
Decodes a 6x6 linear system from a compressed 29x1 tensor.
core::Tensor TransformationToPose(const core::Tensor &transformation)
Convert transformation matrix to pose.
static void PoseToTransformationDevice(core::Tensor &transformation, const core::Tensor &pose, const core::Device::DeviceType &device_type)
core::Tensor PoseToTransformation(const core::Tensor &pose)
Convert pose to the transformation matrix.
Generic file read and write utility for python interface.