vtk_lib_io.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2011, Dirk Holz, University of Bonn.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage, Inc. nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * $Id: vtk_lib_io.cpp 6141 2012-07-04 20:28:01Z rusu $
00035  *
00036  */
00037 
00038 #include <pcl/io/vtk_lib_io.h>
00039 #include <pcl/io/impl/vtk_lib_io.hpp>
00040 #include <vtkImageData.h>
00041 #include <vtkImageShiftScale.h>
00042 #include <vtkPNGWriter.h>
00043 
00045 int
00046 pcl::io::loadPolygonFile (const std::string &file_name, pcl::PolygonMesh& mesh)
00047 {
00048   if (!boost::filesystem::exists(file_name) || boost::filesystem::is_directory(file_name))
00049   {
00050     PCL_ERROR ("[pcl::io::loadPolygonFile]: No such file or directory.\n");
00051     return (0);
00052   }
00053 
00054   // TODO: how to adequately catch exceptions thrown by the vtk readers?!
00055   std::string extension = boost::filesystem::extension(file_name);
00056   if ( extension == ".pcd" ) // no Polygon, but only a point cloud
00057   {
00058     pcl::io::loadPCDFile (file_name, mesh.cloud);
00059     mesh.polygons.resize (0);
00060     return (static_cast<int> (mesh.cloud.width * mesh.cloud.height));
00061   }
00062   else if (extension == ".vtk")
00063    return (pcl::io::loadPolygonFileVTK (file_name, mesh));
00064   else if (extension == ".ply")
00065    return (pcl::io::loadPolygonFilePLY (file_name, mesh));
00066   else if (extension == ".obj")
00067     return (pcl::io::loadPolygonFileOBJ (file_name, mesh));
00068   else if (extension == ".stl" )
00069     return (pcl::io::loadPolygonFileSTL (file_name, mesh));
00070   else
00071   {
00072     PCL_ERROR ("[pcl::io::loadPolygonFile]: Unsupported file type (%s)\n", extension.c_str ());
00073     return (0);
00074   }
00075 }
00076 
00078 int
00079 pcl::io::savePolygonFile (const std::string &file_name, const pcl::PolygonMesh& mesh)
00080 {
00081   // TODO: what about binary/ASCII modes?!?!?!
00082   // TODO: what about sensor position and orientation?!?!?!?
00083 
00084   // TODO: how to adequately catch exceptions thrown by the vtk writers?!
00085 
00086   std::string extension = boost::filesystem::extension (file_name);
00087   if (extension == ".pcd") // no Polygon, but only a point cloud
00088   {
00089     int error_code = pcl::io::savePCDFile (file_name, mesh.cloud);
00090     if (error_code != 0)
00091       return (0);
00092     return (static_cast<int> (mesh.cloud.width * mesh.cloud.height));
00093   }
00094   else if (extension == ".vtk")
00095    return (pcl::io::savePolygonFileVTK (file_name, mesh));
00096   else if (extension == ".ply")
00097    return (pcl::io::savePolygonFilePLY (file_name, mesh));
00098   else if (extension == ".stl" )
00099     return (pcl::io::savePolygonFileSTL (file_name, mesh));
00100   else
00101   {
00102     PCL_ERROR ("[pcl::io::savePolygonFile]: Unsupported file type (%s)\n", extension.c_str ());
00103     return (0);
00104   }
00105 }
00106 
00108 int
00109 pcl::io::loadPolygonFileVTK (const std::string &file_name, pcl::PolygonMesh& mesh)
00110 {
00111   vtkSmartPointer<vtkPolyData> poly_data = vtkSmartPointer<vtkPolyData>::New ();
00112 
00113   vtkSmartPointer<vtkPolyDataReader> ply_reader = vtkSmartPointer<vtkPolyDataReader>::New ();
00114   ply_reader->SetFileName (file_name.c_str ());
00115   ply_reader->Update ();
00116   poly_data = ply_reader->GetOutput ();
00117 
00118   return (pcl::io::vtk2mesh (poly_data, mesh));
00119 }
00120 
00122 int
00123 pcl::io::loadPolygonFilePLY (const std::string &file_name, pcl::PolygonMesh& mesh)
00124 {
00125   vtkSmartPointer<vtkPolyData> poly_data = vtkSmartPointer<vtkPolyData>::New();
00126 
00127   vtkSmartPointer<vtkPLYReader> ply_reader = vtkSmartPointer<vtkPLYReader>::New();
00128   ply_reader->SetFileName (file_name.c_str ());
00129   ply_reader->Update ();
00130   poly_data = ply_reader->GetOutput ();
00131 
00132   return (pcl::io::vtk2mesh (poly_data, mesh));
00133 }
00134 
00136 int
00137 pcl::io::loadPolygonFileOBJ (const std::string &file_name, pcl::PolygonMesh& mesh)
00138 {
00139   vtkSmartPointer<vtkOBJReader> ply_reader = vtkSmartPointer<vtkOBJReader>::New ();
00140   ply_reader->SetFileName (file_name.c_str ());
00141   ply_reader->Update ();
00142 
00143   vtkSmartPointer<vtkPolyData> poly_data = ply_reader->GetOutput ();
00144 
00145   return (pcl::io::vtk2mesh (poly_data, mesh));
00146 }
00147 
00149 int
00150 pcl::io::loadPolygonFileSTL (const std::string &file_name, pcl::PolygonMesh& mesh)
00151 {
00152   vtkSmartPointer<vtkPolyData> poly_data = vtkSmartPointer<vtkPolyData>::New ();
00153 
00154   vtkSmartPointer<vtkSTLReader> ply_reader = vtkSmartPointer<vtkSTLReader>::New ();
00155   ply_reader->SetFileName (file_name.c_str ());
00156   ply_reader->Update ();
00157   poly_data = ply_reader->GetOutput ();
00158 
00159   return (pcl::io::vtk2mesh (poly_data, mesh));
00160 }
00161 
00163 int
00164 pcl::io::savePolygonFileVTK (const std::string &file_name, const pcl::PolygonMesh& mesh)
00165 {
00166   vtkSmartPointer<vtkPolyData> poly_data = vtkSmartPointer<vtkPolyData>::New ();
00167 
00168   pcl::io::mesh2vtk (mesh, poly_data);
00169 
00170   vtkSmartPointer<vtkPolyDataWriter> poly_writer = vtkSmartPointer<vtkPolyDataWriter>::New ();
00171   poly_writer->SetInput (poly_data);
00172   poly_writer->SetFileName (file_name.c_str ());
00173   poly_writer->Write ();
00174 
00175   return (static_cast<int> (mesh.cloud.width * mesh.cloud.width));
00176 }
00177 
00179 int
00180 pcl::io::savePolygonFilePLY (const std::string &file_name, const pcl::PolygonMesh& mesh)
00181 {
00182   vtkSmartPointer<vtkPolyData> poly_data = vtkSmartPointer<vtkPolyData>::New ();
00183 
00184   pcl::io::mesh2vtk (mesh, poly_data);
00185 
00186   vtkSmartPointer<vtkPLYWriter> poly_writer = vtkSmartPointer<vtkPLYWriter>::New ();
00187   poly_writer->SetInput (poly_data);
00188   poly_writer->SetFileName (file_name.c_str ());
00189         poly_writer->SetArrayName ("Colors");
00190   poly_writer->Write ();
00191 
00192   return (static_cast<int> (mesh.cloud.width * mesh.cloud.width));
00193 }
00194 
00196 int
00197 pcl::io::savePolygonFileSTL (const std::string &file_name, const pcl::PolygonMesh& mesh)
00198 {
00199   vtkSmartPointer<vtkPolyData> poly_data = vtkSmartPointer<vtkPolyData>::New ();
00200 
00201   pcl::io::mesh2vtk (mesh, poly_data);
00202 
00203   vtkSmartPointer<vtkSTLWriter> poly_writer = vtkSmartPointer<vtkSTLWriter>::New ();
00204   poly_writer->SetInput (poly_data);
00205   poly_writer->SetFileName (file_name.c_str ());
00206   poly_writer->Write ();
00207 
00208   return (static_cast<int> (mesh.cloud.width * mesh.cloud.width));
00209 }
00210 
00212 int
00213 pcl::io::vtk2mesh (const vtkSmartPointer<vtkPolyData>& poly_data, pcl::PolygonMesh& mesh)
00214 {
00215   mesh.polygons.resize (0);
00216   mesh.cloud.data.clear ();
00217   mesh.cloud.width = mesh.cloud.height = 0;
00218   mesh.cloud.is_dense = true;
00219 
00220   vtkSmartPointer<vtkPoints> mesh_points = poly_data->GetPoints ();
00221   vtkIdType nr_points = mesh_points->GetNumberOfPoints ();
00222   vtkIdType nr_polygons = poly_data->GetNumberOfPolys ();
00223 
00224   if (nr_points == 0)
00225     return (0);
00226 
00227   vtkUnsignedCharArray* poly_colors = NULL;
00228   if (poly_data->GetPointData() != NULL)
00229     poly_colors = vtkUnsignedCharArray::SafeDownCast (poly_data->GetPointData ()->GetScalars ("Colors"));
00230 
00231   // some applications do not save the name of scalars (including PCL's native vtk_io)
00232   if (!poly_colors && poly_data->GetPointData () != NULL)
00233     poly_colors = vtkUnsignedCharArray::SafeDownCast (poly_data->GetPointData ()->GetScalars ("scalars"));
00234 
00235   if (!poly_colors && poly_data->GetPointData () != NULL)
00236     poly_colors = vtkUnsignedCharArray::SafeDownCast (poly_data->GetPointData ()->GetScalars ("RGB"));
00237 
00238   // TODO: currently only handles rgb values with 3 components
00239   if (poly_colors && (poly_colors->GetNumberOfComponents () == 3))
00240   {
00241     pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_temp (new pcl::PointCloud<pcl::PointXYZRGB> ());
00242     cloud_temp->points.resize (nr_points);
00243     double point_xyz[3];
00244     unsigned char point_color[3];
00245     for (vtkIdType i = 0; i < mesh_points->GetNumberOfPoints (); i++)
00246     {
00247       mesh_points->GetPoint (i, &point_xyz[0]);
00248       cloud_temp->points[i].x = static_cast<float> (point_xyz[0]);
00249       cloud_temp->points[i].y = static_cast<float> (point_xyz[1]);
00250       cloud_temp->points[i].z = static_cast<float> (point_xyz[2]);
00251 
00252       poly_colors->GetTupleValue (i, &point_color[0]);
00253       cloud_temp->points[i].r = point_color[0];
00254       cloud_temp->points[i].g = point_color[1];
00255       cloud_temp->points[i].b = point_color[2];
00256     }
00257     cloud_temp->width = static_cast<uint32_t> (cloud_temp->points.size ());
00258     cloud_temp->height = 1;
00259     cloud_temp->is_dense = true;
00260 
00261     pcl::toROSMsg (*cloud_temp, mesh.cloud);
00262   }
00263   else // in case points do not have color information:
00264   {
00265     pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_temp (new pcl::PointCloud<pcl::PointXYZ> ());
00266     cloud_temp->points.resize (nr_points);
00267     double point_xyz[3];
00268     for (vtkIdType i = 0; i < mesh_points->GetNumberOfPoints (); i++)
00269     {
00270       mesh_points->GetPoint (i, &point_xyz[0]);
00271       cloud_temp->points[i].x = static_cast<float> (point_xyz[0]);
00272       cloud_temp->points[i].y = static_cast<float> (point_xyz[1]);
00273       cloud_temp->points[i].z = static_cast<float> (point_xyz[2]);
00274     }
00275     cloud_temp->width = static_cast<uint32_t> (cloud_temp->points.size ());
00276     cloud_temp->height = 1;
00277     cloud_temp->is_dense = true;
00278 
00279     pcl::toROSMsg (*cloud_temp, mesh.cloud);
00280   }
00281 
00282   mesh.polygons.resize (nr_polygons);
00283   vtkIdType* cell_points;
00284   vtkIdType nr_cell_points;
00285   vtkCellArray * mesh_polygons = poly_data->GetPolys ();
00286   mesh_polygons->InitTraversal ();
00287   int id_poly = 0;
00288   while (mesh_polygons->GetNextCell (nr_cell_points, cell_points))
00289   {
00290     mesh.polygons[id_poly].vertices.resize (nr_cell_points);
00291     for (int i = 0; i < nr_cell_points; ++i)
00292       mesh.polygons[id_poly].vertices[i] = static_cast<int> (cell_points[i]);
00293     ++id_poly;
00294   }
00295 
00296   return (static_cast<int> (nr_points));
00297 }
00298 
00300 int
00301 pcl::io::mesh2vtk (const pcl::PolygonMesh& mesh, vtkSmartPointer<vtkPolyData>& poly_data)
00302 {
00303   unsigned int nr_points = mesh.cloud.width * mesh.cloud.height;
00304   unsigned int nr_polygons = static_cast<unsigned int> (mesh.polygons.size ());
00305 
00306   // reset vtkPolyData object
00307   poly_data = vtkSmartPointer<vtkPolyData>::New (); // OR poly_data->Reset();
00308   vtkSmartPointer<vtkPoints> vtk_mesh_points = vtkSmartPointer<vtkPoints>::New ();
00309   vtkSmartPointer<vtkCellArray> vtk_mesh_polygons = vtkSmartPointer<vtkCellArray>::New ();
00310   poly_data->SetPoints (vtk_mesh_points);
00311 
00312   // get field indices for x, y, z (as well as rgb and/or rgba)
00313   int idx_x = -1, idx_y = -1, idx_z = -1, idx_rgb = -1, idx_rgba = -1, idx_normal_x = -1, idx_normal_y = -1, idx_normal_z = -1;
00314   for (int d = 0; d < static_cast<int> (mesh.cloud.fields.size ()); ++d)
00315   {
00316     if (mesh.cloud.fields[d].name == "x") idx_x = d;
00317     else if (mesh.cloud.fields[d].name == "y") idx_y = d;
00318     else if (mesh.cloud.fields[d].name == "z") idx_z = d;
00319     else if (mesh.cloud.fields[d].name == "rgb") idx_rgb = d;
00320     else if (mesh.cloud.fields[d].name == "rgba") idx_rgba = d;
00321     else if (mesh.cloud.fields[d].name == "normal_x") idx_normal_x = d;
00322     else if (mesh.cloud.fields[d].name == "normal_y") idx_normal_y = d;
00323     else if (mesh.cloud.fields[d].name == "normal_z") idx_normal_z = d;
00324   }
00325   if ( ( idx_x == -1 ) || ( idx_y == -1 ) || ( idx_z == -1 ) )
00326     nr_points = 0;
00327 
00328   // copy point data
00329   vtk_mesh_points->SetNumberOfPoints (nr_points);
00330   if (nr_points > 0)
00331   {
00332     Eigen::Vector4f pt = Eigen::Vector4f::Zero ();
00333     Eigen::Array4i xyz_offset (mesh.cloud.fields[idx_x].offset, mesh.cloud.fields[idx_y].offset, mesh.cloud.fields[idx_z].offset, 0);
00334     for (vtkIdType cp = 0; cp < static_cast<vtkIdType> (nr_points); ++cp, xyz_offset += mesh.cloud.point_step)
00335     {
00336       memcpy(&pt[0], &mesh.cloud.data[xyz_offset[0]], sizeof (float));
00337       memcpy(&pt[1], &mesh.cloud.data[xyz_offset[1]], sizeof (float));
00338       memcpy(&pt[2], &mesh.cloud.data[xyz_offset[2]], sizeof (float));
00339       vtk_mesh_points->InsertPoint (cp, pt[0], pt[1], pt[2]);
00340     }
00341   }
00342 
00343   // copy polygon data
00344   if (nr_polygons > 0)
00345   {
00346     for (unsigned int i = 0; i < nr_polygons; i++)
00347     {
00348       unsigned int nr_points_in_polygon = static_cast<unsigned int> (mesh.polygons[i].vertices.size ());
00349       vtk_mesh_polygons->InsertNextCell (nr_points_in_polygon);
00350       for (unsigned int j = 0; j < nr_points_in_polygon; j++)
00351         vtk_mesh_polygons->InsertCellPoint (mesh.polygons[i].vertices[j]);
00352     }
00353     poly_data->SetPolys (vtk_mesh_polygons);
00354   }
00355 
00356   // copy color information
00357   if (idx_rgb != -1 || idx_rgba != -1)
00358   {
00359     vtkSmartPointer<vtkUnsignedCharArray> colors = vtkSmartPointer<vtkUnsignedCharArray>::New ();
00360     colors->SetNumberOfComponents (3);
00361     colors->SetName ("Colors");
00362     pcl::RGB rgb;
00363     int offset = (idx_rgb != -1) ? mesh.cloud.fields[idx_rgb].offset : mesh.cloud.fields[idx_rgba].offset;
00364     for (vtkIdType cp = 0; cp < nr_points; ++cp)
00365     {
00366       memcpy (&rgb, &mesh.cloud.data[cp * mesh.cloud.point_step + offset], sizeof (RGB));
00367       const unsigned char color[3] = {rgb.r, rgb.g, rgb.b};
00368       colors->InsertNextTupleValue (color);
00369     }
00370     poly_data->GetPointData ()->SetScalars (colors);
00371   }
00372 
00373   // copy normal information
00374   if (( idx_normal_x != -1 ) && ( idx_normal_y != -1 ) && ( idx_normal_z != -1 ))
00375   {
00376     vtkSmartPointer<vtkFloatArray> normals = vtkSmartPointer<vtkFloatArray>::New ();
00377     normals->SetNumberOfComponents (3);
00378     float nx = 0.0f, ny = 0.0f, nz = 0.0f;
00379     for (vtkIdType cp = 0; cp < nr_points; ++cp)
00380     {
00381       memcpy (&nx, &mesh.cloud.data[cp*mesh.cloud.point_step+mesh.cloud.fields[idx_normal_x].offset], sizeof (float));
00382       memcpy (&ny, &mesh.cloud.data[cp*mesh.cloud.point_step+mesh.cloud.fields[idx_normal_y].offset], sizeof (float));
00383       memcpy (&nz, &mesh.cloud.data[cp*mesh.cloud.point_step+mesh.cloud.fields[idx_normal_z].offset], sizeof (float));
00384       const float normal[3] = {nx, ny, nz};
00385       normals->InsertNextTupleValue (normal);
00386     }
00387     poly_data->GetPointData()->SetNormals (normals);
00388   }
00389 
00390   if (poly_data->GetPoints () == NULL)
00391     return (0);
00392   return (static_cast<int> (poly_data->GetPoints ()->GetNumberOfPoints ()));
00393 }
00394 
00396 void
00397 pcl::io::saveRangeImagePlanarFilePNG (
00398     const std::string &file_name, const pcl::RangeImagePlanar& range_image)
00399 {
00400   vtkSmartPointer<vtkImageData> image = vtkSmartPointer<vtkImageData>::New();
00401   image->SetDimensions(range_image.width, range_image.height, 1);
00402   image->SetNumberOfScalarComponents(1);
00403   image->SetScalarTypeToFloat();
00404   image->AllocateScalars();
00405 
00406   int* dims = image->GetDimensions();
00407 
00408   for (int y = 0; y < dims[1]; y++)
00409     {
00410     for (int x = 0; x < dims[0]; x++)
00411       {
00412       float* pixel = static_cast<float*>(image->GetScalarPointer(x,y,0));
00413       pixel[0] = range_image(y,x).range;
00414       }
00415     }
00416 
00417   // Compute the scaling
00418   float oldRange = static_cast<float> (image->GetScalarRange()[1] - image->GetScalarRange()[0]);
00419   float newRange = 255; // We want the output [0,255]
00420 
00421   vtkSmartPointer<vtkImageShiftScale> shiftScaleFilter = vtkSmartPointer<vtkImageShiftScale>::New();
00422   shiftScaleFilter->SetOutputScalarTypeToUnsignedChar();
00423   shiftScaleFilter->SetInputConnection(image->GetProducerPort());
00424   shiftScaleFilter->SetShift(-1.0f * image->GetScalarRange()[0]); // brings the lower bound to 0
00425   shiftScaleFilter->SetScale(newRange/oldRange);
00426   shiftScaleFilter->Update();
00427 
00428   vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New();
00429   writer->SetFileName(file_name.c_str());
00430   writer->SetInputConnection(shiftScaleFilter->GetOutputPort());
00431   writer->Write();
00432 }


pcl
Author(s): Open Perception
autogenerated on Mon Oct 6 2014 03:19:11