127 if (filename.empty())
128 throw std::invalid_argument(
"No filename given");
131 std::ifstream input(filename.c_str(), std::ios::binary);
145 std::getline(input, buffer);
148 std::size_t num_faces = 0;
149 std::size_t num_vertices = 0;
150 std::size_t num_grid = 0;
151 std::size_t num_tristrips = 0;
152 std::size_t grid_cols = 0;
153 std::size_t grid_rows = 0;
154 std::vector<PLYVertexProperty> v_format;
155 std::vector<PLYFaceProperty> f_format;
157 bool critical =
false;
158 bool reading_verts =
false;
159 bool reading_faces =
false;
160 bool reading_grid =
false;
161 bool reading_tristrips =
false;
162 std::size_t skip_bytes = 0;
166 std::getline(input, buffer);
172 if (buffer ==
"end_header")
176 header.
split(buffer);
181 if (header[0] ==
"format")
184 if (header[1] ==
"ascii")
186 else if (header[1] ==
"binary_little_endian")
188 else if (header[1] ==
"binary_big_endian")
193 else if (header[0] ==
"comment")
196 std::cout <<
"PLY Loader: " << buffer << std::endl;
198 else if (header[0] ==
"element")
200 reading_faces =
false;
201 reading_verts =
false;
202 reading_grid =
false;
203 reading_tristrips =
false;
204 if (header[1] ==
"vertex")
206 reading_verts =
true;
207 num_vertices = util::string::convert<std::size_t>(header[2]);
209 else if (header[1] ==
"face")
211 reading_faces =
true;
212 num_faces = util::string::convert<std::size_t>(header[2]);
214 else if (header[1] ==
"range_grid")
217 num_grid = util::string::convert<std::size_t>(header[2]);
219 else if (header[1] ==
"tristrips")
221 reading_tristrips =
true;
222 num_tristrips = util::string::convert<std::size_t>(header[2]);
226 std::cout <<
"PLY Loader: Element \"" << header[1]
227 <<
"\" not recognized" << std::endl;
231 if (header[1] ==
"camera")
234 else if (header[0] ==
"obj_info")
236 if (header[1] ==
"num_cols")
237 grid_cols = util::string::convert<std::size_t>(header[2]);
238 else if (header[1] ==
"num_rows")
239 grid_rows = util::string::convert<std::size_t>(header[2]);
241 else if (header[0] ==
"property")
246 if (header[1] ==
"float" || header[1] ==
"float32")
249 if (header[2] ==
"x")
251 else if (header[2] ==
"y")
253 else if (header[2] ==
"z")
255 else if (header[2] ==
"nx")
257 else if (header[2] ==
"ny")
259 else if (header[2] ==
"nz")
261 else if (header[2] ==
"r" || header[2] ==
"red")
263 else if (header[2] ==
"g" || header[2] ==
"green")
265 else if (header[2] ==
"b" || header[2] ==
"blue")
267 else if (header[2] ==
"u")
269 else if (header[2] ==
"v")
271 else if (header[2] ==
"confidence")
273 else if (header[2] ==
"value")
279 else if (header[1] ==
"double" || header[1] ==
"float64")
282 if (header[2] ==
"x")
284 else if (header[2] ==
"y")
286 else if (header[2] ==
"z")
291 else if (header[1] ==
"uchar" || header[1] ==
"uint8")
294 if (header[2] ==
"r" || header[2] ==
"red"
295 || header[2] ==
"diffuse_red")
297 else if (header[2] ==
"g" || header[2] ==
"green"
298 || header[2] ==
"diffuse_green")
300 else if (header[2] ==
"b" || header[2] ==
"blue"
301 || header[2] ==
"diffuse_blue")
306 else if (header[1] ==
"int")
314 std::cout <<
"PLY Loader: Unrecognized vertex property \""
315 << buffer <<
"\"" << std::endl;
320 else if (reading_faces)
322 if (header[1] ==
"list")
324 else if (header[1] ==
"int")
326 else if (header[1] ==
"uchar")
328 else if (header[1] ==
"float")
332 std::cout <<
"PLY Loader: Unrecognized face property \""
333 << buffer <<
"\"" << std::endl;
337 else if (reading_grid)
339 if (header[1] !=
"list")
341 std::cout <<
"PLY Loader: Unrecognized grid property \""
342 << buffer <<
"\"" << std::endl;
346 else if (reading_tristrips)
348 if (header[1] !=
"list")
350 std::cout <<
"PLY Loader: Unrecognized triangle strips "
351 "property \"" << buffer <<
"\"" << std::endl;
357 std::cout <<
"PLY Loader: Skipping property \""
358 << header[1] <<
"\" without element." << std::endl;
379 bool want_colors =
false;
380 bool want_vnormals =
false;
381 bool want_tex_coords =
false;
383 for (std::size_t i = 0; i < v_format.size(); ++i)
399 want_vnormals =
true;
404 want_tex_coords =
true;
415 std::cout <<
"PLY Loader: Skipping " << skip_bytes
416 <<
" bytes." << std::endl;
417 input.ignore(skip_bytes);
421 std::cout <<
"Reading PLY: " << num_vertices <<
" verts..." << std::flush;
423 vertices.reserve(num_vertices);
425 vcolors.reserve(num_vertices);
427 vnormals.reserve(num_vertices);
430 for (std::size_t i = 0; !eof && i < num_vertices; ++i)
437 for (std::size_t n = 0; n < v_format.size(); ++n)
446 = ply_read_value<float>(input, ply_format);
453 = ply_read_value<double>(input, ply_format);
460 = ply_read_value<float>(input, ply_format);
467 = (
float)ply_read_value<unsigned char>(input, ply_format)
475 = ply_read_value<float>(input, ply_format);
481 = ply_read_value<float>(input, ply_format);
485 vconfs.push_back(ply_read_value<float>(input, ply_format));
489 vvalues.push_back(ply_read_value<float>(input, ply_format));
493 ply_read_value<float>(input, ply_format);
497 ply_read_value<double>(input, ply_format);
501 ply_read_value<unsigned int>(input, ply_format);
505 ply_read_value<unsigned char>(input, ply_format);
509 throw std::runtime_error(
"Unhandled PLY vertex property");
513 vertices.push_back(vertex);
515 vnormals.push_back(vnormal);
517 vcolors.push_back(color);
519 tcoords.push_back(tex_coord);
526 std::cout <<
" " << num_faces <<
" faces..." << std::flush;
527 faces.reserve(num_faces * 3);
528 for (std::size_t i = 0; !eof && i < num_faces; ++i)
530 for (std::size_t n = 0; n < f_format.size(); ++n)
538 unsigned char n_verts = ply_read_value<unsigned char>(input, ply_format);
543 faces.push_back(ply_read_value<unsigned int>(input, ply_format));
544 faces.push_back(ply_read_value<unsigned int>(input, ply_format));
545 faces.push_back(ply_read_value<unsigned int>(input, ply_format));
547 else if (n_verts == 4)
550 unsigned int a = ply_read_value<unsigned int>(input, ply_format);
551 unsigned int b = ply_read_value<unsigned int>(input, ply_format);
552 unsigned int c = ply_read_value<unsigned int>(input, ply_format);
553 unsigned int d = ply_read_value<unsigned int>(input, ply_format);
571 else if (!input.eof())
573 std::cout <<
"PLY Loader: Ignoring face with "
574 <<
static_cast<int>(n_verts)
575 <<
" vertices!" << std::endl;
576 for (
int vid = 0; vid < n_verts; ++vid)
577 ply_read_value<unsigned int>(input, ply_format);
583 ply_read_value<int>(input, ply_format);
586 ply_read_value<unsigned char>(input, ply_format);
589 ply_read_value<float>(input, ply_format);
593 throw std::runtime_error(
"Unhandled PLY face property");
601 if (!eof && num_grid != 0 && num_grid == grid_rows * grid_cols)
603 std::cout <<
" " << num_grid <<
" range grid values..." << std::flush;
605 for (std::size_t i = 0; i < num_grid; ++i)
607 unsigned char indicator = ply_read_value<unsigned char>(input, ply_format);
609 img[i] =
static_cast<unsigned int>(-1);
611 img[i] = ply_read_value<unsigned int>(input, ply_format);
619 if (!eof && num_tristrips)
621 std::cout <<
" triangle strips..." << std::flush;
622 for (std::size_t i = 0; i < num_tristrips; ++i)
624 unsigned int num = ply_read_value<unsigned int>(input, ply_format);
625 int last_id1 = -1, last_id2 = -1;
626 bool inverted =
false;
627 for (
unsigned int j = 0; j < num; ++j)
629 int idx = ply_read_value<int>(input, ply_format);
639 faces.push_back(inverted ? last_id2 : last_id1);
640 faces.push_back(inverted ? last_id1 : last_id2);
641 faces.push_back(idx);
642 inverted = !inverted;
652 std::cout <<
" done." << std::endl;
654 std::cout <<
"WARNING: Premature EOF detected!" << std::endl;
691 throw std::invalid_argument(
"Null mesh given");
692 if (filename.empty())
693 throw std::invalid_argument(
"No filename given");
705 throw std::invalid_argument(
"Invalid amount of face indices");
709 write_vcolors = write_vcolors && verts.size() == vcolors.size();
711 write_vnormals = write_vnormals && verts.size() == vnormals.size();
713 write_vconfidences = write_vconfidences && verts.size() == conf.size();
715 write_vvalues = write_vvalues && verts.size() == vvalues.size();
717 write_fcolors = write_fcolors && fcolors.size() == face_amount;
719 write_fnormals = write_fnormals && fnormals.size() == face_amount;
722 ?
"binary_little_endian"
726 std::ofstream out(filename.c_str(), std::ios::binary);
730 std::cout <<
"Writing PLY file (" << verts.size() <<
" verts"
731 << (write_vcolors ?
", with colors" :
"")
732 << (write_vnormals ?
", with normals" :
"")
733 << (write_vconfidences ?
", with confidences" :
"")
734 << (write_vvalues ?
", with values" :
"")
735 <<
", " << face_amount <<
" faces"
736 << (write_fcolors ?
", with colors" :
"")
737 << (write_fnormals ?
", with normals" :
"")
738 <<
")... " << std::flush;
741 out <<
"ply" << std::endl;
742 out <<
"format " << format_str <<
" 1.0" << std::endl;
743 out <<
"comment Export generated by libmve" << std::endl;
744 out <<
"element vertex " << verts.size() << std::endl;
745 out <<
"property float x" << std::endl;
746 out <<
"property float y" << std::endl;
747 out <<
"property float z" << std::endl;
751 out <<
"property float nx" << std::endl;
752 out <<
"property float ny" << std::endl;
753 out <<
"property float nz" << std::endl;
758 out <<
"property uchar red" << std::endl;
759 out <<
"property uchar green" << std::endl;
760 out <<
"property uchar blue" << std::endl;
763 if (write_vconfidences)
765 out <<
"property float confidence" << std::endl;
770 out <<
"property float value" << std::endl;
775 out <<
"element face " << face_amount << std::endl;
776 out <<
"property list uchar int vertex_indices" << std::endl;
780 out <<
"property float nx" << std::endl;
781 out <<
"property float ny" << std::endl;
782 out <<
"property float nz" << std::endl;
787 out <<
"property uchar red" << std::endl;
788 out <<
"property uchar green" << std::endl;
789 out <<
"property uchar blue" << std::endl;
793 out <<
"end_header" << std::endl;
798 for (std::size_t i = 0; i < verts.size(); ++i)
800 out.write((
char const*)*verts[i], 3 *
sizeof(float));
802 out.write((
char const*)*vnormals[i], 3 *
sizeof(float));
805 unsigned char color[3];
807 out.write((
char const*)color, 3);
809 if (write_vconfidences)
810 out.write((
char const*)&conf[i],
sizeof(
float));
812 out.write((
char const*)&vvalues[i],
sizeof(
float));
816 for (std::size_t i = 0; i < face_amount; ++i)
818 out.write((
char const*)&verts_per_simplex_uchar, 1);
822 out.write((
char const*)*fnormals[i], 3 *
sizeof(
float));
825 unsigned char color[3];
827 out.write((
char const*)color, 3);
834 out << std::fixed << std::setprecision(7);
835 for (std::size_t i = 0; i < verts.size(); ++i)
837 out << verts[i][0] <<
" "
838 << verts[i][1] <<
" "
842 for (
int c = 0; c < 3; ++c)
843 out <<
" " << vnormals[i][c];
845 for (
int c = 0; c < 3; ++c)
847 float color = 255.0f * vcolors[i][c];
848 color = std::min(255.0f, std::max(0.0f, color));
849 out <<
" " << (int)(color + 0.5f);
851 if (write_vconfidences)
852 out <<
" " << conf[i];
854 out <<
" " << vvalues[i];
858 for (std::size_t i = 0; i < face_amount; ++i)
864 for (
int j = 0; j < 3; ++j)
865 out <<
" " << fnormals[i][j];
867 for (
int j = 0; j < 3; ++j)
869 float color = 255.0f * fcolors[i][j];
870 color = std::min(255.0f, std::max(0.0f, color));
871 out <<
" " << (int)(color + 0.5f);
878 std::cout <<
"done." << std::endl;
889 if (depth_map ==
nullptr)
890 throw std::invalid_argument(
"Null depth map given");
893 if (filename.empty())
894 throw std::invalid_argument(
"No filename given");
896 int const width = depth_map->width();
897 int const height = depth_map->height();
901 if (confidence_map !=
nullptr && (confidence_map->height() != height
902 || confidence_map->width() != width))
903 throw std::invalid_argument(
"Confidence map dimension does not match");
905 if (color_image !=
nullptr && (color_image->width() != width
906 || color_image->height() != height))
907 throw std::invalid_argument(
"Color image dimension does not match");
910 std::ofstream out(filename.c_str(), std::ios::binary);
914 std::cout <<
"Writing PLY file for image size "
915 << width <<
"x" << height <<
"..." << std::endl;
917 std::cout <<
"Counting... " << std::flush;
921 int num_pixels = width * height;
922 if (confidence_map !=
nullptr)
924 for (
int i = 0; i < num_pixels; ++i)
925 if (confidence_map->at(i, 0) > 0.0f)
930 for (
int i = 0; i < num_pixels; ++i)
931 if (depth_map->at(i, 0) > 0.0f)
935 std::cout <<
"(" << num_verts <<
"), " << std::flush;
938 out <<
"ply" << std::endl;
939 out <<
"format binary_little_endian 1.0" << std::endl;
940 out <<
"comment Export generated by libmve" << std::endl;
941 out <<
"obj_info num_cols " << width << std::endl;
942 out <<
"obj_info num_rows " << height << std::endl;
943 out <<
"element vertex " << num_verts << std::endl;
944 out <<
"property float x" << std::endl;
945 out <<
"property float y" << std::endl;
946 out <<
"property float z" << std::endl;
948 if (color_image !=
nullptr)
950 out <<
"property uchar red" << std::endl;
951 out <<
"property uchar green" << std::endl;
952 out <<
"property uchar blue" << std::endl;
955 if (confidence_map !=
nullptr)
957 out <<
"property float confidence" << std::endl;
960 out <<
"element range_grid " << (width * height) << std::endl;
961 out <<
"property list uchar int vertex_indices" << std::endl;
962 out <<
"end_header" << std::endl;
965 std::cout <<
"writing vertices... " << std::flush;
966 for (
int i = 0; i < num_pixels; ++i)
968 int const x = i % width;
969 int const y = i / width;
970 int const yinv = height - y - 1;
972 float confidence = 0.0f;
973 if (confidence_map !=
nullptr)
975 confidence = confidence_map->at(x, yinv, 0);
976 if (confidence <= 0.0f)
980 float depth = depth_map->at(x, yinv, 0);
988 out.write((
char const*)pos.
begin(), 3 *
sizeof(
float));
989 if (color_image !=
nullptr)
991 unsigned char const* c_off = &color_image->at(x, yinv, 0);
992 out.write((
char const*)c_off, 3);
995 if (confidence_map !=
nullptr)
996 out.write((
char const*)&confidence,
sizeof(
float));
999 std::cout <<
"writing range points... " << std::flush;
1003 for (
int i = 0; i < num_pixels; ++i)
1005 int const x = i % width;
1006 int const y = i / width;
1007 int const yinv = height - y - 1;
1010 if (confidence_map !=
nullptr && confidence_map->at(x, yinv, 0) <= 0.0f)
1012 if (valid && depth_map->at(x, yinv, 0) <= 0.0f)
1015 out.write((
char const*)&valid, 1);
1018 out.write((
char const*)&
vertex_id,
sizeof(
int));
1025 std::cout <<
"done." << std::endl;
1086 if (filename.empty())
1087 throw std::invalid_argument(
"No filename given");
1090 std::fstream input(filename.c_str());
1097 if (buffer !=
"ply")
1104 std::getline(input, buffer);
1106 std::size_t n_verts = 0;
1110 while (input.good())
1112 std::getline(input, buffer);
1122 if (t.size() == 3 && t[0] ==
"element" && t[1] ==
"vertex")
1123 n_verts = util::string::convert<std::size_t>(t[2]);
1124 if (t.size() == 3 && t[0] ==
"element" && t[1] ==
"range_grid")
1125 n_grid = util::string::convert<int>(t[2]);
1126 if (t.size() == 3 && t[0] ==
"obj_info" && t[1] ==
"num_cols")
1127 width = util::string::convert<int>(t[2]);
1128 if (t.size() == 3 && t[0] ==
"obj_info" && t[1] ==
"num_rows")
1129 height = util::string::convert<int>(t[2]);
1130 if (t.size() == 1 && t[0] ==
"end_header")
1134 if (!n_verts || !n_grid || !width || !height || n_grid != width * height)
1142 for (std::size_t i = 0; i < n_verts; ++i)
1145 input >> x >> y >> z;
1150 std::getline(input, buffer);
1154 for (
int i = 0; i < n_grid; ++i)
1157 int const idx = (height - (i / width) - 1) * width + (i % width);
1159 std::getline(input, buffer);
1167 std::cout <<
"Warning: Early EOF while parsing PLY" << std::endl;
1171 if (t.empty() || t[0] !=
"1")
1173 ret->at(idx) = 0.0f;
1177 std::size_t vid = util::string::convert<std::size_t>(t[1]);
1178 if (vid >= verts.size())
1180 std::cout <<
"Warning: Vertex index out of bounds" << std::endl;
1181 ret->at(idx) = 0.0f;
1185 ret->at(idx) = verts[vid].norm();