MVE - Multi-View Environment mve-devel
Loading...
Searching...
No Matches
sample_io.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015, Simon Fuhrmann
3 * TU Darmstadt - Graphics, Capture and Massively Parallel Computing
4 * All rights reserved.
5 *
6 * This software may be modified and distributed under the terms
7 * of the BSD 3-Clause license. See the LICENSE.txt file for details.
8 */
9
10#include <iostream>
11#include <cstring>
12#include <cerrno>
13
14#include "util/exception.h"
15#include "util/tokenizer.h"
16#include "mve/mesh_io_ply.h"
17#include "fssr/sample_io.h"
18
20
21void
22SampleIO::read_file (std::string const& filename, SampleList* samples)
23{
24 /* Load point set from PLY file. */
26 mve::TriangleMesh::VertexList const& verts = mesh->get_vertices();
27 if (verts.empty())
28 {
29 std::cout << "WARNING: No samples in file, skipping." << std::endl;
30 return;
31 }
32
33 /* Check if the points have the required attributes. */
34 mve::TriangleMesh::NormalList const& vnormals = mesh->get_vertex_normals();
35 if (!mesh->has_vertex_normals())
36 throw std::invalid_argument("Vertex normals missing!");
37
38 mve::TriangleMesh::ValueList const& vvalues = mesh->get_vertex_values();
39 if (!mesh->has_vertex_values())
40 throw std::invalid_argument("Vertex scale missing!");
41
42 mve::TriangleMesh::ConfidenceList& vconfs = mesh->get_vertex_confidences();
43 if (!mesh->has_vertex_confidences())
44 {
45 std::cout << "INFO: No confidences given, setting to 1." << std::endl;
46 vconfs.resize(verts.size(), 1.0f);
47 }
48 mve::TriangleMesh::ColorList& vcolors = mesh->get_vertex_colors();
49 if (!mesh->has_vertex_colors())
50 vcolors.resize(verts.size(), math::Vec4f(-1.0f));
51
52 /* Add samples to the list. */
53 SamplesState state;
54 this->reset_samples_state(&state);
55 samples->reserve(verts.size());
56 for (std::size_t i = 0; i < verts.size(); i += 1)
57 {
58 Sample sample;
59 sample.pos = verts[i];
60 sample.normal = vnormals[i];
61 sample.scale = vvalues[i];
62 sample.confidence = vconfs[i];
63 sample.color = math::Vec3f(*vcolors[i]);
64
65 if (this->process_sample(&sample, &state))
66 samples->push_back(sample);
67 }
68 this->print_samples_state(&state);
69}
70
71void
72SampleIO::open_file (std::string const& filename)
73{
74 this->reset_stream_state();
75 this->reset_samples_state(&this->samples);
76 this->stream.filename = filename;
77 this->stream.stream.open(filename.c_str(), std::ios::binary);
78 if (!this->stream.stream.good())
79 throw util::FileException(filename, std::strerror(errno));
80
81 /* Read PLY signature. */
82 std::string line;
83 std::getline(this->stream.stream, line);
84 if (line != "ply")
85 {
86 this->reset_stream_state();
87 throw util::Exception("Invalid PLY signature");
88 }
89
90 /* Parse PLY headers. */
91 bool parsing_vertex_props = false;
92 this->stream.format = mve::geom::PLY_UNKNOWN;
93 while (true)
94 {
95 std::getline(this->stream.stream, line);
96 if (this->stream.stream.eof())
97 {
98 this->reset_stream_state();
99 throw util::Exception("EOF while parsing headers");
100 }
101
102 if (!this->stream.stream.good())
103 {
104 this->reset_stream_state();
105 throw util::Exception("Read error while parsing headers");
106 }
107
110 if (line == "end_header")
111 break;
112
113 util::Tokenizer tokens;
114 tokens.split(line);
115 if (tokens.empty())
116 continue;
117
118 if (tokens.size() == 3 && tokens[0] == "format")
119 {
120 /* Determine the format. */
121 if (tokens[1] == "ascii")
122 this->stream.format = mve::geom::PLY_ASCII;
123 else if (tokens[1] == "binary_little_endian")
124 this->stream.format = mve::geom::PLY_BINARY_LE;
125 else if (tokens[1] == "binary_big_endian")
126 this->stream.format = mve::geom::PLY_BINARY_BE;
127 continue;
128 }
129
130 if (tokens.size() == 3 && tokens[0] == "element")
131 {
132 if (tokens[1] == "vertex")
133 {
134 parsing_vertex_props = true;
135 this->stream.num_vertices
136 = util::string::convert<unsigned int>(tokens[2]);
137 continue;
138 }
139 else
140 {
141 parsing_vertex_props = false;
142 continue;
143 }
144 }
145
146 if (parsing_vertex_props && tokens[0] == "property")
147 {
148 if (tokens[1] == "float" && tokens[2] == "x")
149 this->stream.props.push_back(mve::geom::PLY_V_FLOAT_X);
150 else if (tokens[1] == "float" && tokens[2] == "y")
151 this->stream.props.push_back(mve::geom::PLY_V_FLOAT_Y);
152 else if (tokens[1] == "float" && tokens[2] == "z")
153 this->stream.props.push_back(mve::geom::PLY_V_FLOAT_Z);
154 else if (tokens[1] == "float" && tokens[2] == "nx")
155 this->stream.props.push_back(mve::geom::PLY_V_FLOAT_NX);
156 else if (tokens[1] == "float" && tokens[2] == "ny")
157 this->stream.props.push_back(mve::geom::PLY_V_FLOAT_NY);
158 else if (tokens[1] == "float" && tokens[2] == "nz")
159 this->stream.props.push_back(mve::geom::PLY_V_FLOAT_NZ);
160 else if (tokens[1] == "float" && tokens[2] == "confidence")
161 this->stream.props.push_back(mve::geom::PLY_V_FLOAT_CONF);
162 else if (tokens[1] == "float" && tokens[2] == "value")
163 this->stream.props.push_back(mve::geom::PLY_V_FLOAT_VALUE);
164 else if (tokens[1] == "float" && (tokens[2] == "red"
165 || tokens[2] == "diffuse_red" || tokens[2] == "r"))
166 this->stream.props.push_back(mve::geom::PLY_V_FLOAT_R);
167 else if (tokens[1] == "float" && (tokens[2] == "green"
168 || tokens[2] == "diffuse_green" || tokens[2] == "g"))
169 this->stream.props.push_back(mve::geom::PLY_V_FLOAT_G);
170 else if (tokens[1] == "float" && (tokens[2] == "blue"
171 || tokens[2] == "diffuse_blue" || tokens[2] == "b"))
172 this->stream.props.push_back(mve::geom::PLY_V_FLOAT_B);
173 else if (tokens[1] == "uchar" && (tokens[2] == "red"
174 || tokens[2] == "diffuse_red" || tokens[2] == "r"))
175 this->stream.props.push_back(mve::geom::PLY_V_UINT8_R);
176 else if (tokens[1] == "uchar" && (tokens[2] == "green"
177 || tokens[2] == "diffuse_green" || tokens[2] == "g"))
178 this->stream.props.push_back(mve::geom::PLY_V_UINT8_G);
179 else if (tokens[1] == "uchar" && (tokens[2] == "blue"
180 || tokens[2] == "diffuse_blue" || tokens[2] == "b"))
181 this->stream.props.push_back(mve::geom::PLY_V_UINT8_B);
182 else if (tokens[1] == "float")
183 this->stream.props.push_back(mve::geom::PLY_V_IGNORE_FLOAT);
184 else if (tokens[1] == "uchar")
185 this->stream.props.push_back(mve::geom::PLY_V_IGNORE_UINT8);
186 else if (tokens[1] == "int")
187 this->stream.props.push_back(mve::geom::PLY_V_IGNORE_UINT32);
188 else
189 {
190 this->reset_stream_state();
191 throw util::Exception("Unknown property type: " + tokens[1]);
192 }
193
194 continue;
195 }
196
197 if (!parsing_vertex_props && tokens[0] == "property")
198 continue;
199
200 if (tokens[0] == "comment")
201 continue;
202
203 std::cerr << "Warning: Unrecognized PLY header: " << line << std::endl;
204 }
205
206 /* Sanity check gathered data. */
207 if (this->stream.format == mve::geom::PLY_UNKNOWN)
208 {
209 this->reset_stream_state();
210 throw util::Exception("Unknown PLY file format");
211 }
212
213 /* If the PLY does not contain vertices, ignore properties. */
214 if (this->stream.num_vertices == 0)
215 return;
216
217 std::vector<bool> prop_table;
218 for (std::size_t i = 0; i < this->stream.props.size(); ++i)
219 {
220 mve::geom::PLYVertexProperty prop = this->stream.props[i];
221 if (prop_table.size() < static_cast<std::size_t>(prop + 1))
222 prop_table.resize(prop + 1, false);
223 prop_table[prop] = true;
224 }
225
226 if (!prop_table[mve::geom::PLY_V_FLOAT_X]
227 || !prop_table[mve::geom::PLY_V_FLOAT_Y]
228 || !prop_table[mve::geom::PLY_V_FLOAT_Z])
229 {
230 this->reset_stream_state();
231 throw util::Exception("Missing sample coordinates");
232 }
233 if (!prop_table[mve::geom::PLY_V_FLOAT_NX]
234 || !prop_table[mve::geom::PLY_V_FLOAT_NY]
235 || !prop_table[mve::geom::PLY_V_FLOAT_NZ])
236 {
237 this->reset_stream_state();
238 throw util::Exception("Missing sample normals");
239 }
240 if (!prop_table[mve::geom::PLY_V_FLOAT_VALUE])
241 {
242 this->reset_stream_state();
243 throw util::Exception("Missing sample scale");
244 }
245}
246
247bool
248SampleIO::next_sample (Sample* sample)
249{
250 while (this->next_sample_intern(sample))
251 if (this->process_sample(sample, &this->samples))
252 return true;
253 return false;
254}
255
256bool
257SampleIO::next_sample_intern (Sample* sample)
258{
259 if (this->stream.filename.empty())
260 throw std::runtime_error("Sample stream not initialized");
261 if (!this->stream.stream.good())
262 throw std::runtime_error("Sample stream broken");
263 if (this->stream.props.empty())
264 throw std::runtime_error("Invalid sample stream state");
265
266 sample->confidence = 1.0f;
267 sample->color = math::Vec3f(-1.0f);
268
269 if (this->stream.current_vertex == this->stream.num_vertices)
270 {
271 this->print_samples_state(&this->samples);
272 this->reset_samples_state(&this->samples);
273 this->reset_stream_state();
274 return false;
275 }
276
277 for (std::size_t i = 0; i < this->stream.props.size(); ++i)
278 {
279 mve::geom::PLYVertexProperty property = this->stream.props[i];
280 switch (property)
281 {
283 this->ply_read(&sample->pos[0]);
284 break;
286 this->ply_read(&sample->pos[1]);
287 break;
289 this->ply_read(&sample->pos[2]);
290 break;
292 this->ply_read(&sample->normal[0]);
293 break;
295 this->ply_read(&sample->normal[1]);
296 break;
298 this->ply_read(&sample->normal[2]);
299 break;
301 this->ply_read(&sample->color[0]);
302 break;
304 this->ply_read(&sample->color[1]);
305 break;
307 this->ply_read(&sample->color[2]);
308 break;
310 this->ply_read_convert(&sample->color[0]);
311 break;
313 this->ply_read_convert(&sample->color[1]);
314 break;
316 this->ply_read_convert(&sample->color[2]);
317 break;
319 this->ply_read(&sample->scale);
320 break;
322 this->ply_read(&sample->confidence);
323 break;
325 {
326 float dummy;
327 this->ply_read(&dummy);
328 break;
329 }
331 {
332 uint8_t dummy;
333 this->ply_read(&dummy);
334 break;
335 }
336 default:
337 this->reset_stream_state();
338 throw std::runtime_error("Invalid sample attribute");
339 }
340
341 if (this->stream.stream.eof())
342 {
343 this->reset_stream_state();
344 throw util::FileException(this->stream.filename, "Unexpected EOF");
345 }
346 }
347
348 this->stream.current_vertex += 1;
349 return true;
350}
351
352void
353SampleIO::ply_read (float* value)
354{
356 (this->stream.stream, this->stream.format);
357}
358
359void
360SampleIO::ply_read (uint8_t* value)
361{
362 *value = mve::geom::ply_read_value<uint8_t>
363 (this->stream.stream, this->stream.format);
364}
365
366void
367SampleIO::ply_read_convert (float* value)
368{
369 uint8_t temp;
370 this->ply_read(&temp);
371 *value = static_cast<float>(temp) / 255.0f;
372}
373
374void
375SampleIO::reset_stream_state (void)
376{
377 this->stream.filename.clear();
378 this->stream.stream.close();
379 this->stream.props.clear();
380 this->stream.format = mve::geom::PLY_UNKNOWN;
381 this->stream.num_vertices = 0;
382 this->stream.current_vertex = 0;
383}
384
385void
386SampleIO::reset_samples_state (SamplesState* state)
387{
388 state->num_skipped_zero_normal = 0;
389 state->num_skipped_invalid_confidence = 0;
390 state->num_skipped_invalid_scale = 0;
391 state->num_skipped_large_scale = 0;
392 state->num_unnormalized_normals = 0;
393}
394
395bool
396SampleIO::process_sample (Sample* sample, SamplesState* state)
397{
398 /* Skip invalid samples. */
399 if (sample->scale <= 0.0f)
400 {
401 state->num_skipped_invalid_scale += 1;
402 return false;
403 }
404 if (sample->confidence <= 0.0f)
405 {
406 state->num_skipped_invalid_confidence += 1;
407 return false;
408 }
409 if (sample->normal.square_norm() == 0.0f)
410 {
411 state->num_skipped_zero_normal += 1;
412 return false;
413 }
414
415 /* Process sample scale if requested. */
416 if (this->opts.max_scale > 0.0f && sample->scale > this->opts.max_scale)
417 {
418 state->num_skipped_large_scale += 1;
419 return false;
420 }
421
422 if (this->opts.min_scale > 0.0f)
423 sample->scale = std::max(this->opts.min_scale, sample->scale);
424 sample->scale *= this->opts.scale_factor;
425
426 /* Normalize normals. */
427 if (!MATH_EPSILON_EQ(1.0f, sample->normal.square_norm(), 1e-5f))
428 {
429 sample->normal.normalize();
430 state->num_unnormalized_normals += 1;
431 }
432
433 return true;
434}
435
436void
437SampleIO::print_samples_state (SamplesState* state)
438{
439 if (state->num_skipped_invalid_scale > 0)
440 {
441 std::cout << "WARNING: Skipped "
442 << state->num_skipped_invalid_scale
443 << " samples with invalid scale." << std::endl;
444 }
445 if (state->num_skipped_invalid_confidence > 0)
446 {
447 std::cout << "WARNING: Skipped "
448 << state->num_skipped_invalid_confidence
449 << " samples with zero confidence." << std::endl;
450 }
451 if (state->num_skipped_zero_normal > 0)
452 {
453 std::cout << "WARNING: Skipped "
454 << state->num_skipped_zero_normal
455 << " samples with zero-length normal." << std::endl;
456 }
457 if (state->num_skipped_large_scale > 0)
458 {
459 std::cout << "WARNING: Skipped "
460 << state->num_skipped_large_scale
461 << " samples with too large scale." << std::endl;
462 }
463 if (state->num_unnormalized_normals > 0)
464 {
465 std::cout << "WARNING: Normalized "
466 << state->num_unnormalized_normals
467 << " normals with non-unit length." << std::endl;
468 }
469}
470
Vector class for arbitrary dimensions and types.
Definition vector.h:87
std::vector< math::Vec3f > VertexList
Definition mesh.h:33
std::vector< float > ConfidenceList
Definition mesh.h:35
std::vector< math::Vec4f > ColorList
Definition mesh.h:34
std::vector< float > ValueList
Definition mesh.h:36
std::vector< math::Vec3f > NormalList
Definition mesh.h:95
std::shared_ptr< TriangleMesh > Ptr
Definition mesh.h:92
Universal, simple exception class.
Definition exception.h:24
Exception class for file exceptions with additional filename.
Definition exception.h:53
Simple tokenizer.
Definition tokenizer.h:29
void split(std::string const &str, char delim=' ', bool keep_empty=false)
Very simple tokenziation at a given delimiter characater.
Definition tokenizer.h:62
#define FSSR_NAMESPACE_END
Definition defines.h:14
#define FSSR_NAMESPACE_BEGIN
Definition defines.h:13
#define MATH_EPSILON_EQ(x, v, eps)
Definition defines.h:96
std::vector< Sample > SampleList
Representation of a list of samples.
Definition sample.h:31
Vector< float, 3 > Vec3f
Definition vector.h:31
TriangleMesh::Ptr load_ply_mesh(std::string const &filename)
Loads a triangle mesh from a PLY model file.
template float ply_read_value< float >(std::istream &input, PLYFormat format)
PLYVertexProperty
PLY vertex element properties.
@ PLY_V_IGNORE_FLOAT
@ PLY_V_IGNORE_UINT8
@ PLY_V_IGNORE_UINT32
@ PLY_V_FLOAT_VALUE
void clip_newlines(std::string *str)
Clips newlines from the end of the string, in-place.
Definition strings.h:317
void clip_whitespaces(std::string *str)
Clips whitespaces from the front and end of the string, in-place.
Definition strings.h:299
Representation of a point sample.
Definition sample.h:22
math::Vec3f pos
Definition sample.h:23
float confidence
Definition sample.h:27
math::Vec3f color
Definition sample.h:25
math::Vec3f normal
Definition sample.h:24
float scale
Definition sample.h:26