HDF5MeshTool.cpp
Go to the documentation of this file.
1 
28 #include <iostream>
29 #include <vector>
30 #include <algorithm>
31 
32 #include <string.h>
33 
34 #include "lvr2/io/ModelFactory.hpp"
35 #include "lvr2/io/Timestamp.hpp"
40 
41 #include "Options.hpp"
42 
43 #include <string>
44 #include <sstream>
45 #include <algorithm>
46 #include <cstring>
47 #include <memory>
48 
50 #include "lvr2/io/hdf5/MeshIO.hpp"
51 
52 using namespace lvr2;
53 
54 int main( int argc, char ** argv )
55 {
56  hdf5meshtool::Options options(argc, argv);
57  std::cout << timestamp << "Load HDF5 file structure..." << std::endl;
58  using HDF5MeshToolIO = lvr2::Hdf5IO<
63 
64  // Get extension
65  boost::filesystem::path selectedFile(options.getInputFile());
66  std::string extension = selectedFile.extension().string();
67  MeshBufferPtr meshBuffer;
68  HDF5MeshToolIO hdf5In;
69  bool readFromHdf5 = false;
70 
71  // check extension
72  if (extension == ".h5") // use new Hdf5IO
73  {
74  hdf5In.open(options.getInputFile());
75  if (hdf5In.m_hdf5_file->isValid()) // TODO: update hdf5io to return bool on open()
76  {
77  readFromHdf5 = true;
78  }
79  meshBuffer = hdf5In.loadMesh(options.getMeshName());
80  }
81  else // use model reader
82  {
84  meshBuffer = model->m_mesh;
85  }
86 
87  if (meshBuffer != nullptr)
88  {
90  size_t numFaces = meshBuffer->numFaces();
91  size_t numVertices = meshBuffer->numVertices();
92  std::cout << timestamp << "Building mesh from buffers with " << numFaces
93  << " faces and " << numVertices << " vertices..." << std::endl;
94 
95  floatArr vertices = meshBuffer->getVertices();
96  indexArray indices = meshBuffer->getFaceIndices();
97 
98  for(size_t i = 0; i < numVertices; i++)
99  {
100  size_t pos = 3 * i;
102  vertices[pos],
103  vertices[pos + 1],
104  vertices[pos + 2]));
105  }
106 
107  size_t invalid_face_cnt = 0;
108  for(size_t i = 0; i < numFaces; i++) {
109  size_t pos = 3 * i;
110  VertexHandle v1(indices[pos]);
111  VertexHandle v2(indices[pos + 1]);
112  VertexHandle v3(indices[pos + 2]);
113  try{
114  hem.addFace(v1, v2, v3);
115  }
116  catch(lvr2::PanicException)
117  {
118  invalid_face_cnt++;
119  }
120  }
121 
122  HDF5MeshToolIO hdf5;
123  bool writeToHdf5Input = false;
124  if (readFromHdf5 && options.getInputFile() == options.getOutputFile())
125  {
126  hdf5 = hdf5In;
127  writeToHdf5Input = true;
128  }
129  else
130  {
131  hdf5.open(options.getOutputFile());
132  }
133  hdf5.setMeshName(options.getMeshName());
134 
135  // face normals
136  DenseFaceMap<Normal<float>> faceNormals;
137  boost::optional<DenseFaceMap<Normal<float>>> faceNormalsOpt;
138  if (readFromHdf5)
139  {
140  faceNormalsOpt = hdf5In.getDenseAttributeMap<DenseFaceMap<Normal<float>>>("face_normals");
141  }
142  if (faceNormalsOpt)
143  {
144  std::cout << timestamp << "Using existing face normals..." << std::endl;
145  faceNormals = *faceNormalsOpt;
146  }
147  else
148  {
149  std::cout << timestamp << "Computing face normals..." << std::endl;
150  faceNormals = calcFaceNormals(hem);
151  }
152  if(options.getEdgeCollapseNum() > 0)
153  {
154  double percent = options.getEdgeCollapseNum() > 100 ? 1 : options.getEdgeCollapseNum() / 100.0;
155  size_t numCollapse = static_cast<size_t>(percent * hem.numEdges());
156  std::cout << timestamp << "Reduce mesh by collapsing " << percent * 100
157  << "% of the edges (" << numCollapse << " out of " << hem.numEdges() << ")" << std::endl;
158  simpleMeshReduction(hem, numCollapse, faceNormals);
159  }
160 
161  // add mesh to file
162  if(options.getEdgeCollapseNum() > 0 || !writeToHdf5Input)
163  {
164  std::cout << timestamp << "Adding mesh to file..." << std::endl;
165  // add mesh to file
166  bool addedMesh = hdf5.addMesh(hem);
167  if (addedMesh)
168  {
169  std::cout << timestamp << "successfully added mesh" << std::endl;
170  }
171  else
172  {
173  std::cout << timestamp << "could not add the mesh!" << std::endl;
174  }
175  }
176  else
177  {
178  std::cout << timestamp << "Mesh already included." << std::endl;
179  }
180 
181  // add face normals to file
182  if(!faceNormalsOpt || options.getEdgeCollapseNum() > 0 || !writeToHdf5Input)
183  {
184  bool addedFaceNormals = hdf5.addDenseAttributeMap<DenseFaceMap<Normal<float>>>(
185  hem, faceNormals, "face_normals");
186  if(addedFaceNormals)
187  {
188  std::cout << timestamp << "successfully added face normals" << std::endl;
189  }
190  else
191  {
192  std::cout << timestamp << "could not add face normals!" << std::endl;
193  }
194  }
195  else
196  {
197  std::cout << timestamp << "Face normals already included." << std::endl;
198  }
199 
200  // vertex normals
201  DenseVertexMap<Normal<float>> vertexNormals;
202  boost::optional<DenseVertexMap<Normal<float>>> vertexNormalsOpt;
203  if (readFromHdf5)
204  {
205  vertexNormalsOpt = hdf5In.getDenseAttributeMap<DenseVertexMap<Normal<float>>>("vertex_normals");
206  }
207  if (vertexNormalsOpt)
208  {
209  std::cout << timestamp << "Using existing vertex normals..." << std::endl;
210  vertexNormals = *vertexNormalsOpt;
211  }
212  else if (meshBuffer != nullptr && meshBuffer->hasVertexNormals())
213  {
214  std::cout << timestamp << "Using existing vertex normals from mesh buffer..." << std::endl;
215  const FloatChannelOptional channel_opt = meshBuffer->getChannel<float>("vertex_normals");
216  if (channel_opt && channel_opt.get().width() == 3 and channel_opt.get().numElements() == hem.numVertices())
217  {
218  auto &channel = channel_opt.get();
219  vertexNormals.reserve(channel.numElements());
220  for (size_t i = 0; i < channel.numElements(); i++)
221  {
222  vertexNormals.insert(VertexHandle(i), channel[i]);
223  }
224  }
225  else
226  {
227  std::cerr << timestamp << "Error while reading vertex normals..." << std::endl;
228  }
229  }
230 
231  if(vertexNormals.numValues() == 0)
232  {
233  std::cout << timestamp << "Computing vertex normals..." << std::endl;
234  vertexNormals = calcVertexNormals(hem, faceNormals);
235  }
236  if (!vertexNormalsOpt || !writeToHdf5Input)
237  {
238  std::cout << timestamp << "Adding vertex normals..." << std::endl;
239  bool addedVertexNormals = hdf5.addDenseAttributeMap<DenseVertexMap<Normal<float>>>(
240  hem, vertexNormals, "vertex_normals");
241  if (addedVertexNormals)
242  {
243  std::cout << timestamp << "successfully added vertex normals" << std::endl;
244  }
245  else
246  {
247  std::cout << timestamp << "could not add vertex normals!" << std::endl;
248  }
249  }
250  else
251  {
252  std::cout << timestamp << "Vertex normals already included." << std::endl;
253  }
254 
255  // vertex colors
256  using color = std::array<uint8_t, 3>;
258  boost::optional<DenseVertexMap<color>> colorsOpt;
259  ChannelOptional<uint8_t> channel_opt;
260  if (readFromHdf5)
261  {
262  colorsOpt = hdf5In.getDenseAttributeMap<DenseVertexMap<color>>("vertex_colors");
263  }
264  if (colorsOpt)
265  {
266  std::cout << timestamp << "Using existing vertex colors..." << std::endl;
267  colors = *colorsOpt;
268  }
269  else if (meshBuffer != nullptr && (channel_opt = meshBuffer->getChannel<uint8_t>("vertex_colors"))
270  && channel_opt && channel_opt.get().width() == 3 && channel_opt.get().numElements() == hem.numVertices()) {
271  std::cout << timestamp << "Using existing colors from mesh buffer..." << std::endl;
272 
273  auto &channel = channel_opt.get();
274  colors.reserve(channel.numElements());
275  for (size_t i = 0; i < channel.numElements(); i++)
276  {
277  colors.insert(VertexHandle(i), channel[i]);
278  }
279  }
280  if (!colorsOpt || !writeToHdf5Input)
281  {
282  std::cout << timestamp << "Adding vertex colors..." << std::endl;
283  bool addedVertexColors = hdf5.addDenseAttributeMap<DenseVertexMap<color>>(
284  hem, colors, "vertex_colors");
285  if (addedVertexColors)
286  {
287  std::cout << timestamp << "successfully added vertex colors" << std::endl;
288  }
289  else
290  {
291  std::cout << timestamp << "could not add vertex colors!" << std::endl;
292  }
293  }
294  else
295  {
296  std::cout << timestamp << "Vertex colors already included." << std::endl;
297  }
298 
299 
300  // vertex average angles
301  DenseVertexMap<float> averageAngles;
302  boost::optional<DenseVertexMap<float>> averageAnglesOpt;
303  if (readFromHdf5)
304  {
305  averageAnglesOpt = hdf5In.getDenseAttributeMap<DenseVertexMap<float>>("average_angles");
306  }
307  if (averageAnglesOpt)
308  {
309  std::cout << timestamp << "Using existing vertex average angles..." << std::endl;
310  averageAngles = *averageAnglesOpt;
311  }
312  else
313  {
314  std::cout << timestamp << "Computing vertex average angles..." << std::endl;
315  averageAngles = calcAverageVertexAngles(hem, vertexNormals);
316  }
317  if (!averageAnglesOpt || !writeToHdf5Input)
318  {
319  std::cout << timestamp << "Adding vertex average angles..." << std::endl;
320  bool addedAverageAngles = hdf5.addDenseAttributeMap<DenseVertexMap<float>>(
321  hem, averageAngles, "average_angles");
322  if (addedAverageAngles)
323  {
324  std::cout << timestamp << "successfully added vertex average angles" << std::endl;
325  }
326  else
327  {
328  std::cout << timestamp << "could not add vertex average angles!" << std::endl;
329  }
330  }
331  else
332  {
333  std::cout << timestamp << "Vertex average angles already included." << std::endl;
334  }
335 
336  // roughness
337  DenseVertexMap<float> roughness;
338  boost::optional<DenseVertexMap<float>> roughnessOpt;
339  if (readFromHdf5)
340  {
341  roughnessOpt = hdf5In.getDenseAttributeMap<DenseVertexMap<float>>("roughness");
342  }
343  if (roughnessOpt)
344  {
345  std::cout << timestamp << "Using existing roughness..." << std::endl;
346  roughness = *roughnessOpt;
347  }
348  else
349  {
350  std::cout << timestamp << "Computing roughness with a local radius of "
351  << options.getLocalRadius() << "m ..." << std::endl;
352  roughness = calcVertexRoughness(hem, options.getLocalRadius(), vertexNormals);
353  }
354  if (!roughnessOpt || !writeToHdf5Input)
355  {
356  std::cout << timestamp << "Adding roughness..." << std::endl;
357  bool addedRoughness = hdf5.addDenseAttributeMap<DenseVertexMap<float>>(
358  hem, roughness, "roughness");
359  if (addedRoughness)
360  {
361  std::cout << timestamp << "successfully added roughness." << std::endl;
362  }
363  else
364  {
365  std::cout << timestamp << "could not add roughness!" << std::endl;
366  }
367  }
368  else
369  {
370  std::cout << timestamp << "Roughness already included." << std::endl;
371  }
372 
373  // height differences
374  DenseVertexMap<float> heightDifferences;
375  boost::optional<DenseVertexMap<float>> heightDifferencesOpt;
376  if (readFromHdf5)
377  {
378  heightDifferencesOpt = hdf5In.getDenseAttributeMap<DenseVertexMap<float>>("height_diff");
379  }
380  if (heightDifferencesOpt)
381  {
382  std::cout << timestamp << "Using existing height differences..." << std::endl;
383  heightDifferences = *heightDifferencesOpt;
384  }
385  else
386  {
387  std::cout << timestamp << "Computing height diff with a local radius of "
388  << options.getLocalRadius() << "m ..." << std::endl;
389  heightDifferences = calcVertexHeightDifferences(hem, options.getLocalRadius());
390  }
391  if (!heightDifferencesOpt || !writeToHdf5Input)
392  {
393  std::cout << timestamp << "Adding roughness..." << std::endl;
394  bool addedHeightDiff = hdf5.addDenseAttributeMap<DenseVertexMap<float>>(
395  hem, heightDifferences, "height_diff");
396  if (addedHeightDiff)
397  {
398  std::cout << timestamp << "successfully added height differences." << std::endl;
399  }
400  else
401  {
402  std::cout << timestamp << "could not add height differences!" << std::endl;
403  }
404  }
405  else
406  {
407  std::cout << timestamp << "Height differences already included." << std::endl;
408  }
409  }
410  else
411  {
412  std::cout << timestamp << "Error reading mesh data from "
413  << options.getOutputFile() << std::endl;
414  }
415 
416  return 0;
417 }
size_t simpleMeshReduction(BaseMesh< BaseVecT > &mesh, const size_t count, FaceMap< Normal< typename BaseVecT::CoordType >> &faceNormals)
Like iterativeEdgeCollapse but with a fixed cost function.
size_t numVertices() const final
Returns the number of vertices in the mesh.
Handle to access vertices of the mesh.
Definition: Handles.hpp:146
const kaboom::Options * options
std::shared_ptr< MeshBuffer > MeshBufferPtr
Definition: MeshBuffer.hpp:217
DenseVertexMap< Normal< typename BaseVecT::CoordType > > calcVertexNormals(const BaseMesh< BaseVecT > &mesh, const FaceMap< Normal< typename BaseVecT::CoordType >> &normals, const PointsetSurface< BaseVecT > &surface)
Calculates a normal for each vertex in the mesh.
static Timestamp timestamp
A global time stamp object for program runtime measurement.
Definition: Timestamp.hpp:116
static ModelPtr readModel(std::string filename)
DenseFaceMap< Normal< typename BaseVecT::CoordType > > calcFaceNormals(const BaseMesh< BaseVecT > &mesh)
Calculates a normal for each face in the mesh.
void reserve(size_t newCap)
boost::optional< ValueT > insert(HandleT key, const ValueT &value) final
Inserts the given value at the given key position.
An exception denoting an internal bug.
Definition: Panic.hpp:46
FaceHandle addFace(VertexHandle v1H, VertexHandle v2H, VertexHandle v3H) final
Creates a face connecting the three given vertices.
boost::shared_array< unsigned int > indexArray
Definition: DataStruct.hpp:128
Manager Class for all Hdf5IO components located in hdf5 directory.
Hdf5IO Feature for handling MeshBuffer related IO.
Definition: MeshIO.hpp:52
boost::shared_array< float > floatArr
Definition: DataStruct.hpp:133
DenseVertexMap< float > calcAverageVertexAngles(const BaseMesh< BaseVecT > &mesh, const VertexMap< Normal< typename BaseVecT::CoordType >> &normals)
Calculates the average angle for each vertex.
Half-edge data structure implementing the BaseMesh interface.
size_t numFaces() const final
Returns the number of faces in the mesh.
size_t numEdges() const final
Returns the number of edges in the mesh.
DenseVertexMap< float > calcVertexHeightDifferences(const BaseMesh< BaseVecT > &mesh, double radius)
Calculate the height difference value for each vertex of the given BaseMesh.
FloatChannel::Optional FloatChannelOptional
Definition: Channel.hpp:88
int main(int argc, char **argv)
Hdf5IO Feature for handling VariantChannel related IO.
std::shared_ptr< Model > ModelPtr
Definition: Model.hpp:80
MeshBufferPtr loadMesh(std::string name)
A map with constant lookup overhead using small-ish integer-keys.
Definition: VectorMap.hpp:60
A class to parse the program options for the reconstruction executable.
typename Channel< T >::Optional ChannelOptional
Definition: Channel.hpp:85
size_t numValues() const final
Returns the number of values in this map.
DenseVertexMap< float > calcVertexRoughness(const BaseMesh< BaseVecT > &mesh, double radius, const VertexMap< Normal< typename BaseVecT::CoordType >> &normals)
Calculates the roughness for each vertex.
VertexHandle addVertex(BaseVecT pos) final
Adds a vertex with the given position to the mesh.
char ** argv


lvr2
Author(s): Thomas Wiemann , Sebastian Pütz , Alexander Mock , Lars Kiesow , Lukas Kalbertodt , Tristan Igelbrink , Johan M. von Behren , Dominik Feldschnieders , Alexander Löhr
autogenerated on Mon Feb 28 2022 22:46:06