00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <fstream>
00039 #include <fcntl.h>
00040 #include <string>
00041 #include <map>
00042 #include <stdlib.h>
00043 #include <pcl/point_types.h>
00044 #include <pcl/common/io.h>
00045 #include <pcl/io/ply_io.h>
00046 #include <sstream>
00047 #include <boost/algorithm/string.hpp>
00048
00049 boost::tuple<boost::function<void ()>, boost::function<void ()> >
00050 pcl::PLYReader::elementDefinitionCallback (const std::string& element_name, std::size_t count)
00051 {
00052 if (element_name == "vertex")
00053 {
00054 cloud_->data.clear ();
00055 cloud_->fields.clear ();
00056 cloud_->width = static_cast<uint32_t> (count);
00057 cloud_->height = 1;
00058 cloud_->is_dense = false;
00059 cloud_->point_step = 0;
00060 cloud_->row_step = 0;
00061 vertex_count_ = 0;
00062 return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (
00063 boost::bind (&pcl::PLYReader::vertexBeginCallback, this),
00064 boost::bind (&pcl::PLYReader::vertexEndCallback, this)));
00065 }
00066
00067
00068
00069
00070
00071
00072 else if (element_name == "camera")
00073 {
00074 cloud_->is_dense = true;
00075 return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (0, 0));
00076 }
00077 else if (element_name == "range_grid")
00078 {
00079 (*range_grid_).resize (count);
00080 range_count_ = 0;
00081 return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (
00082 boost::bind (&pcl::PLYReader::rangeGridBeginCallback, this),
00083 boost::bind (&pcl::PLYReader::rangeGridEndCallback, this)));
00084 }
00085 else
00086 {
00087 return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (0, 0));
00088 }
00089 }
00090
00091 bool
00092 pcl::PLYReader::endHeaderCallback ()
00093 {
00094 cloud_->data.resize (cloud_->point_step * cloud_->width * cloud_->height);
00095 return (cloud_->data.size () == cloud_->point_step * cloud_->width * cloud_->height);
00096 }
00097
00098 void
00099 pcl::PLYReader::appendFloatProperty (const std::string& name, const size_t& size)
00100 {
00101 cloud_->fields.push_back (::sensor_msgs::PointField ());
00102 ::sensor_msgs::PointField ¤t_field = cloud_->fields.back ();
00103 current_field.name = name;
00104 current_field.offset = cloud_->point_step;
00105 current_field.datatype = ::sensor_msgs::PointField::FLOAT32;
00106 current_field.count = static_cast<uint32_t> (size);
00107 cloud_->point_step += static_cast<uint32_t> (pcl::getFieldSize (::sensor_msgs::PointField::FLOAT32) * size);
00108 }
00109
00110 namespace pcl
00111 {
00112 template <>
00113 boost::function<void (pcl::io::ply::float32)>
00114 PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00115 {
00116 if (element_name == "vertex")
00117 {
00118 appendFloatProperty (property_name, 1);
00119 return (boost::bind (&pcl::PLYReader::vertexFloatPropertyCallback, this, _1));
00120 }
00121 else if (element_name == "camera")
00122 {
00123 if (property_name == "view_px")
00124 {
00125 return boost::bind (&pcl::PLYReader::originXCallback, this, _1);
00126 }
00127 else if (property_name == "view_py")
00128 {
00129 return boost::bind (&pcl::PLYReader::originYCallback, this, _1);
00130 }
00131 else if (property_name == "view_pz")
00132 {
00133 return boost::bind (&pcl::PLYReader::originZCallback, this, _1);
00134 }
00135 else if (property_name == "x_axisx")
00136 {
00137 return boost::bind (&pcl::PLYReader::orientationXaxisXCallback, this, _1);
00138 }
00139 else if (property_name == "x_axisy")
00140 {
00141 return boost::bind (&pcl::PLYReader::orientationXaxisYCallback, this, _1);
00142 }
00143 else if (property_name == "x_axisz")
00144 {
00145 return boost::bind (&pcl::PLYReader::orientationXaxisZCallback, this, _1);
00146 }
00147 else if (property_name == "y_axisx")
00148 {
00149 return boost::bind (&pcl::PLYReader::orientationYaxisXCallback, this, _1);
00150 }
00151 else if (property_name == "y_axisy")
00152 {
00153 return boost::bind (&pcl::PLYReader::orientationYaxisYCallback, this, _1);
00154 }
00155 else if (property_name == "y_axisz")
00156 {
00157 return boost::bind (&pcl::PLYReader::orientationYaxisZCallback, this, _1);
00158 }
00159 else if (property_name == "z_axisx")
00160 {
00161 return boost::bind (&pcl::PLYReader::orientationZaxisXCallback, this, _1);
00162 }
00163 else if (property_name == "z_axisy")
00164 {
00165 return boost::bind (&pcl::PLYReader::orientationZaxisYCallback, this, _1);
00166 }
00167 else if (property_name == "z_axisz")
00168 {
00169 return boost::bind (&pcl::PLYReader::orientationZaxisZCallback, this, _1);
00170 }
00171 else
00172 {
00173 return (0);
00174 }
00175 }
00176 else
00177 {
00178 return (0);
00179 }
00180 }
00181
00182 template <> boost::function<void (pcl::io::ply::uint8)>
00183 PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00184 {
00185 if (element_name == "vertex")
00186 {
00187 if ((property_name == "red") || (property_name == "green") || (property_name == "blue") ||
00188 (property_name == "diffuse_red") || (property_name == "diffuse_green") || (property_name == "diffuse_blue") )
00189 {
00190 if ((property_name == "red") || (property_name == "diffuse_red"))
00191 appendFloatProperty ("rgb");
00192 return boost::bind (&pcl::PLYReader::vertexColorCallback, this, property_name, _1);
00193 }
00194 else if (property_name == "intensity")
00195 {
00196 appendFloatProperty (property_name);
00197 return boost::bind (&pcl::PLYReader::vertexIntensityCallback, this, _1);
00198 }
00199 else
00200 return (0);
00201 }
00202 else
00203 return (0);
00204 }
00205
00206 template <> boost::function<void (pcl::io::ply::int32)>
00207 PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00208 {
00209 if (element_name == "camera")
00210 {
00211 if (property_name == "viewportx")
00212 {
00213 return boost::bind (&pcl::PLYReader::cloudWidthCallback, this, _1);
00214 }
00215 else if (property_name == "viewporty")
00216 {
00217 return boost::bind (&pcl::PLYReader::cloudHeightCallback, this, _1);
00218 }
00219 else
00220 {
00221 return (0);
00222 }
00223 }
00224 else
00225 return (0);
00226 }
00227
00228 template <>
00229 boost::tuple<boost::function<void (pcl::io::ply::uint8)>, boost::function<void (pcl::io::ply::int32)>, boost::function<void ()> >
00230 pcl::PLYReader::listPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00231 {
00232 if ((element_name == "range_grid") && (property_name == "vertex_indices")) {
00233 return boost::tuple<boost::function<void (pcl::io::ply::uint8)>, boost::function<void (pcl::io::ply::int32)>, boost::function<void ()> > (
00234 boost::bind (&pcl::PLYReader::rangeGridVertexIndicesBeginCallback, this, _1),
00235 boost::bind (&pcl::PLYReader::rangeGridVertexIndicesElementCallback, this, _1),
00236 boost::bind (&pcl::PLYReader::rangeGridVertexIndicesEndCallback, this)
00237 );
00238 }
00239
00240
00241
00242
00243
00244
00245
00246 else {
00247 return boost::tuple<boost::function<void (pcl::io::ply::uint8)>, boost::function<void (pcl::io::ply::int32)>, boost::function<void ()> > (0, 0, 0);
00248 }
00249 }
00250 }
00251
00252 void
00253 pcl::PLYReader::vertexFloatPropertyCallback (pcl::io::ply::float32 value)
00254 {
00255 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00256 &value,
00257 sizeof (pcl::io::ply::float32));
00258 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::float32));
00259 }
00260
00261 void
00262 pcl::PLYReader::vertexColorCallback (const std::string& color_name, pcl::io::ply::uint8 color)
00263 {
00264 static int32_t r, g, b;
00265 if ((color_name == "red") || (color_name == "diffuse_red"))
00266 {
00267 r = int32_t (color);
00268 rgb_offset_before_ = vertex_offset_before_;
00269 }
00270 if ((color_name == "green") || (color_name == "diffuse_green"))
00271 {
00272 g = int32_t (color);
00273 }
00274 if ((color_name == "blue") || (color_name == "diffuse_blue"))
00275 {
00276 b = int32_t (color);
00277 int32_t rgb = r << 16 | g << 8 | b;
00278 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + rgb_offset_before_],
00279 &rgb,
00280 sizeof (int32_t));
00281 vertex_offset_before_ += static_cast<int> (sizeof (int32_t));
00282 }
00283 }
00284
00285 void
00286 pcl::PLYReader::vertexIntensityCallback (pcl::io::ply::uint8 intensity)
00287 {
00288 pcl::io::ply::float32 intensity_ (intensity);
00289 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00290 &intensity_,
00291 sizeof (pcl::io::ply::float32));
00292 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::float32));
00293 }
00294
00295 void
00296 pcl::PLYReader::vertexBeginCallback ()
00297 {
00298 vertex_offset_before_ = 0;
00299 }
00300
00301 void
00302 pcl::PLYReader::vertexEndCallback ()
00303 {
00304 ++vertex_count_;
00305 }
00306
00307 void
00308 pcl::PLYReader::rangeGridBeginCallback () { }
00309
00310 void
00311 pcl::PLYReader::rangeGridVertexIndicesBeginCallback (pcl::io::ply::uint8 size)
00312 {
00313 (*range_grid_)[range_count_].reserve (size);
00314 }
00315
00316 void pcl::PLYReader::rangeGridVertexIndicesElementCallback (pcl::io::ply::int32 vertex_index)
00317 {
00318 (*range_grid_)[range_count_].push_back (vertex_index);
00319 }
00320
00321 void
00322 pcl::PLYReader::rangeGridVertexIndicesEndCallback () { }
00323
00324 void
00325 pcl::PLYReader::rangeGridEndCallback ()
00326 {
00327 ++range_count_;
00328 }
00329
00330 void
00331 pcl::PLYReader::objInfoCallback (const std::string& line)
00332 {
00333 std::vector<std::string> st;
00334 boost::split (st, line, boost::is_any_of (std::string ( "\t\r ")), boost::token_compress_on);
00335 assert (st[0].substr (0, 8) == "obj_info");
00336 {
00337 assert (st.size () == 3);
00338 {
00339 if (st[1] == "num_cols")
00340 cloudWidthCallback (atoi (st[2].c_str ()));
00341 else if (st[1] == "num_rows")
00342 cloudHeightCallback (atoi (st[2].c_str ()));
00343 else if (st[1] == "echo_rgb_offset_x")
00344 originXCallback (static_cast<float> (atof (st[2].c_str ())));
00345 else if (st[1] == "echo_rgb_offset_y")
00346 originYCallback (static_cast<float> (atof (st[2].c_str ())));
00347 else if (st[1] == "echo_rgb_offset_z")
00348 originZCallback (static_cast<float> (atof (st[2].c_str ())));
00349 }
00350 }
00351 }
00352
00353 bool
00354 pcl::PLYReader::parse (const std::string& istream_filename)
00355 {
00356 pcl::io::ply::ply_parser::flags_type ply_parser_flags = 0;
00357 pcl::io::ply::ply_parser ply_parser (ply_parser_flags);
00358
00359 ply_parser.info_callback (boost::bind (&pcl::PLYReader::infoCallback, this, boost::ref (istream_filename), _1, _2));
00360 ply_parser.warning_callback (boost::bind (&pcl::PLYReader::warningCallback, this, boost::ref (istream_filename), _1, _2));
00361 ply_parser.error_callback (boost::bind (&pcl::PLYReader::errorCallback, this, boost::ref (istream_filename), _1, _2));
00362
00363 ply_parser.element_definition_callback (boost::bind (&pcl::PLYReader::elementDefinitionCallback, this, _1, _2));
00364 ply_parser.end_header_callback (boost::bind (&pcl::PLYReader::endHeaderCallback, this));
00365
00366 pcl::io::ply::ply_parser::scalar_property_definition_callbacks_type scalar_property_definition_callbacks;
00367 pcl::io::ply::at<pcl::io::ply::float32> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::float32>, this, _1, _2);
00368 pcl::io::ply::at<pcl::io::ply::uint8> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::uint8>, this, _1, _2);
00369 pcl::io::ply::at<pcl::io::ply::int32> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::int32>, this, _1, _2);
00370 ply_parser.scalar_property_definition_callbacks (scalar_property_definition_callbacks);
00371
00372 pcl::io::ply::ply_parser::list_property_definition_callbacks_type list_property_definition_callbacks;
00373 pcl::io::ply::at<pcl::io::ply::uint8, pcl::io::ply::int32> (list_property_definition_callbacks) = boost::bind (&pcl::PLYReader::listPropertyDefinitionCallback<pcl::io::ply::uint8, pcl::io::ply::int32>, this, _1, _2);
00374 ply_parser.list_property_definition_callbacks (list_property_definition_callbacks);
00375
00376 return ply_parser.parse (istream_filename);
00377 }
00378
00380 int
00381 pcl::PLYReader::readHeader (const std::string &file_name, sensor_msgs::PointCloud2 &cloud,
00382 Eigen::Vector4f &, Eigen::Quaternionf &,
00383 int &, int &, unsigned int &, const int)
00384 {
00385
00386 cloud_ = &cloud;
00387 range_grid_ = new std::vector<std::vector<int> >;
00388 if (!parse (file_name))
00389 {
00390 PCL_ERROR ("[pcl::PLYReader::read] problem parsing header!\n");
00391 return (-1);
00392 }
00393 cloud_->row_step = cloud_->point_step * cloud_->width;
00394 return 0;
00395 }
00396
00398 int
00399 pcl::PLYReader::read (const std::string &file_name, sensor_msgs::PointCloud2 &cloud,
00400 Eigen::Vector4f &origin, Eigen::Quaternionf &orientation, int &ply_version, const int)
00401 {
00402
00403 int data_type;
00404 unsigned int data_idx;
00405
00406 if (this->readHeader (file_name, cloud, origin, orientation, ply_version, data_type, data_idx))
00407 {
00408 PCL_ERROR ("[pcl::PLYReader::read] problem parsing header!\n");
00409 return (-1);
00410 }
00411
00412
00413 size_t r_size;
00414 if ((r_size = (*range_grid_).size ()) > 0 && r_size != vertex_count_)
00415 {
00416
00417 std::vector<pcl::uint8_t> data ((*range_grid_).size () * cloud.point_step);
00418 const static float f_nan = std::numeric_limits <float>::quiet_NaN ();
00419 const static double d_nan = std::numeric_limits <double>::quiet_NaN ();
00420 for (size_t r = 0; r < r_size; ++r)
00421 {
00422 if ((*range_grid_)[r].size () == 0)
00423 {
00424 for (size_t f = 0; f < cloud_->fields.size (); ++f)
00425 if (cloud_->fields[f].datatype == ::sensor_msgs::PointField::FLOAT32)
00426
00427 memcpy (&data[r * cloud_->point_step + cloud_->fields[f].offset],
00428 reinterpret_cast<const char*> (&f_nan), sizeof (float));
00429 else if (cloud_->fields[f].datatype == ::sensor_msgs::PointField::FLOAT64)
00430
00431 memcpy (&data[r * cloud_->point_step + cloud_->fields[f].offset],
00432 reinterpret_cast<const char*> (&d_nan), sizeof (double));
00433 else
00434 memset (&data[r * cloud_->point_step + cloud_->fields[f].offset], 0,
00435 pcl::getFieldSize (cloud_->fields[f].datatype) * cloud_->fields[f].count);
00436 }
00437 else
00438 memcpy (&data[r* cloud_->point_step], &cloud_->data[(*range_grid_)[r][0] * cloud_->point_step], cloud_->point_step);
00439 }
00440 cloud_->data.swap (data);
00441 cloud_->is_dense = true;
00442 }
00443
00444 orientation = Eigen::Quaternionf (orientation_);
00445 origin = origin_;
00446
00447 return (0);
00448 }
00449
00451
00452 std::string
00453 pcl::PLYWriter::generateHeader (const sensor_msgs::PointCloud2 &cloud,
00454 const Eigen::Vector4f &origin,
00455 const Eigen::Quaternionf &,
00456 bool binary,
00457 bool use_camera,
00458 int valid_points)
00459 {
00460 std::ostringstream oss;
00461
00462 oss << "ply";
00463 if (!binary)
00464 oss << "\nformat ascii 1.0";
00465 else
00466 {
00467 if (cloud.is_bigendian)
00468 oss << "\nformat binary_big_endian 1.0";
00469 else
00470 oss << "\nformat binary_little_endian 1.0";
00471 }
00472 oss << "\ncomment PCL generated";
00473
00474 if (!use_camera)
00475 {
00476 oss << "\nobj_info is_cyberware_data 0"
00477 "\nobj_info is_mesh 0"
00478 "\nobj_info is_warped 0"
00479 "\nobj_info is_interlaced 0";
00480 oss << "\nobj_info num_cols " << cloud.width;
00481 oss << "\nobj_info num_rows " << cloud.height;
00482 oss << "\nobj_info echo_rgb_offset_x " << origin[0];
00483 oss << "\nobj_info echo_rgb_offset_y " << origin[1];
00484 oss << "\nobj_info echo_rgb_offset_z " << origin[2];
00485 oss << "\nobj_info echo_rgb_frontfocus 0.0"
00486 "\nobj_info echo_rgb_backfocus 0.0"
00487 "\nobj_info echo_rgb_pixelsize 0.0"
00488 "\nobj_info echo_rgb_centerpixel 0"
00489 "\nobj_info echo_frames 1"
00490 "\nobj_info echo_lgincr 0.0";
00491 }
00492
00493 const std::string &fields_list = getFieldsList (cloud);
00494
00495 size_t xyz_found = fields_list.find ("x y z", 0);
00496 if (xyz_found != std::string::npos)
00497 {
00498 oss << "\nelement vertex "<< valid_points;
00499 oss << "\nproperty float x"
00500 "\nproperty float y"
00501 "\nproperty float z";
00502
00503 xyz_found+=5;
00504
00505 if (fields_list.find ("intensity", xyz_found) != std::string::npos)
00506 oss << "\nproperty float intensity";
00507
00508 if (fields_list.find ("rgb", xyz_found) != std::string::npos)
00509 oss << "\nproperty uchar red"
00510 "\nproperty uchar green"
00511 "\nproperty uchar blue";
00512
00513 if (fields_list.find ("rgba", xyz_found) != std::string::npos)
00514 oss << "\nproperty uchar alpha";
00515
00516 if (fields_list.find ("normal_x normal_y normal_z", xyz_found) != std::string::npos)
00517 oss << "\nproperty float nx"
00518 "\nproperty float ny"
00519 "\nproperty float nz"
00520 "\nproperty float curvature";
00521
00522 if (fields_list.find ("radius", xyz_found) != std::string::npos)
00523 oss << "\nproperty float radius";
00524
00525 if (fields_list.find ("vp_x vp_y vp_z", xyz_found) != std::string::npos)
00526 oss << "\nproperty float vp_x"
00527 "\nproperty float vp_y"
00528 "\nproperty float vp_z";
00529
00530 if (fields_list.find ("range", xyz_found) != std::string::npos)
00531 oss << "\nproperty float range";
00532
00533 if (fields_list.find ("strength", xyz_found) != std::string::npos)
00534 oss << "\nproperty float strength";
00535
00536 if (fields_list.find ("confidence", xyz_found) != std::string::npos)
00537 oss << "\nproperty float confidence";
00538 }
00539 else
00540 {
00541 if (fields_list.find ("normal_x normal_y normal_z", 0) != std::string::npos)
00542 {
00543 oss << "\nelement vertex "<< valid_points;
00544 oss << "\nproperty float nx"
00545 "\nproperty float ny"
00546 "\nproperty float nz"
00547 "\nproperty float curvature";
00548 }
00549 else
00550 {
00551 if (fields_list.find ("x y", 0) != std::string::npos)
00552 {
00553 oss << "\nelement vertex "<< valid_points;
00554 oss << "\nproperty float x"
00555 "\nproperty float y";
00556 }
00557 else
00558 PCL_ERROR ("[pcl::PLYWriter] PLY file format doesn't handle this kind of data: %s!\n", fields_list.c_str ());
00559 }
00560 }
00561
00562 if (use_camera)
00563 {
00564 oss << "\nelement camera 1"
00565 "\nproperty float view_px"
00566 "\nproperty float view_py"
00567 "\nproperty float view_pz"
00568 "\nproperty float x_axisx"
00569 "\nproperty float x_axisy"
00570 "\nproperty float x_axisz"
00571 "\nproperty float y_axisx"
00572 "\nproperty float y_axisy"
00573 "\nproperty float y_axisz"
00574 "\nproperty float z_axisx"
00575 "\nproperty float z_axisy"
00576 "\nproperty float z_axisz"
00577 "\nproperty float focal"
00578 "\nproperty float scalex"
00579 "\nproperty float scaley"
00580 "\nproperty float centerx"
00581 "\nproperty float centery"
00582 "\nproperty int viewportx"
00583 "\nproperty int viewporty"
00584 "\nproperty float k1"
00585 "\nproperty float k2";
00586 }
00587 else
00588 {
00589 oss << "\nelement range_grid " << cloud.width * cloud.height;
00590 oss << "\nproperty list uchar int vertex_indices";
00591 }
00592
00593
00594 oss << "\nend_header\n";
00595 return (oss.str ());
00596 }
00597
00599
00600 int
00601 pcl::PLYWriter::writeASCII (const std::string &file_name,
00602 const sensor_msgs::PointCloud2 &cloud,
00603 const Eigen::Vector4f &origin,
00604 const Eigen::Quaternionf &orientation,
00605 int precision,
00606 bool use_camera)
00607 {
00608 if (cloud.data.empty ())
00609 {
00610 PCL_ERROR ("[pcl::PLYWriter::writeASCII] Input point cloud has no data!\n");
00611 return (-1);
00612 }
00613
00614 std::ofstream fs;
00615 fs.precision (precision);
00616
00617 fs.open (file_name.c_str ());
00618 if (!fs)
00619 {
00620 PCL_ERROR ("[pcl::PLYWriter::writeASCII] Error during opening (%s)!\n", file_name.c_str ());
00621 return (-1);
00622 }
00623
00624 unsigned int nr_points = cloud.width * cloud.height;
00625 unsigned int point_size = static_cast<unsigned int> (cloud.data.size () / nr_points);
00626
00627
00628 if (use_camera)
00629 {
00630 fs << generateHeader (cloud, origin, orientation, false, use_camera, nr_points);
00631 writeContentWithCameraASCII (nr_points, point_size, cloud, origin, orientation, fs);
00632 }
00633 else
00634 {
00635 std::ostringstream os;
00636 int nr_valid_points;
00637 writeContentWithRangeGridASCII (nr_points, point_size, cloud, os, nr_valid_points);
00638 fs << generateHeader (cloud, origin, orientation, false, use_camera, nr_valid_points);
00639 fs << os.str ();
00640 }
00641
00642
00643 fs.close ();
00644 return (0);
00645 }
00646
00647 void
00648 pcl::PLYWriter::writeContentWithCameraASCII (int nr_points,
00649 int point_size,
00650 const sensor_msgs::PointCloud2 &cloud,
00651 const Eigen::Vector4f &origin,
00652 const Eigen::Quaternionf &orientation,
00653 std::ofstream& fs)
00654 {
00655
00656 for (int i = 0; i < nr_points; ++i)
00657 {
00658 for (size_t d = 0; d < cloud.fields.size (); ++d)
00659 {
00660 int count = cloud.fields[d].count;
00661 if (count == 0)
00662 count = 1;
00663
00664 for (int c = 0; c < count; ++c)
00665 {
00666 switch (cloud.fields[d].datatype)
00667 {
00668 case sensor_msgs::PointField::INT8:
00669 {
00670 char value;
00671 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (char)], sizeof (char));
00672 fs << boost::numeric_cast<int> (value);
00673 break;
00674 }
00675 case sensor_msgs::PointField::UINT8:
00676 {
00677 unsigned char value;
00678 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned char)], sizeof (unsigned char));
00679 fs << boost::numeric_cast<int> (value);
00680 break;
00681 }
00682 case sensor_msgs::PointField::INT16:
00683 {
00684 short value;
00685 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (short)], sizeof (short));
00686 fs << boost::numeric_cast<int> (value);
00687 break;
00688 }
00689 case sensor_msgs::PointField::UINT16:
00690 {
00691 unsigned short value;
00692 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned short)], sizeof (unsigned short));
00693 fs << boost::numeric_cast<int> (value);
00694 break;
00695 }
00696 case sensor_msgs::PointField::INT32:
00697 {
00698 int value;
00699 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (int)], sizeof (int));
00700 fs << value;
00701 break;
00702 }
00703 case sensor_msgs::PointField::UINT32:
00704 {
00705 if (cloud.fields[d].name.find ("rgb") == std::string::npos)
00706 {
00707 unsigned int value;
00708 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (unsigned int));
00709 fs << value;
00710 }
00711 else
00712 {
00713 pcl::RGB color;
00714 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (pcl::RGB));
00715 int r = color.r;
00716 int g = color.g;
00717 int b = color.b;
00718 fs << r << " " << g << " " << b;
00719 if (cloud.fields[d].name.find ("rgba") != std::string::npos)
00720 {
00721 int a = color.a;
00722 fs << " " << a;
00723 }
00724 }
00725 break;
00726 }
00727 case sensor_msgs::PointField::FLOAT32:
00728 {
00729 if (cloud.fields[d].name.find ("rgb") == std::string::npos)
00730 {
00731 float value;
00732 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
00733 fs << value;
00734 }
00735 else
00736 {
00737 pcl::RGB color;
00738 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (pcl::RGB));
00739 int r = color.r;
00740 int g = color.g;
00741 int b = color.b;
00742 fs << r << " " << g << " " << b;
00743 if (cloud.fields[d].name.find ("rgba") != std::string::npos)
00744 {
00745 int a = color.a;
00746 fs << " " << a;
00747 }
00748 }
00749 break;
00750 }
00751 case sensor_msgs::PointField::FLOAT64:
00752 {
00753 double value;
00754 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (double)], sizeof (double));
00755 fs << value;
00756 break;
00757 }
00758 default:
00759 PCL_WARN ("[pcl::PLYWriter::writeASCII] Incorrect field data type specified (%d)!\n", cloud.fields[d].datatype);
00760 break;
00761 }
00762
00763 if (d < cloud.fields.size () - 1 || c < static_cast<int> (cloud.fields[d].count) - 1)
00764 fs << " ";
00765 }
00766 }
00767 fs << std::endl;
00768 }
00769
00770 if (origin[3] != 0)
00771 fs << origin[0]/origin[3] << " " << origin[1]/origin[3] << " " << origin[2]/origin[3] << " ";
00772 else
00773 fs << origin[0] << " " << origin[1] << " " << origin[2] << " ";
00774
00775 Eigen::Matrix3f R = orientation.toRotationMatrix ();
00776 fs << R (0,0) << " " << R (0,1) << " " << R (0,2) << " ";
00777 fs << R (1,0) << " " << R (1,1) << " " << R (1,2) << " ";
00778 fs << R (2,0) << " " << R (2,1) << " " << R (2,2) << " ";
00779
00780 fs << 0 << " ";
00781
00782 fs << 0 << " " << 0 << " ";
00783
00784 fs << 0 << " " << 0 << " ";
00785
00786 fs << cloud.width << " " << cloud.height << " ";
00787
00788 fs << 0 << " " << 0;
00789 fs << std::endl;
00790 fs.flush ();
00791 }
00792
00793 void
00794 pcl::PLYWriter::writeContentWithRangeGridASCII (int nr_points,
00795 int point_size,
00796 const sensor_msgs::PointCloud2 &cloud,
00797 std::ostringstream& fs,
00798 int& valid_points)
00799 {
00800 valid_points = 0;
00801 std::vector<std::vector <int> > grids (nr_points);
00802
00803 for (int i = 0; i < nr_points; ++i)
00804 {
00805 std::ostringstream line;
00806 bool is_valid_line = true;
00807 for (size_t d = 0; d < cloud.fields.size (); ++d)
00808 {
00809 int count = cloud.fields[d].count;
00810 if (count == 0)
00811 count = 1;
00812 for (int c = 0; c < count; ++c)
00813 {
00814 switch (cloud.fields[d].datatype)
00815 {
00816 case sensor_msgs::PointField::INT8:
00817 {
00818 char value;
00819 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (char)], sizeof (char));
00820 line << boost::numeric_cast<int> (value);
00821 break;
00822 }
00823 case sensor_msgs::PointField::UINT8:
00824 {
00825 unsigned char value;
00826 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned char)], sizeof (unsigned char));
00827 line << boost::numeric_cast<int> (value);
00828 break;
00829 }
00830 case sensor_msgs::PointField::INT16:
00831 {
00832 short value;
00833 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (short)], sizeof (short));
00834 line << boost::numeric_cast<int> (value);
00835 break;
00836 }
00837 case sensor_msgs::PointField::UINT16:
00838 {
00839 unsigned short value;
00840 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned short)], sizeof (unsigned short));
00841 line << boost::numeric_cast<int> (value);
00842 break;
00843 }
00844 case sensor_msgs::PointField::INT32:
00845 {
00846 int value;
00847 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (int)], sizeof (int));
00848 line << value;
00849 break;
00850 }
00851 case sensor_msgs::PointField::UINT32:
00852 {
00853 if (cloud.fields[d].name.find ("rgb") == std::string::npos)
00854 {
00855 unsigned int value;
00856 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (unsigned int));
00857 line << value;
00858 }
00859 else
00860 {
00861 pcl::RGB color;
00862 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (pcl::RGB));
00863 int r = color.r;
00864 int g = color.g;
00865 int b = color.b;
00866 line << r << " " << g << " " << b;
00867 if (cloud.fields[d].name.find ("rgba") != std::string::npos)
00868 {
00869 int a = color.a;
00870 line << " " << a;
00871 }
00872 }
00873 break;
00874 }
00875 case sensor_msgs::PointField::FLOAT32:
00876 {
00877 if (cloud.fields[d].name.find ("rgb") == std::string::npos)
00878 {
00879 float value;
00880 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
00881 if ("x" == cloud.fields[d].name)
00882 {
00883 if (value != value)
00884 is_valid_line = false;
00885 }
00886 line << value;
00887 }
00888 else
00889 {
00890 pcl::RGB color;
00891 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (pcl::RGB));
00892 int r = color.r;
00893 int g = color.g;
00894 int b = color.b;
00895 line << r << " " << g << " " << b;
00896 if (cloud.fields[d].name.find ("rgba") != std::string::npos)
00897 {
00898 int a = color.a;
00899 line << " " << a;
00900 }
00901 }
00902 break;
00903 }
00904 case sensor_msgs::PointField::FLOAT64:
00905 {
00906 double value;
00907 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (double)], sizeof (double));
00908 line << value;
00909 break;
00910 }
00911 default:
00912 PCL_WARN ("[pcl::PLYWriter::writeASCII] Incorrect field data type specified (%d)!\n", cloud.fields[d].datatype);
00913 break;
00914 }
00915
00916 if (d < cloud.fields.size () - 1 || c < static_cast<int> (cloud.fields[d].count) - 1)
00917 line << " ";
00918 }
00919 }
00920
00921 if (is_valid_line)
00922 {
00923 grids[i].push_back (valid_points);
00924 fs << line.str () << std::endl;
00925 ++valid_points;
00926 }
00927 }
00928
00929
00930 for (int i = 0; i < nr_points; ++i)
00931 {
00932 fs << grids [i].size ();
00933 for (std::vector <int>::const_iterator it = grids [i].begin ();
00934 it != grids [i].end ();
00935 ++it)
00936 fs << " " << *it;
00937 fs << std::endl;
00938 }
00939 fs.flush ();
00940 }
00941
00943 int
00944 pcl::PLYWriter::writeBinary (const std::string &file_name,
00945 const sensor_msgs::PointCloud2 &cloud,
00946 const Eigen::Vector4f &origin,
00947 const Eigen::Quaternionf &orientation)
00948 {
00949 if (cloud.data.empty ())
00950 {
00951 PCL_ERROR ("[pcl::PLYWriter::writeBinary] Input point cloud has no data!\n");
00952 return (-1);
00953 }
00954
00955 std::ofstream fs;
00956 fs.open (file_name.c_str ());
00957 if (!fs)
00958 {
00959 PCL_ERROR ("[pcl::PLYWriter::writeBinary] Error during opening (%s)!\n", file_name.c_str ());
00960 return (-1);
00961 }
00962
00963 unsigned int nr_points = cloud.width * cloud.height;
00964 unsigned int point_size = static_cast<unsigned int> (cloud.data.size () / nr_points);
00965
00966
00967 fs << generateHeader (cloud, origin, orientation, true, true, nr_points);
00968
00969 fs.close ();
00970
00971 std::ofstream fpout (file_name.c_str (), std::ios::app | std::ios::binary);
00972 if (!fpout)
00973 {
00974 PCL_ERROR ("[pcl::PLYWriter::writeBinary] Error during reopening (%s)!\n", file_name.c_str ());
00975 return (-1);
00976 }
00977
00978
00979 for (unsigned int i = 0; i < nr_points; ++i)
00980 {
00981 size_t total = 0;
00982 for (size_t d = 0; d < cloud.fields.size (); ++d)
00983 {
00984 int count = cloud.fields[d].count;
00985 if (count == 0)
00986 count = 1;
00987
00988 if (cloud.fields[d].name == "_")
00989 {
00990 total += cloud.fields[d].count;
00991 continue;
00992 }
00993
00994 for (int c = 0; c < count; ++c)
00995 {
00996 switch (cloud.fields[d].datatype)
00997 {
00998 case sensor_msgs::PointField::INT8:
00999 {
01000 char value;
01001 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (char)], sizeof (char));
01002 fpout.write (reinterpret_cast<const char*> (&value), sizeof (char));
01003 break;
01004 }
01005 case sensor_msgs::PointField::UINT8:
01006 {
01007 unsigned char value;
01008 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned char)], sizeof (unsigned char));
01009 fpout.write (reinterpret_cast<const char*> (&value), sizeof (unsigned char));
01010 break;
01011 }
01012 case sensor_msgs::PointField::INT16:
01013 {
01014 short value;
01015 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (short)], sizeof (short));
01016 fpout.write (reinterpret_cast<const char*> (&value), sizeof (short));
01017 break;
01018 }
01019 case sensor_msgs::PointField::UINT16:
01020 {
01021 unsigned short value;
01022 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned short)], sizeof (unsigned short));
01023 fpout.write (reinterpret_cast<const char*> (&value), sizeof (unsigned short));
01024 break;
01025 }
01026 case sensor_msgs::PointField::INT32:
01027 {
01028 int value;
01029 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (int)], sizeof (int));
01030 fpout.write (reinterpret_cast<const char*> (&value), sizeof (int));
01031 break;
01032 }
01033 case sensor_msgs::PointField::UINT32:
01034 {
01035 if (cloud.fields[d].name.find ("rgb") == std::string::npos)
01036 {
01037 unsigned int value;
01038 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned int)], sizeof (unsigned int));
01039 fpout.write (reinterpret_cast<const char*> (&value), sizeof (unsigned int));
01040 }
01041 else
01042 {
01043 pcl::RGB color;
01044 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned int)], sizeof (pcl::RGB));
01045 unsigned char r = color.r;
01046 unsigned char g = color.g;
01047 unsigned char b = color.b;
01048 fpout.write (reinterpret_cast<const char*> (&r), sizeof (unsigned char));
01049 fpout.write (reinterpret_cast<const char*> (&g), sizeof (unsigned char));
01050 fpout.write (reinterpret_cast<const char*> (&b), sizeof (unsigned char));
01051 if (cloud.fields[d].name.find ("rgba") != std::string::npos)
01052 {
01053 unsigned char a = color.a;
01054 fpout.write (reinterpret_cast<const char*> (&a), sizeof (unsigned char));
01055 }
01056 }
01057 break;
01058 }
01059 case sensor_msgs::PointField::FLOAT32:
01060 {
01061 if (cloud.fields[d].name.find ("rgb") == std::string::npos)
01062 {
01063 float value;
01064 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (float)], sizeof (float));
01065 fpout.write (reinterpret_cast<const char*> (&value), sizeof (float));
01066 }
01067 else
01068 {
01069 pcl::RGB color;
01070 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (float)], sizeof (pcl::RGB));
01071 unsigned char r = color.r;
01072 unsigned char g = color.g;
01073 unsigned char b = color.b;
01074 fpout.write (reinterpret_cast<const char*> (&r), sizeof (unsigned char));
01075 fpout.write (reinterpret_cast<const char*> (&g), sizeof (unsigned char));
01076 fpout.write (reinterpret_cast<const char*> (&b), sizeof (unsigned char));
01077 if (cloud.fields[d].name.find ("rgba") != std::string::npos)
01078 {
01079 unsigned char a = color.a;
01080 fpout.write (reinterpret_cast<const char*> (&a), sizeof (unsigned char));
01081 }
01082 }
01083 break;
01084 }
01085 case sensor_msgs::PointField::FLOAT64:
01086 {
01087 double value;
01088 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (double)], sizeof (double));
01089 fpout.write (reinterpret_cast<const char*> (&value), sizeof (double));
01090 break;
01091 }
01092 default:
01093 PCL_WARN ("[pcl::PLYWriter::writeBinary] Incorrect field data type specified (%d)!\n", cloud.fields[d].datatype);
01094 break;
01095 }
01096 }
01097 }
01098 }
01099
01100 float t;
01101 for (int i = 0; i < 3; ++i)
01102 {
01103 if (origin[3] != 0)
01104 t = origin[i]/origin[3];
01105 else
01106 t = origin[i];
01107 fpout.write (reinterpret_cast<const char*> (&t), sizeof (float));
01108 }
01109 Eigen::Matrix3f R = orientation.toRotationMatrix ();
01110 for (int i = 0; i < 3; ++i)
01111 for (int j = 0; j < 3; ++j)
01112 {
01113 fpout.write (reinterpret_cast<const char*> (&R (i, j)),sizeof (float));
01114 }
01115
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01129
01130 const float zerof = 0;
01131 for (int i = 0; i < 5; ++i)
01132 fpout.write (reinterpret_cast<const char*> (&zerof), sizeof (float));
01133
01134
01135 int width = cloud.width;
01136 fpout.write (reinterpret_cast<const char*> (&width), sizeof (int));
01137
01138 int height = cloud.height;
01139 fpout.write (reinterpret_cast<const char*> (&height), sizeof (int));
01140
01141 for (int i = 0; i < 2; ++i)
01142 fpout.write (reinterpret_cast<const char*> (&zerof), sizeof (float));
01143
01144
01145 fpout.close ();
01146 return (0);
01147 }
01148
01150 int
01151 pcl::io::savePLYFile (const std::string &file_name, const pcl::PolygonMesh &mesh, unsigned precision)
01152 {
01153 if (mesh.cloud.data.empty ())
01154 {
01155 PCL_ERROR ("[pcl::io::savePLYFile] Input point cloud has no data!\n");
01156 return (-1);
01157 }
01158
01159 std::ofstream fs;
01160 fs.precision (precision);
01161 fs.open (file_name.c_str ());
01162 if (!fs)
01163 {
01164 PCL_ERROR ("[pcl::io::savePLYFile] Error during opening (%s)!\n", file_name.c_str ());
01165 return (-1);
01166 }
01167
01168
01169 size_t nr_points = mesh.cloud.width * mesh.cloud.height;
01170 size_t point_size = mesh.cloud.data.size () / nr_points;
01171
01172
01173 size_t nr_faces = mesh.polygons.size ();
01174
01175
01176 fs << "ply";
01177 fs << "\nformat ascii 1.0";
01178 fs << "\ncomment PCL generated";
01179
01180 fs << "\nelement vertex "<< mesh.cloud.width * mesh.cloud.height;
01181 fs << "\nproperty float x"
01182 "\nproperty float y"
01183 "\nproperty float z";
01184
01185 int rgb_index = getFieldIndex (mesh.cloud, "rgb"),
01186 rgba_index = getFieldIndex (mesh.cloud, "rgba");
01187 if (rgb_index != -1)
01188 {
01189 fs << "\nproperty uchar red"
01190 "\nproperty uchar green"
01191 "\nproperty uchar blue";
01192 }
01193 else if (rgba_index != -1)
01194 {
01195 fs << "\nproperty uchar red"
01196 "\nproperty uchar green"
01197 "\nproperty uchar blue"
01198 "\nproperty uchar alpha";
01199 }
01200
01201
01202 fs << "\nelement face "<< nr_faces;
01203 fs << "\nproperty list uchar int vertex_index";
01204 fs << "\nend_header\n";
01205
01206
01207 for (size_t i = 0; i < nr_points; ++i)
01208 {
01209 int xyz = 0;
01210 for (size_t d = 0; d < mesh.cloud.fields.size (); ++d)
01211 {
01212 int count = mesh.cloud.fields[d].count;
01213 if (count == 0)
01214 count = 1;
01215 int c = 0;
01216
01217
01218 if ((mesh.cloud.fields[d].datatype == sensor_msgs::PointField::FLOAT32) && (
01219 mesh.cloud.fields[d].name == "x" ||
01220 mesh.cloud.fields[d].name == "y" ||
01221 mesh.cloud.fields[d].name == "z"))
01222 {
01223 float value;
01224 memcpy (&value, &mesh.cloud.data[i * point_size + mesh.cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
01225 fs << value;
01226
01227
01228 ++xyz;
01229 }
01230 else if (mesh.cloud.fields[d].datatype == sensor_msgs::PointField::FLOAT32 && mesh.cloud.fields[d].name.find ("rgb") != std::string::npos)
01231 {
01232 pcl::RGB color;
01233 if(rgb_index != -1)
01234 {
01235 memcpy (&color, &mesh.cloud.data[i * point_size + mesh.cloud.fields[rgb_index].offset + c * sizeof (float)], sizeof (RGB));
01236 fs << (int) color.r << " " << (int) color.g << " " << (int) color.b;
01237 }
01238 else
01239 {
01240 memcpy (&color, &mesh.cloud.data[i * point_size + mesh.cloud.fields[rgba_index].offset + c * sizeof (float)], sizeof (RGB));
01241 fs << (int) color.r << " " << (int) color.g << " " << (int) color.b << " " << (int) color.a;
01242 }
01243 }
01244 fs << " ";
01245 }
01246 if (xyz != 3)
01247 {
01248 PCL_ERROR ("[pcl::io::savePLYFile] Input point cloud has no XYZ data!\n");
01249 return (-2);
01250 }
01251 fs << std::endl;
01252 }
01253
01254
01255 for (size_t i = 0; i < nr_faces; i++)
01256 {
01257 fs << mesh.polygons[i].vertices.size () << " ";
01258 size_t j = 0;
01259 for (j = 0; j < mesh.polygons[i].vertices.size () - 1; ++j)
01260 fs << mesh.polygons[i].vertices[j] << " ";
01261 fs << mesh.polygons[i].vertices[j] << std::endl;
01262 }
01263
01264
01265 fs.close ();
01266 return (0);
01267 }