CortidQCT  1.2.2.52
Sampler.h
Go to the documentation of this file.
1 
12 #pragma once
13 
14 #include "MeasurementModel.h"
15 #include "VoxelVolume.h"
16 
17 #include <Eigen/Core>
18 #include <gsl/gsl>
19 
20 namespace CortidQCT {
21 
22 #pragma clang diagnostic push
23 #pragma clang diagnostic ignored "-Wpadded"
25 
26 public:
27  VoxelVolume::ValueType outside;
28 
29  inline explicit VolumeSampler(
30  VoxelVolume const &vol,
31  VoxelVolume::ValueType outside_ = VoxelVolume::ValueType{0}) noexcept
32  : outside{outside_}, volume_{vol} {}
33 
34  template <class Derived, class DerivedOut>
35  inline void operator()(Eigen::MatrixBase<Derived> const &positions,
36  Eigen::MatrixBase<DerivedOut> &values) const {
37  using Eigen::Vector3f;
38 
39  Expects(values.rows() == positions.rows());
40  Expects(positions.cols() == 3);
41 
42  Vector3f const scale{1.f / volume_.voxelSize().width,
43  1.f / volume_.voxelSize().height,
44  1.f / volume_.voxelSize().depth};
45 
46  volume_.withUnsafeDataPointer(
47  [this, &positions, &values, scale](auto const *ptr) {
48 
49 #pragma omp parallel for
50  for (Eigen::Index i = 0; i < positions.rows(); ++i) {
51 
52  values(i) = this->interpolate(
53  (positions.row(i).array() * scale.array().transpose())
54  .matrix()
55  .transpose(),
56  gsl::make_not_null(ptr));
57  }
58  });
59  }
60 
61  template <class Derived>
62  inline Eigen::Matrix<VoxelVolume::ValueType, Eigen::Dynamic, 1>
63  operator()(Eigen::MatrixBase<Derived> const &positions) const {
64  Eigen::Matrix<VoxelVolume::ValueType, Eigen::Dynamic, 1> values(
65  positions.rows());
66 
67  operator()(positions, values);
68 
69  return values;
70  }
71 
72 private:
73  template <class Derived>
75  at(Eigen::MatrixBase<Derived> const &pos,
76  gsl::not_null<VoxelVolume::ValueType const *> ptr) const {
77  auto const &size = volume_.size();
78 
79  auto const isInside = (pos.array() >= 0).all() &&
80  pos(0) < gsl::narrow_cast<int>(size.width) &&
81  pos(1) < gsl::narrow_cast<int>(size.height) &&
82  pos(2) < gsl::narrow_cast<int>(size.depth);
83 
84  auto const index =
85  gsl::narrow_cast<std::size_t>(pos(2)) * size.width * size.height +
86  gsl::narrow_cast<std::size_t>(pos(1)) * size.width +
87  gsl::narrow_cast<std::size_t>(pos(0));
88 
89  return isInside ? ptr.get()[index] : outside;
90  }
91 
92  template <class Derived>
93  inline auto
94  interpolate(Eigen::MatrixBase<Derived> const &pos,
95  gsl::not_null<VoxelVolume::ValueType const *> ptr) const {
96 
97  using Value = VoxelVolume::ValueType;
98  using Eigen::Vector3f;
99  using Eigen::Vector3i;
100  using gsl::make_not_null;
101 
102  Vector3i const x0 = pos.array().floor().matrix().template cast<int>();
103  Vector3i const x1 = pos.array().ceil().matrix().template cast<int>();
104  Vector3f const xd = pos - x0.cast<float>();
105  Vector3f const xn = Vector3f::Ones() - xd;
106 
107  // get values of lattice points
108  Value const c000 = at(x0, ptr);
109  Value const c001 = at(Vector3i{x0(0), x0(1), x1(2)}, ptr);
110  Value const c010 = at(Vector3i{x0(0), x1(1), x0(2)}, ptr);
111  Value const c011 = at(Vector3i{x0(0), x1(1), x1(2)}, ptr);
112  Value const c100 = at(Vector3i{x1(0), x0(1), x0(2)}, ptr);
113  Value const c101 = at(Vector3i{x1(0), x0(1), x1(2)}, ptr);
114  Value const c110 = at(Vector3i{x1(0), x1(1), x0(2)}, ptr);
115  Value const c111 = at(x1, ptr);
116 
117  auto const c00 = c000 * xn(0) + c100 * xd(0);
118  auto const c01 = c001 * xn(0) + c101 * xd(0);
119  auto const c10 = c010 * xn(0) + c110 * xd(0);
120  auto const c11 = c011 * xn(0) + c111 * xd(0);
121 
122  auto const c0 = c00 * xn(1) + c10 * xd(1);
123  auto const c1 = c01 * xn(1) + c11 * xd(1);
124 
125  auto const c = c0 * xn(2) + c1 * xd(2);
126 
127  return c;
128  }
129 
130  VoxelVolume const &volume_;
131 };
132 
134 
135 public:
136  inline explicit ModelSampler(MeasurementModel const &model) noexcept
137  : model_(model) {}
138 
139  template <class DerivedIn, class VectorOut>
140  inline void operator()(Eigen::MatrixBase<DerivedIn> const &positions,
141  float offset, VectorOut &&values) const {
142  using Eigen::Dynamic;
143  using Eigen::Matrix;
144  using Eigen::Vector3f;
145 
146  Expects(values.rows() == positions.rows());
147  Expects(positions.cols() == 4);
148  Expects(values.cols() == 1);
149 
150  Vector3f const min{model_.samplingRange.min, model_.densityRange.min,
151  model_.angleRange.min};
152  Vector3f const scale{1.f / model_.samplingRange.stride,
153  1.f / model_.densityRange.stride,
154  1.f / model_.angleRange.stride};
155 
156  for (auto &&label : model_.labels()) {
157  model_.withUnsafeDataPointer(label, [this, &positions, &values, min,
158  scale, offset,
159  label](float const *ptr) {
160  for (Eigen::Index i = 0; i < positions.rows(); ++i) {
161  if (static_cast<MeasurementModel::Label>(positions(i, 3)) != label) {
162  continue;
163  }
164 
165  Vector3f const position{positions(i, 0) + offset, positions(i, 1),
166  positions(i, 2)};
167  values(i) = this->interpolate(
168  ((position - min).array() * scale.array()).matrix(), ptr);
169  }
170  });
171  }
172  }
173 
174  template <class Derived>
175  inline Eigen::Matrix<float, Eigen::Dynamic, 1>
176  operator()(Eigen::MatrixBase<Derived> const &positions, float offset) const {
177  Eigen::Matrix<float, Eigen::Dynamic, 1> values(positions.rows());
178 
179  operator()(positions, offset, values);
180 
181  return values;
182  }
183 
184 private:
185  inline float at(int x, int y, int z, Eigen::Vector3i const &sizeI,
186  float const *ptr) const {
187 
188  auto const index = x * sizeI.y() * sizeI.z() + z * sizeI.y() + y;
189  return ptr[index];
190  }
191 
192  template <class Derived>
193  inline float interpolate(Eigen::MatrixBase<Derived> const &pos,
194  float const *ptr) const {
195  using Eigen::Vector3f;
196  using Eigen::Vector3i;
197  using std::clamp;
198  using std::log;
199 
200  Vector3i const sizeI{static_cast<int>(model_.samplingRange.numElements()),
201  static_cast<int>(model_.densityRange.numElements()),
202  static_cast<int>(model_.angleRange.numElements())};
203 
204  auto const x00 = clamp(static_cast<int>(pos(0)), 0, sizeI.x() - 1);
205  auto const x01 = clamp(static_cast<int>(pos(2) + 0.5f), 0, sizeI.z() - 1);
206  auto const x0 = static_cast<int>(pos(1));
207  auto const x1 = x0 + 1;
208  auto const xd = pos(1) - static_cast<float>(x0);
209  auto const xn = 1.f - xd;
210 
211  auto const c0 = at(x00, clamp(x0, 0, sizeI.y() - 1), x01, sizeI, ptr);
212  auto const c1 = at(x00, clamp(x1, 0, sizeI.y() - 1), x01, sizeI, ptr);
213 
214  auto const c = c0 * xn + c1 * xd;
215 
216  return log(c);
217  }
218 
219  MeasurementModel const &model_;
220 };
221 #pragma clang diagnostic pop
222 
223 } // namespace CortidQCT
Name namespace for CortidQCT library.
Definition: CortidQCT.h:23
VolumeSize const & size() const noexcept
Returns the volume size.
Definition: VoxelVolume.h:76
VoxelSize const & voxelSize() const noexcept
Returns the voxel size.
Definition: VoxelVolume.h:79
Type representing a voxel volume.
Definition: VoxelVolume.h:32
Type representing the measurement model.
Definition: MeasurementModel.h:33
float depth
Size along the z-axis.
Definition: VoxelSize.h:28
float width
Size along the x-axis.
Definition: VoxelSize.h:24
Definition: Sampler.h:133
auto withUnsafeDataPointer(F &&f) const noexcept(noexcept(f(std::declval< VoxelData >().data())))
Calls the given functional with an unsafe pointer to the raw voxel storage.
Definition: VoxelVolume.h:108
Definition: Sampler.h:24
This header contains the definition of the MeasurementModel type.
This header contains the definition of the VoxelVolume type.
float height
Size along the y-axis.
Definition: VoxelSize.h:26
float ValueType
Voxel value type.
Definition: VoxelVolume.h:35