ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
EigenConverter.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 <type_traits>
11 
15 
16 namespace cloudViewer {
17 namespace core {
18 namespace eigen_converter {
19 
27 template <typename func_t>
28 static void LaunchIndexFillKernel(const Indexer &indexer, const func_t &func) {
29  ParallelFor(Device("CPU:0"), indexer.NumWorkloads(),
30  [&indexer, &func](int64_t i) {
31  func(indexer.GetInputPtr(0, i), i);
32  });
33 }
34 
35 template <typename T>
36 static Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
38  static_assert(std::is_same<T, double>::value ||
39  std::is_same<T, float>::value ||
40  std::is_same<T, int>::value,
41  "Only supports double, float and int (MatrixXd, MatrixXf and "
42  "MatrixXi).");
43  core::Dtype dtype = core::Dtype::FromType<T>();
44 
45  core::SizeVector dim = tensor.GetShape();
46  if (dim.size() != 2) {
48  " [TensorToEigenMatrix]: Number of dimensions supported = 2, "
49  "but got {}.",
50  dim.size());
51  }
52 
53  core::Tensor tensor_cpu_contiguous =
54  tensor.Contiguous().To(core::Device("CPU:0"), dtype);
55  T *data_ptr = tensor_cpu_contiguous.GetDataPtr<T>();
56 
57  Eigen::Map<
58  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>
59  eigen_matrix(data_ptr, dim[0], dim[1]);
60 
61  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
62  eigen_matrix_copy(eigen_matrix);
63  return eigen_matrix_copy;
64 }
65 
66 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
68  return TensorToEigenMatrix<double>(tensor);
69 }
70 
71 Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
73  return TensorToEigenMatrix<float>(tensor);
74 }
75 
76 Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
78  return TensorToEigenMatrix<int>(tensor);
79 }
80 
81 template <typename T, int N>
82 static std::vector<Eigen::Matrix<T, N, 1>> TensorToEigenVectorNxVector(
83  const core::Tensor &tensor) {
84  AssertTensorShape(tensor, {utility::nullopt, N});
85 
86  static_assert(
87  (std::is_same<T, double>::value || std::is_same<T, int>::value) &&
88  N > 0,
89  "Only supports double and int (VectorNd and VectorNi) with N>0.");
90  core::Dtype dtype;
91  if (std::is_same<T, double>::value) {
92  dtype = core::Float64;
93  } else if (std::is_same<T, int>::value) {
94  dtype = core::Int32;
95  }
96  if (dtype.ByteSize() * N != sizeof(Eigen::Matrix<T, N, 1>)) {
97  utility::LogError("Internal error: dtype size mismatch {} != {}.",
98  dtype.ByteSize() * N, sizeof(Eigen::Matrix<T, N, 1>));
99  }
100 
101  // Eigen::VectorNx is not a "fixed-size vectorizable Eigen type" thus it is
102  // safe to write directly into std vector memory, see:
103  // https://eigen.tuxfamily.org/dox/group__TopicStlContainers.html.
104  std::vector<Eigen::Matrix<T, N, 1>> eigen_vector(tensor.GetLength());
105  const core::Tensor t = tensor.To(dtype).Contiguous();
106  MemoryManager::MemcpyToHost(eigen_vector.data(), t.GetDataPtr(),
107  t.GetDevice(),
108  t.GetDtype().ByteSize() * t.NumElements());
109  return eigen_vector;
110 }
111 
112 template <typename T, int N>
114  const std::vector<Eigen::Matrix<T, N, 1>> &values,
115  core::Dtype dtype,
116  const core::Device &device) {
117  // Unlike TensorToEigenVector3NVector, more types can be supported here. To
118  // keep consistency, we only allow double and int.
119  static_assert(
120  (std::is_same<T, double>::value || std::is_same<T, int>::value) &&
121  N > 0,
122  "Only supports double and int (VectorNd and VectorNi) with N>0.");
123  // Init CPU Tensor.
124  int64_t num_values = static_cast<int64_t>(values.size());
125  core::Tensor tensor_cpu =
126  core::Tensor::Empty({num_values, N}, dtype, Device("CPU:0"));
127 
128  // Fill Tensor. This takes care of dtype conversion at the same time.
129  core::Indexer indexer({tensor_cpu}, tensor_cpu,
131  DISPATCH_DTYPE_TO_TEMPLATE(dtype, [&]() {
132  LaunchIndexFillKernel(indexer, [&](void *ptr, int64_t workload_idx) {
133  // Fills the flattened tensor tensor_cpu[:] with dtype
134  // casting. tensor_cpu[:][i] corresponds to the (i/N)-th
135  // element's (i%N)-th coordinate value.
136  *static_cast<scalar_t *>(ptr) = static_cast<scalar_t>(
137  values[workload_idx / N](workload_idx % N));
138  });
139  });
140 
141  // Copy Tensor to device if necessary.
142  return tensor_cpu.To(device);
143 }
144 
145 std::vector<Eigen::Vector2d> TensorToEigenVector2dVector(
146  const core::Tensor &tensor) {
147  return TensorToEigenVectorNxVector<double, 2>(tensor);
148 }
149 
150 std::vector<Eigen::Vector3d> TensorToEigenVector3dVector(
151  const core::Tensor &tensor) {
152  return TensorToEigenVectorNxVector<double, 3>(tensor);
153 }
154 
155 std::vector<Eigen::Vector3i> TensorToEigenVector3iVector(
156  const core::Tensor &tensor) {
157  return TensorToEigenVectorNxVector<int, 3>(tensor);
158 }
159 
160 std::vector<Eigen::Vector2i> TensorToEigenVector2iVector(
161  const core::Tensor &tensor) {
162  return TensorToEigenVectorNxVector<int, 2>(tensor);
163 }
164 
166  const std::vector<Eigen::Vector3d> &values,
167  core::Dtype dtype,
168  const core::Device &device) {
169  return EigenVectorNxVectorToTensor(values, dtype, device);
170 }
171 
173  const std::vector<Eigen::Vector2d> &values,
174  core::Dtype dtype,
175  const core::Device &device) {
176  return EigenVectorNxVectorToTensor(values, dtype, device);
177 }
178 
180  const std::vector<Eigen::Vector3i> &values,
181  core::Dtype dtype,
182  const core::Device &device) {
183  return EigenVectorNxVectorToTensor(values, dtype, device);
184 }
186  const std::vector<Eigen::Vector2i> &values,
187  core::Dtype dtype,
188  const core::Device &device) {
189  return EigenVectorNxVectorToTensor(values, dtype, device);
190 }
191 
192 } // namespace eigen_converter
193 } // namespace core
194 } // namespace cloudViewer
Indexer indexer
#define DISPATCH_DTYPE_TO_TEMPLATE(DTYPE,...)
Definition: Dispatch.h:31
#define AssertTensorShape(tensor,...)
Definition: TensorCheck.h:61
int64_t ByteSize() const
Definition: Dtype.h:59
static void MemcpyToHost(void *host_ptr, const void *src_ptr, const Device &src_device, size_t num_bytes)
Same as Memcpy, but with host (CPU:0) as default dst_device.
Tensor Contiguous() const
Definition: Tensor.cpp:772
int64_t GetLength() const
Definition: Tensor.h:1125
Dtype GetDtype() const
Definition: Tensor.h:1164
int64_t NumElements() const
Definition: Tensor.h:1170
Device GetDevice() const override
Definition: Tensor.cpp:1435
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
Definition: Tensor.cpp:400
SizeVector GetShape() const
Definition: Tensor.h:1127
Tensor To(Dtype dtype, bool copy=false) const
Definition: Tensor.cpp:739
#define LogError(...)
Definition: Logging.h:60
static Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > TensorToEigenMatrix(const core::Tensor &tensor)
static core::Tensor EigenVectorNxVectorToTensor(const std::vector< Eigen::Matrix< T, N, 1 >> &values, core::Dtype dtype, const core::Device &device)
std::vector< Eigen::Vector2i > TensorToEigenVector2iVector(const core::Tensor &tensor)
Converts a tensor of shape (N, 2) to std::vector<Eigen::Vector2i>. An exception will be thrown if the...
core::Tensor EigenVector2iVectorToTensor(const std::vector< Eigen::Vector2i > &values, core::Dtype dtype, const core::Device &device)
Converts a vector of Eigen::Vector2i to a (N, 2) tensor. This function also takes care of dtype conve...
static std::vector< Eigen::Matrix< T, N, 1 > > TensorToEigenVectorNxVector(const core::Tensor &tensor)
Eigen::Matrix< int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > TensorToEigenMatrixXi(const core::Tensor &tensor)
Converts a 2D tensor to Eigen::MatrixXi of same shape. Regardless of the tensor dtype,...
std::vector< Eigen::Vector2d > TensorToEigenVector2dVector(const core::Tensor &tensor)
Converts a tensor of shape (N, 2) to std::vector<Eigen::Vector2d>. An exception will be thrown if the...
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > TensorToEigenMatrixXf(const core::Tensor &tensor)
Converts a 2D tensor to Eigen::MatrixXf of same shape. Regardless of the tensor dtype,...
std::vector< Eigen::Vector3d > TensorToEigenVector3dVector(const core::Tensor &tensor)
Converts a tensor of shape (N, 3) to std::vector<Eigen::Vector3d>. An exception will be thrown if the...
core::Tensor EigenVector3dVectorToTensor(const std::vector< Eigen::Vector3d > &values, core::Dtype dtype, const core::Device &device)
Converts a vector of Eigen::Vector3d to a (N, 3) tensor. This function also takes care of dtype conve...
std::vector< Eigen::Vector3i > TensorToEigenVector3iVector(const core::Tensor &tensor)
Converts a tensor of shape (N, 3) to std::vector<Eigen::Vector3i>. An exception will be thrown if the...
static void LaunchIndexFillKernel(const Indexer &indexer, const func_t &func)
core::Tensor EigenVector2dVectorToTensor(const std::vector< Eigen::Vector2d > &values, core::Dtype dtype, const core::Device &device)
Converts a vector of Eigen::Vector2d to a (N, 2) tensor. This function also takes care of dtype conve...
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > TensorToEigenMatrixXd(const core::Tensor &tensor)
Converts a 2D tensor to Eigen::MatrixXd of same shape. Regardless of the tensor dtype,...
core::Tensor EigenVector3iVectorToTensor(const std::vector< Eigen::Vector3i > &values, core::Dtype dtype, const core::Device &device)
Converts a vector of Eigen::Vector3i to a (N, 3) tensor. This function also takes care of dtype conve...
void ParallelFor(const Device &device, int64_t n, const func_t &func)
Definition: ParallelFor.h:111
const Dtype Float64
Definition: Dtype.cpp:43
const Dtype Int32
Definition: Dtype.cpp:46
constexpr nullopt_t nullopt
Definition: Optional.h:136
Generic file read and write utility for python interface.