VoxelGrid.cpp
Go to the documentation of this file.
1 #include "VoxelGrid.h"
2 
3 #include "../utils.h"
4 
6 
7 #include <SimoxUtility/algorithm/string/string_tools.h>
8 
9 #include <algorithm>
10 
11 
13 {
14 
15  bool Voxel::isFree() const
16  {
17  return empty() || getTotal() == 0;
18  }
19 
20  std::size_t Voxel::getTotal() const
21  {
22  std::size_t sum = 0;
23  for (const auto& [_, num] : *this)
24  {
25  sum += num;
26  }
27  return sum;
28  }
29 
30  std::map<Label, float> Voxel::getDensity() const
31  {
32  const float total = static_cast<float>(getTotal());
33 
34  std::map<Label, float> density;
35  for (const auto& [label, num] : *this)
36  {
37  density[label] = total > 0.f ? num / total : 0.f;;
38  }
39  return density;
40  }
41 
43  {
44  return getMax().first;
45  }
46 
47  std::pair<Label, std::size_t> Voxel::getMax() const
48  {
49  return *std::max_element(begin(), end());
50  }
51 
52  bool Voxel::operator==(const Voxel& rhs) const
53  {
54  // Collect labels to compare.
55  std::set<Label> labels;
56  for (const Voxel* voxel :
57  {
58  this, &rhs
59  })
60  {
61  for (const auto& [label, num] : *voxel)
62  {
63  if (num > 0) // No need to compare entries with count 0.
64  {
65  labels.insert(label);
66  }
67  }
68  }
69  for (Label label : labels)
70  {
71  if ((*this).at(label) != rhs.at(label))
72  {
73  return false;
74  }
75  }
76  return true;
77  }
78 
79  bool Voxel::operator!=(const Voxel& rhs) const
80  {
81  return !(*this == rhs);
82  }
83 
84  std::ostream& operator<<(std::ostream& os, const Voxel& voxel)
85  {
86  os << "{ ";
87  std::vector<std::string> items;
88  for (const auto& [label, num] : voxel)
89  {
90  items.push_back(std::to_string(label) + ": " + std::to_string(num));
91  }
92  os << simox::alg::join(items, ", ") << " }";
93  return os;
94  }
95 
96 
97  template <class PointT>
98  static void addPointCloud(
99  VoxelGrid& grid,
100  const pcl::PointCloud<PointT>& _pointCloud,
101  const Eigen::Matrix4f& pointCloudPose)
102  {
103  // Transform the point cloud in one go to avoid transformation of each
104  // point individually.
105  const pcl::PointCloud<PointT> pointCloud = utils::transformPointCloudToGrid(
106  _pointCloud, pointCloudPose, grid.getPose());
107 
108  // After transforming the point cloud, it is local.
109  const bool local = true;
110 
111  for (const PointT& point : pointCloud)
112  {
113  const Eigen::Vector3f vpoint(point.data);
114 
115  const Eigen::Vector3i indices = grid.getVoxelGridIndex(vpoint, local);
116  if (!grid.isInside(indices))
117  {
118  continue;
119  }
120 
121  auto& voxel = grid.getVoxel(indices);
122  voxel[static_cast<Label>(point.label)]++;
123  }
124  }
125 
126 
127 
129  const pcl::PointCloud<pcl::PointXYZL>& pointCloud,
130  const Eigen::Matrix4f& pointCloudPose)
131  {
132  LabelDensity::addPointCloud(*this, pointCloud, pointCloudPose);
133  }
134 
136  const pcl::PointCloud<pcl::PointXYZRGBL>& pointCloud,
137  const Eigen::Matrix4f& pointCloudPose)
138  {
139  LabelDensity::addPointCloud(*this, pointCloud, pointCloudPose);
140  }
141 
142 
143  std::set<Label> VoxelGrid::getUniqueLabels() const
144  {
145  std::set<Label> ids;
146  for (const Voxel& voxel : *this)
147  {
148  for (const auto& item : voxel)
149  {
150  ids.insert(item.first);
151  }
152  }
153  return ids;
154  }
155 
156  void VoxelGrid::reduceNoise(std::size_t minNumPoints)
157  {
158  for (auto& voxel : *this)
159  {
160  std::set<Label> remove;
161  for (const auto& [label, num] : voxel)
162  {
163  if (num < minNumPoints)
164  {
165  remove.insert(label);
166  }
167  }
168 
169  for (Label label : remove)
170  {
171  voxel.erase(voxel.find(label));
172  }
173  }
174  }
175 
176 
177  static io::VoxelAttributeGetterMap<Voxel> makeJsonGetters(const VoxelGrid& grid)
178  {
180 
181  const std::set<Label> labels = grid.getUniqueLabels();
182 
183  for (Label label : labels)
184  {
185  getters[std::to_string(label)] = [label](const Voxel & voxel) -> nlohmann::json
186  {
187  const auto find = voxel.find(label);
188  return find != voxel.end() ? find->second : 0;
189  };
190  }
191 
192  return getters;
193  }
194 
195  static io::VoxelAttributeSetterMap<Voxel> makeJsonSetters(const std::set<Label>& labels)
196  {
197  voxelgrid::io::VoxelAttributeSetterMap<Voxel> setters;
198  for (Label label : labels)
199  {
200  setters[std::to_string(label)] = [label](const nlohmann::json & j, Voxel & voxel)
201  {
202  voxel[label] = j;
203  };
204  }
205  return setters;
206  }
207 
208  static std::set<Label> getLabelsFromKeys(const nlohmann::json& json)
209  {
210  // All numeric top-level keys are labels.
211 
212  std::set<Label> labels;
213  for (const auto& item : json.items())
214  {
215  if (item.key() == "structure")
216  {
217  continue;
218  }
219  try
220  {
221  const int key = std::stoi(item.key());
222  if (key >= 0)
223  {
224  labels.insert(static_cast<Label>(key));
225  }
226  }
227  catch (std::invalid_argument&)
228  {
229  // Ignore this key.
230  }
231  }
232 
233  return labels;
234  }
235 
236 
237  void VoxelGrid::writeJson(std::ostream& os) const
238  {
239  io::JsonIO::write<Voxel>(os, *this, makeJsonGetters(*this));
240  }
241 
242  void VoxelGrid::writeJson(const std::filesystem::path& file) const
243  {
244  io::JsonIO::write<Voxel>(file, *this, makeJsonGetters(*this));
245  }
246 
247  void VoxelGrid::readJson(std::istream& is)
248  {
249  // Since we do not know which labels are present, we have to take a peak at
250  // the JSON content.
251  const nlohmann::json json = io::JsonIO::readJson(is);
252  from_json(json, *this);
253  }
254 
255  void VoxelGrid::readJson(const std::filesystem::path& file)
256  {
257  std::ifstream ifs(file);
258  readJson(ifs);
259  }
260 
261 
262  void to_json(nlohmann::json& json, const VoxelGrid& grid)
263  {
264  io::JsonIO::toJson(json, grid, makeJsonGetters(grid));
265  }
266 
267  void from_json(const nlohmann::json& json, VoxelGrid& grid)
268  {
269  io::JsonIO::fromJson(json, grid, makeJsonSetters(getLabelsFromKeys(json)));
270  }
271 
272 
273  void VoxelGrid::toCsv(std::ostream& os, bool includeTotal) const
274  {
275  static const std::string sep = ",";
276 
277  const std::set<Label> labels = getUniqueLabels();
278 
279  // Write header.
280 
281  std::vector<std::string> strings;
282  // Index
283  strings.push_back("index");
284  // Counts
285  std::transform(labels.begin(), labels.end(), std::back_inserter(strings),
286  [](Label l)
287  {
288  return std::to_string(l);
289  });
290 
291  if (includeTotal)
292  {
293  // Total
294  strings.push_back("total");
295  }
296 
297  os << simox::alg::join(strings, sep) << std::endl;
298 
299  // Write data.
300  for (std::size_t index = 0; index < numVoxels(); ++index)
301  {
302  const Voxel& voxel = getVoxel(index);
303  if (!voxel.empty())
304  {
305  strings.clear();
306 
307  // Index
308  strings.push_back(std::to_string(index));
309  // Counts
310  std::transform(labels.begin(), labels.end(), std::back_inserter(strings),
311  [&voxel](const Label id)
312  {
313  auto it = voxel.find(id);
314  return std::to_string(it != voxel.end() ? it->second : 0);
315  });
316 
317  // Total
318  if (includeTotal)
319  {
320  strings.push_back(std::to_string(voxel.getTotal()));
321  }
322 
323  // Write line.
324  os << simox::alg::join(strings, sep) << std::endl;
325  }
326  }
327  }
328 
329  void VoxelGrid::toCsv(const std::filesystem::path& file, bool includeTotal) const
330  {
331  std::ofstream os(file);
332  toCsv(os, includeTotal);
333  }
334 
335 }
VoxelGrid.h
visionx::voxelgrid::io::JsonIO::fromJson
static void fromJson(const nlohmann::json &j, VoxelGrid< VoxelT > &grid, const VoxelAttributeSetterMap< VoxelT > &attributeMap)
Deserialize a voxel grid from JSON.
Definition: JsonIO.h:306
visionx::voxelgrid::VoxelGrid
A 3D grid of voxels of type _VoxelT.
Definition: VoxelGrid.hpp:50
visionx::voxelgrid::io::JsonIO::toJson
static void toJson(nlohmann::json &j, const VoxelGrid< VoxelT > &grid, const VoxelAttributeGetterMap< VoxelT > &attributeMap)
Serialize a voxel grid to JSON.
Definition: JsonIO.h:259
index
uint8_t index
Definition: EtherCATFrame.h:59
visionx::voxelgrid::utils::transformPointCloudToGrid
pcl::PointCloud< PointT > transformPointCloudToGrid(const pcl::PointCloud< PointT > &pointCloud, const Eigen::Matrix4f &pointCloudPose, const Eigen::Matrix4f &gridPose)
Transform a point cloud to local grid coordinates.
Definition: point_cloud.h:37
armarx::RemoteGui::Client::Label
Definition: Widgets.h:31
visionx::voxelgrid::LabelDensity::Voxel::getMaxLabel
Label getMaxLabel() const
Get the label with most points.
Definition: VoxelGrid.cpp:42
visionx::voxelgrid::VoxelGrid::getPose
Eigen::Matrix4f getPose() const
Get the grid pose in the world frame.
Definition: VoxelGrid.hpp:320
visionx::voxelgrid::LabelDensity::operator<<
std::ostream & operator<<(std::ostream &os, const Voxel &voxel)
Definition: VoxelGrid.cpp:84
visionx::voxelgrid::LabelDensity::VoxelGrid::toCsv
void toCsv(std::ostream &os, bool includeTotal=false) const
Write the voxel data to a CSV file.
Definition: VoxelGrid.cpp:273
visionx::voxelgrid::io::VoxelAttributeGetterMap
std::map< std::string, VoxelAttributeGetter< VoxelT > > VoxelAttributeGetterMap
Map of attribute name to attribute getter.
Definition: JsonIO.h:28
visionx::voxelgrid::LabelDensity::VoxelGrid::reduceNoise
void reduceNoise(std::size_t minNumPoints)
Remove entries with number of points below minNumPoints.
Definition: VoxelGrid.cpp:156
visionx::voxelgrid::LabelDensity::VoxelGrid
Voxel grid storing the number of points per label in each voxel.
Definition: VoxelGrid.h:69
cxxopts::empty
bool empty(const std::string &s)
Definition: cxxopts.hpp:255
visionx::voxelgrid::LabelDensity::VoxelGrid::readJson
void readJson(std::istream &is)
Read this voxel grid from JSON.
Definition: VoxelGrid.cpp:247
visionx::voxelgrid::LabelDensity::VoxelGrid::writeJson
void writeJson(std::ostream &os) const
Write this voxel grid to JSON.
Definition: VoxelGrid.cpp:237
visionx::voxelgrid::VoxelGrid::getVoxel
VoxelT & getVoxel(std::size_t index)
Get the voxel with the given index.
Definition: VoxelGrid.hpp:104
visionx::voxelgrid::LabelDensity::Voxel::isFree
bool isFree() const
Indicate whether this voxel is free, i.e. it contains no points.
Definition: VoxelGrid.cpp:15
visionx::voxelgrid::Label
uint32_t Label
Type of an object label.
Definition: types.h:7
visionx::voxelgrid::VoxelGrid< VoxelT >::numVoxels
std::size_t numVoxels() const
Get the number of voxels in the grid.
Definition: VoxelGrid.hpp:165
pcl::graph::indices
pcl::PointIndices::Ptr indices(const PCG &g)
Retrieve the indices of the points of the point cloud stored in a point cloud graph that actually bel...
Definition: point_cloud_graph.h:737
visionx::voxelgrid::io::JsonIO::readJson
static nlohmann::json readJson(const std::string &filename)
Read JSON from file.
Definition: JsonIO.cpp:23
visionx::voxelgrid::LabelDensity::Voxel::getDensity
std::map< Label, float > getDensity() const
Get the relative frequency of labels, so that the sum is 1.0.
Definition: VoxelGrid.cpp:30
visionx::voxelgrid::LabelDensity::Voxel::getTotal
std::size_t getTotal() const
Get the total number of points in this voxel.
Definition: VoxelGrid.cpp:20
visionx::voxelgrid::VoxelGrid::getVoxelGridIndex
Eigen::Vector3i getVoxelGridIndex(size_t index) const
Get the grid index of the voxel with the given flat index.
Definition: VoxelGrid.hpp:228
visionx::voxelgrid::LabelDensity::Voxel::getMax
std::pair< Label, std::size_t > getMax() const
Get the label with most points and the number of points.
Definition: VoxelGrid.cpp:47
visionx::voxelgrid::LabelDensity::Voxel
Map of labels (object IDs) to number of points.
Definition: VoxelGrid.h:27
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:40
visionx::voxelgrid::LabelDensity::VoxelGrid::getUniqueLabels
std::set< Label > getUniqueLabels() const
Get the set of unique labels.
Definition: VoxelGrid.cpp:143
visionx::voxelgrid::LabelDensity::VoxelGrid::addPointCloud
void addPointCloud(const pcl::PointCloud< pcl::PointXYZL > &pointCloud, const Eigen::Matrix4f &pointCloudPose=Eigen::Matrix4f::Identity())
Add the point cloud.
Definition: VoxelGrid.cpp:128
visionx::voxelgrid::LabelDensity::from_json
void from_json(const nlohmann::json &json, VoxelGrid &grid)
Read the voxel grid from JSON.
Definition: VoxelGrid.cpp:267
GfxTL::Matrix4f
MatrixXX< 4, 4, float > Matrix4f
Definition: MatrixXX.h:601
armarx::transform
auto transform(const Container< InputT, Alloc > &in, OutputT(*func)(InputT const &)) -> Container< OutputT, typename std::allocator_traits< Alloc >::template rebind_alloc< OutputT > >
Convenience function (with less typing) to transform a container of type InputT into the same contain...
Definition: algorithm.h:315
visionx::voxelgrid::LabelDensity::Voxel::operator==
bool operator==(const Voxel &rhs) const
Equality operator.
Definition: VoxelGrid.cpp:52
visionx::voxelgrid::VoxelGrid::isInside
bool isInside(const Eigen::Vector3i &index) const
Indicate whether the given point is inside the voxel.
Definition: VoxelGrid.hpp:368
JsonIO.h
visionx::voxelgrid::LabelDensity::to_json
void to_json(nlohmann::json &json, const VoxelGrid &grid)
Write the voxel grid to JSON.
Definition: VoxelGrid.cpp:262
visionx::voxelgrid::LabelDensity
Definition: Visualizer.cpp:9
visionx::PointT
pcl::PointXYZRGBA PointT
Definition: MaskRCNNPointCloudObjectLocalizer.h:79
visionx::voxelgrid::LabelDensity::Voxel::operator!=
bool operator!=(const Voxel &rhs) const
Definition: VoxelGrid.cpp:79